diff options
3 files changed, 49 insertions, 5 deletions
diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 6c1b2cac..1bbc514e 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -104,7 +104,8 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { private static final char[] DEFAULT_PREFIX = "$default$".toCharArray(); private static final char[] SET_PREFIX = "$set".toCharArray(); private static final char[] SELF_METHOD_NAME = "self".toCharArray(); - private static final char[] TO_BUILDER_METHOD_NAME = "toBuilder".toCharArray(); + private static final String TO_BUILDER_METHOD_NAME_STRING = "toBuilder"; + private static final char[] TO_BUILDER_METHOD_NAME = TO_BUILDER_METHOD_NAME_STRING.toCharArray(); private static final char[] FILL_VALUES_METHOD_NAME = "$fillValuesFrom".toCharArray(); private static final char[] EMPTY_LIST = "emptyList".toCharArray(); @@ -345,6 +346,15 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { MethodDeclaration md = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, tdParent, typeParams, ast); if (md != null) injectMethod(tdParent, md); } + + if (toBuilder) switch (methodExists(TO_BUILDER_METHOD_NAME_STRING, tdParent, 0)) { + case EXISTS_BY_USER: + annotationNode.addWarning("Not generating toBuilder() as it already exists."); + break; + case NOT_EXISTS: + MethodDeclaration md = generateToBuilderMethod(builderClassName, builderImplClassName, tdParent, typeParams, ast); + if (md != null) injectMethod(tdParent, md); + } } private EclipseNode generateBuilderAbstractClass(EclipseNode tdParent, String builderClass, @@ -535,6 +545,41 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { } /** + * Generates a <code>toBuilder()</code> method in the annotated class that looks like this: + * <pre> + * public ParentBuilder<?, ?> toBuilder() { + * return new <i>Foobar</i>BuilderImpl().$fillValuesFrom(this); + * } + * </pre> + */ + private MethodDeclaration generateToBuilderMethod(String builderClassName, String builderImplClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long) pS << 32 | pE; + + MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); + out.selector = TO_BUILDER_METHOD_NAME; + out.modifiers = ClassFileConstants.AccPublic; + out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; + + // Add type params if there are any. + if (typeParams != null && typeParams.length > 0) out.typeParameters = copyTypeParams(typeParams, source); + + TypeReference[] wildcards = new TypeReference[] {new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND) }; + out.returnType = new ParameterizedSingleTypeReference(builderClassName.toCharArray(), mergeToTypeReferences(typeParams, wildcards), 0, p); + + AllocationExpression newClass = new AllocationExpression(); + newClass.type = namePlusTypeParamsToTypeReference(builderImplClassName.toCharArray(), typeParams, p); + MessageSend invokeFillMethod = new MessageSend(); + invokeFillMethod.receiver = newClass; + invokeFillMethod.selector = FILL_VALUES_METHOD_NAME; + invokeFillMethod.arguments = new Expression[] {new ThisReference(0, 0)}; + out.statements = new Statement[] {new ReturnStatement(invokeFillMethod, pS, pE)}; + + out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope); + return out; + } + + /** * Generates a <code>$fillValuesFrom()</code> method in the abstract builder class that looks * like this: * <pre> diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index c8727f93..bdcd043a 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -523,7 +523,6 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { JCExpression newClass = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, type.toName(builderImplClassName), typeParams), List.<JCExpression>nil(), null); List<JCExpression> methodArgs = List.<JCExpression>of(maker.Ident(type.toName("this"))); JCMethodInvocation invokeFillMethod = maker.Apply(List.<JCExpression>nil(), maker.Select(newClass, type.toName(FILL_VALUES_METHOD_NAME)), methodArgs); -// JCMethodInvocation invokeFillMethod = maker.Apply(List.<JCExpression>nil(), maker.Select(newClass, type.toName(FILL_VALUES_METHOD_NAME)), List.<JCExpression>nil()); JCStatement statement = maker.Return(invokeFillMethod); JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); diff --git a/test/transform/resource/after-ecj/SuperBuilderBasicToBuilder.java b/test/transform/resource/after-ecj/SuperBuilderBasicToBuilder.java index 6dd06fb7..2b294d65 100644 --- a/test/transform/resource/after-ecj/SuperBuilderBasicToBuilder.java +++ b/test/transform/resource/after-ecj/SuperBuilderBasicToBuilder.java @@ -82,7 +82,7 @@ public class SuperBuilderBasicToBuilder { public ChildBuilder() {
super();
}
- protected @java.lang.Override @java.lang.SuppressWarnings("all") B $fillValuesFrom(C instance) {
+ protected @java.lang.Override @java.lang.SuppressWarnings("all") B $fillValuesFrom(final C instance) {
super.$fillValuesFrom(instance);
field3(instance.field3);
return self();
@@ -120,10 +120,10 @@ public class SuperBuilderBasicToBuilder { return new ChildBuilderImpl().$fillValuesFrom(this);
}
}
- public SuperBuilderBasic() {
+ public SuperBuilderBasicToBuilder() {
super();
}
public static void test() {
- Child x = Child.builder().field3(0.0).field1(5).item("").build();
+ Child x = Child.builder().field3(0.0).field1(5).item("").build().toBuilder().build();
}
}
|