19
19
import static com .google .common .collect .Iterables .tryFind ;
20
20
import static javax .lang .model .element .Modifier .PUBLIC ;
21
21
import static javax .lang .model .util .ElementFilter .typesIn ;
22
- import static org .inferred .freebuilder .processor .BuilderFactory .TypeInference .INFERRED_TYPES ;
22
+ import static org .inferred .freebuilder .processor .BuilderFactory .TypeInference .EXPLICIT_TYPES ;
23
23
import static org .inferred .freebuilder .processor .BuilderMethods .getBuilderMethod ;
24
24
import static org .inferred .freebuilder .processor .BuilderMethods .mutator ;
25
25
import static org .inferred .freebuilder .processor .BuilderMethods .setter ;
36
36
import org .inferred .freebuilder .processor .Metadata .Property ;
37
37
import org .inferred .freebuilder .processor .util .Block ;
38
38
import org .inferred .freebuilder .processor .util .Excerpt ;
39
+ import org .inferred .freebuilder .processor .util .Excerpts ;
40
+ import org .inferred .freebuilder .processor .util .ModelUtils ;
39
41
import org .inferred .freebuilder .processor .util .ParameterizedType ;
40
42
import org .inferred .freebuilder .processor .util .PreconditionExcerpts ;
41
43
import org .inferred .freebuilder .processor .util .SourceBuilder ;
44
+ import org .inferred .freebuilder .processor .util .Variable ;
42
45
43
46
import java .util .List ;
44
47
@@ -172,6 +175,7 @@ public Optional<BuildableProperty> create(Config config) {
172
175
private final BuilderFactory builderFactory ;
173
176
private final MergeBuilderMethod mergeFromBuilderMethod ;
174
177
private final PartialToBuilderMethod partialToBuilderMethod ;
178
+ private final Excerpt suppressUnchecked ;
175
179
176
180
private BuildableProperty (
177
181
Metadata metadata ,
@@ -185,12 +189,16 @@ private BuildableProperty(
185
189
this .builderFactory = builderFactory ;
186
190
this .mergeFromBuilderMethod = mergeFromBuilderMethod ;
187
191
this .partialToBuilderMethod = partialToBuilderMethod ;
192
+ if (ModelUtils .needsSafeVarargs (property .getType ())) {
193
+ suppressUnchecked = Excerpts .add ("@SuppressWarnings(\" unchecked\" )" );
194
+ } else {
195
+ suppressUnchecked = Excerpts .empty ();
196
+ }
188
197
}
189
198
190
199
@ Override
191
200
public void addBuilderFieldDeclaration (SourceBuilder code ) {
192
- code .addLine ("private final %s %s = %s;" ,
193
- builderType , property .getField (), builderFactory .newBuilder (builderType , INFERRED_TYPES ));
201
+ code .addLine ("private Object %s = null;" , property .getField ());
194
202
}
195
203
196
204
@ Override
@@ -202,6 +210,7 @@ public void addBuilderFieldAccessors(SourceBuilder code) {
202
210
}
203
211
204
212
private void addSetter (SourceBuilder code , Metadata metadata ) {
213
+ Variable builder = new Variable ("builder" );
205
214
code .addLine ("" )
206
215
.addLine ("/**" )
207
216
.addLine (" * Sets the value to be returned by %s." ,
@@ -215,12 +224,20 @@ private void addSetter(SourceBuilder code, Metadata metadata) {
215
224
metadata .getBuilder (),
216
225
setter (property ),
217
226
property .getType (),
218
- property .getName ())
219
- .add (methodBody (code , property .getName ())
220
- .add (PreconditionExcerpts .checkNotNull (property .getName ()))
221
- .addLine (" %s.clear();" , property .getField ())
222
- .addLine (" %s.mergeFrom(%s);" , property .getField (), property .getName ())
223
- .addLine (" return (%s) this;" , metadata .getBuilder ()))
227
+ property .getName ());
228
+ Block body = methodBody (code , property .getName ())
229
+ .add (PreconditionExcerpts .checkNotNull (property .getName ()))
230
+ .addLine (" if (%1$s == null || %1$s instanceof %2$s) {" ,
231
+ property .getField (), ModelUtils .maybeAsTypeElement (property .getType ()).get ())
232
+ .addLine (" %s = %s;" , property .getField (), property .getName ())
233
+ .addLine (" } else {" )
234
+ .addLine (" %1$s %2$s %3$s = (%2$s) %4$s;" ,
235
+ suppressUnchecked , builderType , builder , property .getField ())
236
+ .addLine (" %s.clear();" , builder )
237
+ .addLine (" %s.mergeFrom(%s);" , builder , property .getName ())
238
+ .addLine (" }" )
239
+ .addLine (" return (%s) this;" , metadata .getBuilder ());
240
+ code .add (body )
224
241
.addLine ("}" );
225
242
}
226
243
@@ -264,44 +281,115 @@ private void addMutate(SourceBuilder code, Metadata metadata) {
264
281
consumer .getQualifiedName (),
265
282
builderType )
266
283
.add (methodBody (code , "mutator" )
267
- .addLine (" mutator.accept(%s) ;" , property . getField ( ))
284
+ .addLine (" mutator.accept(%s()) ;" , getBuilderMethod ( property ))
268
285
.addLine (" return (%s) this;" , metadata .getBuilder ()))
269
286
.addLine ("}" );
270
287
}
271
288
272
289
private void addGetter (SourceBuilder code , Metadata metadata ) {
290
+ Variable builder = new Variable ("builder" );
291
+ Variable value = new Variable ("value" );
273
292
code .addLine ("" )
274
293
.addLine ("/**" )
275
294
.addLine (" * Returns a builder for the value that will be returned by %s." ,
276
295
metadata .getType ().javadocNoArgMethodLink (property .getGetterName ()))
277
296
.addLine (" */" )
278
- .addLine ("public %s %s() {" , builderType , getBuilderMethod (property ))
279
- .addLine (" return %s;" , property .getField ())
297
+ .addLine ("public %s %s() {" , builderType , getBuilderMethod (property ));
298
+ Block body = methodBody (code )
299
+ .addLine (" if (%s == null) {" , property .getField ())
300
+ .addLine (" %s = %s;" ,
301
+ property .getField (), builderFactory .newBuilder (builderType , EXPLICIT_TYPES ))
302
+ .addLine (" } else if (%s instanceof %s) {" ,
303
+ property .getField (), ModelUtils .maybeAsTypeElement (property .getType ()).get ())
304
+ .addLine (" %1$s %2$s %3$s = (%2$s) %4$s;" ,
305
+ suppressUnchecked , property .getType (), value , property .getField ());
306
+ if (partialToBuilderMethod == PartialToBuilderMethod .TO_BUILDER_AND_MERGE ) {
307
+ body .addLine (" %s = %s.toBuilder();" , property .getField (), value );
308
+ } else {
309
+ body .addLine (" %s = %s" ,
310
+ property .getField (), builderFactory .newBuilder (builderType , EXPLICIT_TYPES ))
311
+ .addLine (" .mergeFrom(%s);" , value );
312
+ }
313
+ body .addLine (" }" )
314
+ .addLine (" %1$s %2$s %3$s = (%2$s) %4$s;" ,
315
+ suppressUnchecked , builderType , builder , property .getField ())
316
+ .addLine (" return %s;" , builder );
317
+ code .add (body )
280
318
.addLine ("}" );
281
319
}
282
320
283
321
@ Override
284
322
public void addFinalFieldAssignment (SourceBuilder code , Excerpt finalField , String builder ) {
285
- code . addLine ( "%s = %s.build();" , finalField , property . getField (). on ( builder ) );
323
+ addFieldAssignment ( code , finalField , builder , "build" );
286
324
}
287
325
288
326
@ Override
289
327
public void addPartialFieldAssignment (SourceBuilder code , Excerpt finalField , String builder ) {
290
- code .addLine ("%s = %s.buildPartial();" , finalField , property .getField ().on (builder ));
328
+ addFieldAssignment (code , finalField , builder , "buildPartial" );
329
+ }
330
+
331
+ private void addFieldAssignment (
332
+ SourceBuilder code ,
333
+ Excerpt finalField ,
334
+ String builder ,
335
+ String buildMethod ) {
336
+ Variable fieldBuilder = new Variable (property .getName () + "Builder" );
337
+ Variable fieldValue = new Variable (property .getName () + "Value" );
338
+ code .addLine ("if (%s == null) {" , property .getField ().on (builder ))
339
+ .addLine (" %s = %s.%s();" ,
340
+ finalField , builderFactory .newBuilder (builderType , EXPLICIT_TYPES ), buildMethod )
341
+ .addLine ("} else if (%s instanceof %s) {" ,
342
+ property .getField ().on (builder ),
343
+ ModelUtils .maybeAsTypeElement (property .getType ()).get ());
344
+ if (suppressUnchecked != Excerpts .empty ()) {
345
+ code .addLine (" %1$s %2$s %3$s = (%2$s) %4$s;" ,
346
+ suppressUnchecked , property .getType (), fieldValue , property .getField ().on (builder ))
347
+ .addLine (" %s = %s;" , finalField , fieldValue );
348
+ } else {
349
+ code .addLine (" %s = (%s) %s;" ,
350
+ finalField , property .getType (), property .getField ().on (builder ));
351
+ }
352
+ code .addLine ("} else {" )
353
+ .addLine (" %1$s %2$s %3$s = (%2$s) %4$s;" ,
354
+ suppressUnchecked , builderType , fieldBuilder , property .getField ().on (builder ))
355
+ .addLine (" %s = %s.%s();" , finalField , fieldBuilder , buildMethod )
356
+ .addLine ("}" );
291
357
}
292
358
293
359
@ Override
294
360
public void addMergeFromValue (Block code , String value ) {
295
- code .addLine ("%s.mergeFrom(%s.%s());" , property .getField (), value , property .getGetterName ());
361
+ code .addLine ("if (%s == null) {" , property .getField ())
362
+ .addLine (" %s = %s.%s();" , property .getField (), value , property .getGetterName ())
363
+ .addLine ("} else {" )
364
+ .addLine (" %s().mergeFrom(%s.%s());" ,
365
+ getBuilderMethod (property ), value , property .getGetterName ())
366
+ .addLine ("}" );
296
367
}
297
368
298
369
@ Override
299
370
public void addMergeFromBuilder (Block code , String builder ) {
300
- code .add ("%s.mergeFrom(%s.%s()" , property .getField (), builder , getBuilderMethod (property ));
371
+ Excerpt base = Declarations .upcastToGeneratedBuilder (code , metadata , builder );
372
+ Variable fieldValue = new Variable (property .getName () + "Value" );
373
+ code .addLine ("if (%s == null) {" , property .getField ().on (base ))
374
+ .addLine (" // Nothing to merge" )
375
+ .addLine ("} else if (%s instanceof %s) {" ,
376
+ property .getField ().on (base ),
377
+ ModelUtils .maybeAsTypeElement (property .getType ()).get ())
378
+ .addLine (" %1$s %2$s %3$s = (%2$s) %4$s;" ,
379
+ suppressUnchecked , property .getType (), fieldValue , property .getField ().on (base ))
380
+ .addLine (" if (%s == null) {" , property .getField ())
381
+ .addLine (" %s = %s;" , property .getField (), fieldValue )
382
+ .addLine (" } else {" )
383
+ .addLine (" %s().mergeFrom(%s);" , getBuilderMethod (property ), fieldValue )
384
+ .addLine (" }" )
385
+ .addLine ("} else {" )
386
+ .add (" %s().mergeFrom(%s.%s()" ,
387
+ getBuilderMethod (property ), base , getBuilderMethod (property ));
301
388
if (mergeFromBuilderMethod == MergeBuilderMethod .BUILD_PARTIAL_AND_MERGE ) {
302
389
code .add (".buildPartial()" );
303
390
}
304
- code .add (");\n " );
391
+ code .add (");\n " )
392
+ .addLine ("}" );
305
393
}
306
394
307
395
@ Override
@@ -322,7 +410,16 @@ public void addSetFromResult(SourceBuilder code, Excerpt builder, Excerpt variab
322
410
323
411
@ Override
324
412
public void addClearField (Block code ) {
325
- code .addLine ("%s.clear();" , property .getField ());
413
+ Variable fieldBuilder = new Variable (property .getName () + "Builder" );
414
+ code .addLine (" if (%1$s == null || %1$s instanceof %2$s) {" ,
415
+ property .getField (),
416
+ ModelUtils .maybeAsTypeElement (property .getType ()).get ())
417
+ .addLine (" %s = null;" , property .getField ())
418
+ .addLine (" } else {" )
419
+ .addLine (" %1$s %2$s %3$s = (%2$s) %4$s;" ,
420
+ suppressUnchecked , builderType , fieldBuilder , property .getField ())
421
+ .addLine (" %s.clear();" , fieldBuilder )
422
+ .addLine (" }" );
326
423
}
327
424
328
425
private static final class IsCallableMethod implements Predicate <ExecutableElement > {
0 commit comments