diff options
author | Jan Rieke <it@janrieke.de> | 2018-09-11 10:32:50 +0200 |
---|---|---|
committer | Jan Rieke <it@janrieke.de> | 2018-09-11 10:39:01 +0200 |
commit | b42ce5325afbe6202d5d5815a9c74dd64a0ce3de (patch) | |
tree | 19b540dc134d406bdc27f0d5e53fe09ddd9ce0c5 | |
parent | 849aa4fddadb40439a30967131d2847b90fb139f (diff) | |
download | lombok-b42ce5325afbe6202d5d5815a9c74dd64a0ce3de.tar.gz lombok-b42ce5325afbe6202d5d5815a9c74dd64a0ce3de.tar.bz2 lombok-b42ce5325afbe6202d5d5815a9c74dd64a0ce3de.zip |
SuperBuilder: generate toBuilder method (javac)
4 files changed, 53 insertions, 22 deletions
diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 63697691..91cd4abb 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -84,7 +84,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { return ((Boolean) expr).booleanValue(); } - private static class BuilderFieldData { + public static class BuilderFieldData { JCExpression type; Name rawName; Name name; diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index b8f572d5..62dc93c1 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -68,6 +68,7 @@ import lombok.javac.Javac; import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; import lombok.javac.JavacTreeMaker; +import lombok.javac.handlers.HandleBuilder.BuilderFieldData; import lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult; import lombok.javac.handlers.JavacSingularsRecipes.ExpressionMaker; import lombok.javac.handlers.JavacSingularsRecipes.StatementMaker; @@ -78,21 +79,9 @@ import lombok.javac.handlers.JavacSingularsRecipes.SingularData; @HandlerPriority(-1024) //-2^10; to ensure we've picked up @FieldDefault's changes (-2048) but @Value hasn't removed itself yet (-512), so that we can error on presence of it on the builder classes. public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { private static final String SELF_METHOD = "self"; - - private static class BuilderFieldData { - JCExpression type; - Name rawName; - Name name; - Name nameOfDefaultProvider; - Name nameOfSetFlag; - SingularData singularData; - ObtainVia obtainVia; - JavacNode obtainViaNode; - JavacNode originalFieldNode; - - java.util.List<JavacNode> createdFields = new ArrayList<JavacNode>(); - } - + private static final String TO_BUILDER_METHOD_NAME = "toBuilder"; + private static final String FILL_VALUES_METHOD_NAME = "$fillValuesFrom"; + @Override public void handle(AnnotationValues<SuperBuilder> annotation, JCAnnotation ast, JavacNode annotationNode) { handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder"); @@ -109,6 +98,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { if (!checkName("builderMethodName", builderMethodName, annotationNode)) return; if (!checkName("buildMethodName", buildMethodName, annotationNode)) return; + boolean toBuilder = superbuilderAnnotation.toBuilder(); + JavacNode tdParent = annotationNode.up(); java.util.List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>(); @@ -307,6 +298,19 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { if (builderMethod != null) injectMethod(tdParent, builderMethod); } } + + if (toBuilder) { + switch (methodExists(TO_BUILDER_METHOD_NAME, tdParent, 0)) { + case EXISTS_BY_USER: + annotationNode.addWarning("Not generating toBuilder() as it already exists."); + return; + case NOT_EXISTS: + JCMethodDecl md = generateToBuilderMethod(builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); + if (md != null) { + injectMethod(tdParent, md); + } + } + } } /** @@ -495,6 +499,39 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { return maker.MethodDef(maker.Modifiers(modifiers), type.toName(builderMethodName), returnType, copyTypeParams(source, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); } + /** + * Generates a toBuilder() method that looks like this: + * <pre> + * public ParentBuilder<?, ?> toBuilder() { + * return new <i>Foobar</i>BuilderImpl().$fillValuesFrom(this); + * } + * </pre> + */ + private JCMethodDecl generateToBuilderMethod(String builderClassName, String builderImplClassName, JavacNode source, JavacNode type, List<JCTypeParameter> typeParams) { + JavacTreeMaker maker = type.getTreeMaker(); + + ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); + for (JCTypeParameter typeParam : typeParams) typeArgs.append(maker.Ident(typeParam.name)); + + JCExpression newClass = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, type.toName(builderImplClassName), typeParams), List.<JCExpression>nil(), null); + 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)); + int modifiers = Flags.PUBLIC; + + // Add any type params of the annotated class to the return type. + ListBuffer<JCExpression> typeParameterNames = new ListBuffer<JCExpression>(); + typeParameterNames.addAll(typeParameterNames(maker, typeParams)); + // Now add the <?, ?>. + JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); + typeParameterNames.add(wildcard); + typeParameterNames.add(wildcard); + JCTypeApply returnType = maker.TypeApply(maker.Ident(type.toName(builderClassName)), typeParameterNames.toList()); + + return maker.MethodDef(maker.Modifiers(modifiers), type.toName(TO_BUILDER_METHOD_NAME), returnType, copyTypeParams(source, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); + } + private JCMethodDecl generateAbstractSelfMethod(JavacNode type, boolean override, String builderGenericName) { JavacTreeMaker maker = type.getTreeMaker(); List<JCAnnotation> annotations = List.nil(); diff --git a/test/transform/resource/after-delombok/SuperBuilderBasicToBuilder.java b/test/transform/resource/after-delombok/SuperBuilderBasicToBuilder.java index 2e097c1a..ae3f5f31 100644 --- a/test/transform/resource/after-delombok/SuperBuilderBasicToBuilder.java +++ b/test/transform/resource/after-delombok/SuperBuilderBasicToBuilder.java @@ -1,7 +1,5 @@ import java.util.List;
-import manual.model.Superclass.SuperclassBuilder;
-import manual.model.Superclass.SuperclassBuilderImpl;
public class SuperBuilderBasicToBuilder {
public static class Parent {
int field1;
diff --git a/test/transform/resource/after-ecj/SuperBuilderBasicToBuilder.java b/test/transform/resource/after-ecj/SuperBuilderBasicToBuilder.java index 03fc86d1..a2299a9c 100644 --- a/test/transform/resource/after-ecj/SuperBuilderBasicToBuilder.java +++ b/test/transform/resource/after-ecj/SuperBuilderBasicToBuilder.java @@ -1,9 +1,5 @@ import java.util.List;
-import SuperBuilderBasicToBuilder.Child.ChildBuilder;
-import SuperBuilderBasicToBuilder.Child.ChildBuilderImpl;
-import SuperBuilderBasicToBuilder.Parent.ParentBuilder;
-import SuperBuilderBasicToBuilder.Parent.ParentBuilderImpl;
public class SuperBuilderBasic {
public static @lombok.experimental.SuperBuilder class Parent {
public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder<C extends Parent, B extends ParentBuilder<C, B>> {
|