2525import org .mybatis .dynamic .sql .util .FragmentAndParameters ;
2626import org .mybatis .dynamic .sql .util .StringUtilities ;
2727
28- public class SqlColumn <T > implements BindableColumn <T >, SortSpecification {
28+ public class SqlColumn <T > implements BindableColumn <T >, SortSpecification , SqlColumnBuilders {
2929
3030 protected final String name ;
3131 protected final SqlTable table ;
@@ -39,7 +39,7 @@ public class SqlColumn<T> implements BindableColumn<T>, SortSpecification {
3939 protected final @ Nullable Class <T > javaType ;
4040 protected final @ Nullable String javaProperty ;
4141
42- private SqlColumn (Builder < T > builder ) {
42+ protected SqlColumn (AbstractBuilder < T , ? > builder ) {
4343 name = Objects .requireNonNull (builder .name );
4444 table = Objects .requireNonNull (builder .table );
4545 jdbcType = builder .jdbcType ;
@@ -91,15 +91,13 @@ public Optional<String> javaProperty() {
9191 }
9292
9393 @ Override
94- public SortSpecification descending () {
95- Builder <T > b = copy ();
96- return b .withDescendingPhrase (" DESC" ).build (); //$NON-NLS-1$
94+ public SqlColumn <T > descending () {
95+ return copyBuilder ().withDescendingPhrase (" DESC" ).build (); //$NON-NLS-1$
9796 }
9897
9998 @ Override
10099 public SqlColumn <T > as (String alias ) {
101- Builder <T > b = copy ();
102- return b .withAlias (alias ).build ();
100+ return copyBuilder ().withAlias (alias ).build ();
103101 }
104102
105103 /**
@@ -110,9 +108,7 @@ public SqlColumn<T> as(String alias) {
110108 * @return a new column that will be rendered with the specified table qualifier
111109 */
112110 public SqlColumn <T > qualifiedWith (String tableQualifier ) {
113- Builder <T > b = copy ();
114- b .withTableQualifier (tableQualifier );
115- return b .build ();
111+ return copyBuilder ().withTableQualifier (tableQualifier ).build ();
116112 }
117113
118114 /**
@@ -127,8 +123,8 @@ public SqlColumn<T> qualifiedWith(String tableQualifier) {
127123 * @return a new column aliased with a camel case version of the column name
128124 */
129125 public SqlColumn <T > asCamelCase () {
130- Builder < T > b = copy ();
131- return b .withAlias ("\" " + StringUtilities .toCamelCase (name ) + "\" " ).build (); //$NON-NLS-1$ //$NON-NLS-2$
126+ return copyBuilder ()
127+ .withAlias ("\" " + StringUtilities .toCamelCase (name ) + "\" " ).build (); //$NON-NLS-1$ //$NON-NLS-2$
132128 }
133129
134130 @ Override
@@ -150,29 +146,40 @@ public Optional<RenderingStrategy> renderingStrategy() {
150146 return Optional .ofNullable (renderingStrategy );
151147 }
152148
149+ @ Override
153150 public <S > SqlColumn <S > withTypeHandler (String typeHandler ) {
154- Builder <S > b = copy ();
155- return b .withTypeHandler (typeHandler ).build ();
151+ return cast (copyBuilder ().withTypeHandler (typeHandler ).build ());
156152 }
157153
154+ @ Override
158155 public <S > SqlColumn <S > withRenderingStrategy (RenderingStrategy renderingStrategy ) {
159- Builder <S > b = copy ();
160- return b .withRenderingStrategy (renderingStrategy ).build ();
156+ return cast (copyBuilder ().withRenderingStrategy (renderingStrategy ).build ());
161157 }
162158
159+ @ Override
160+ @ SuppressWarnings ("unchecked" )
163161 public <S > SqlColumn <S > withParameterTypeConverter (ParameterTypeConverter <S , ?> parameterTypeConverter ) {
164- Builder <S > b = copy ();
165- return b .withParameterTypeConverter (parameterTypeConverter ).build ();
162+ return cast (copyBuilder ().withParameterTypeConverter ((ParameterTypeConverter <T , ?>) parameterTypeConverter ).build ());
166163 }
167164
165+ @ Override
166+ @ SuppressWarnings ("unchecked" )
168167 public <S > SqlColumn <S > withJavaType (Class <S > javaType ) {
169- Builder <S > b = copy ();
170- return b .withJavaType (javaType ).build ();
168+ return cast (copyBuilder ().withJavaType ((Class <T >) javaType ).build ());
171169 }
172170
171+ @ Override
173172 public <S > SqlColumn <S > withJavaProperty (String javaProperty ) {
174- Builder <S > b = copy ();
175- return b .withJavaProperty (javaProperty ).build ();
173+ return cast (copyBuilder ().withJavaProperty (javaProperty ).build ());
174+ }
175+
176+ private Builder <T > copyBuilder () {
177+ return populateBaseBuilder (new Builder <>());
178+ }
179+
180+ @ SuppressWarnings ("unchecked" )
181+ protected <S extends SqlColumn <?>> S cast (SqlColumn <?> column ) {
182+ return (S ) column ;
176183 }
177184
178185 /**
@@ -181,22 +188,22 @@ public <S> SqlColumn<S> withJavaProperty(String javaProperty) {
181188 * chaining in the "with" methods. With this bit of fiction, we force the compiler to delay type
182189 * inference to the last method in the chain.
183190 *
184- * @param <S > the type. Will be the same as T for this usage.
185- * @return a new SqlColumn of type S (S is the same as T)
191+ * @param <B > the concrete builder type
192+ * @return the populated builder
186193 */
187194 @ SuppressWarnings ("unchecked" )
188- private < S > Builder < S > copy ( ) {
189- return new Builder < S >()
195+ protected < B extends AbstractBuilder < T , ?>> B populateBaseBuilder ( B builder ) {
196+ return ( B ) builder
190197 .withName (this .name )
191198 .withTable (this .table )
192199 .withJdbcType (this .jdbcType )
193200 .withDescendingPhrase (this .descendingPhrase )
194201 .withAlias (this .alias )
195202 .withTypeHandler (this .typeHandler )
196203 .withRenderingStrategy (this .renderingStrategy )
197- .withParameterTypeConverter (( ParameterTypeConverter < S , ?>) this .parameterTypeConverter )
204+ .withParameterTypeConverter (this .parameterTypeConverter )
198205 .withTableQualifier (this .tableQualifier )
199- .withJavaType (( Class < S >) this .javaType )
206+ .withJavaType (this .javaType )
200207 .withJavaProperty (this .javaProperty );
201208 }
202209
@@ -213,7 +220,7 @@ public static <T> SqlColumn<T> of(String name, SqlTable table, JDBCType jdbcType
213220 .build ();
214221 }
215222
216- public static class Builder < T > {
223+ public static abstract class AbstractBuilder < T , B extends AbstractBuilder < T , B > > {
217224 protected @ Nullable String name ;
218225 protected @ Nullable SqlTable table ;
219226 protected @ Nullable JDBCType jdbcType ;
@@ -226,63 +233,72 @@ public static class Builder<T> {
226233 protected @ Nullable Class <T > javaType ;
227234 protected @ Nullable String javaProperty ;
228235
229- public Builder < T > withName (String name ) {
236+ public B withName (String name ) {
230237 this .name = name ;
231- return this ;
238+ return getThis () ;
232239 }
233240
234- public Builder < T > withTable (SqlTable table ) {
241+ public B withTable (SqlTable table ) {
235242 this .table = table ;
236- return this ;
243+ return getThis () ;
237244 }
238245
239- public Builder < T > withJdbcType (@ Nullable JDBCType jdbcType ) {
246+ public B withJdbcType (@ Nullable JDBCType jdbcType ) {
240247 this .jdbcType = jdbcType ;
241- return this ;
248+ return getThis () ;
242249 }
243250
244- public Builder < T > withDescendingPhrase (String descendingPhrase ) {
251+ public B withDescendingPhrase (String descendingPhrase ) {
245252 this .descendingPhrase = descendingPhrase ;
246- return this ;
253+ return getThis () ;
247254 }
248255
249- public Builder < T > withAlias (@ Nullable String alias ) {
256+ public B withAlias (@ Nullable String alias ) {
250257 this .alias = alias ;
251- return this ;
258+ return getThis () ;
252259 }
253260
254- public Builder < T > withTypeHandler (@ Nullable String typeHandler ) {
261+ public B withTypeHandler (@ Nullable String typeHandler ) {
255262 this .typeHandler = typeHandler ;
256- return this ;
263+ return getThis () ;
257264 }
258265
259- public Builder < T > withRenderingStrategy (@ Nullable RenderingStrategy renderingStrategy ) {
266+ public B withRenderingStrategy (@ Nullable RenderingStrategy renderingStrategy ) {
260267 this .renderingStrategy = renderingStrategy ;
261- return this ;
268+ return getThis () ;
262269 }
263270
264- public Builder < T > withParameterTypeConverter (ParameterTypeConverter <T , ?> parameterTypeConverter ) {
271+ public B withParameterTypeConverter (ParameterTypeConverter <T , ?> parameterTypeConverter ) {
265272 this .parameterTypeConverter = parameterTypeConverter ;
266- return this ;
273+ return getThis () ;
267274 }
268275
269- private Builder < T > withTableQualifier (@ Nullable String tableQualifier ) {
276+ public B withTableQualifier (@ Nullable String tableQualifier ) {
270277 this .tableQualifier = tableQualifier ;
271- return this ;
278+ return getThis () ;
272279 }
273280
274- public Builder < T > withJavaType (@ Nullable Class <T > javaType ) {
281+ public B withJavaType (@ Nullable Class <T > javaType ) {
275282 this .javaType = javaType ;
276- return this ;
283+ return getThis () ;
277284 }
278285
279- public Builder < T > withJavaProperty (@ Nullable String javaProperty ) {
286+ public B withJavaProperty (@ Nullable String javaProperty ) {
280287 this .javaProperty = javaProperty ;
281- return this ;
288+ return getThis () ;
282289 }
283290
291+ protected abstract B getThis ();
292+ }
293+
294+ public static class Builder <T > extends AbstractBuilder <T , Builder <T >> {
284295 public SqlColumn <T > build () {
285296 return new SqlColumn <>(this );
286297 }
298+
299+ @ Override
300+ protected Builder <T > getThis () {
301+ return this ;
302+ }
287303 }
288304}
0 commit comments