diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | src/core/lombok/Builder.java | 10 | ||||
-rwxr-xr-x | src/core/lombok/eclipse/handlers/HandleBuilder.java | 44 | ||||
-rw-r--r-- | src/core/lombok/javac/handlers/HandleBuilder.java | 52 | ||||
-rw-r--r-- | test/transform/resource/after-delombok/BuilderWithPrefix.java | 34 | ||||
-rw-r--r-- | test/transform/resource/after-ecj/BuilderWithPrefix.java | 27 | ||||
-rw-r--r-- | test/transform/resource/before/BuilderWithPrefix.java | 6 |
7 files changed, 166 insertions, 10 deletions
@@ -15,10 +15,11 @@ /.factorypath /lombok.iml /.idea +*.iml *.markdown.html /junit*.properties /eclipse.location /.apt_generated/ /out /website/lombokSupporters -/pom.xml
\ No newline at end of file +/pom.xml diff --git a/src/core/lombok/Builder.java b/src/core/lombok/Builder.java index dfa5ecb5..d7fe42a1 100644 --- a/src/core/lombok/Builder.java +++ b/src/core/lombok/Builder.java @@ -153,6 +153,16 @@ public @interface Builder { * @return The builder class will be generated with this access modifier. */ AccessLevel access() default lombok.AccessLevel.PUBLIC; + + /** + * Prefix to prepend to set methods in the generated builder class. By default, generated methods to not include a + * prefix. If this value populated, the first letter of the generated method name will be capitalized. + * + * For example, a method normally generated as {@code someField(String someField)} would instead be generated as {@code withSomeField(String someField)} + * + * @return The prefix to prepend to generated method names. + */ + String setterPrefix() default ""; /** * Put on a field (in case of {@code @Builder} on a type) or a parameter (for {@code @Builder} on a constructor or static method) to diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index d2b1b823..5a4d5bff 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import com.sun.tools.javac.util.Name; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration; @@ -487,7 +488,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } for (BuilderFieldData bfd : builderFields) { - makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners, bfd.originalFieldNode); + makePrefixedSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners, bfd.originalFieldNode, builderInstance.setterPrefix()); } { @@ -845,7 +846,46 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { sourceNode, methodAnnsList, annotations != null ? Arrays.asList(copyAnnotations(sourceNode.get(), annotations)) : Collections.<Annotation>emptyList()); injectMethod(builderType, setter); } - + + public void makePrefixedSetterMethodsForBuilder(EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, boolean fluent, boolean chain, AccessLevel access, EclipseNode originalFieldNode, String prefix) { + boolean deprecate = isFieldDeprecated(bfd.originalFieldNode); + if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) { + makePrefixedSetterMethodForBuilder(builderType, deprecate, bfd.createdFields.get(0), bfd.name, bfd.nameOfSetFlag, sourceNode, fluent, chain, bfd.annotations, access, originalFieldNode, prefix); + } else { + bfd.singularData.getSingularizer().generateMethods(bfd.singularData, deprecate, builderType, fluent, chain, access); + } + } + + private void makePrefixedSetterMethodForBuilder(EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] paramName, char[] nameOfSetFlag, EclipseNode sourceNode, boolean fluent, boolean chain, Annotation[] annotations, AccessLevel access, EclipseNode originalFieldNode, String prefix) { + TypeDeclaration td = (TypeDeclaration) builderType.get(); + AbstractMethodDeclaration[] existing = td.methods; + if (existing == null) existing = EMPTY; + int len = existing.length; + FieldDeclaration fd = (FieldDeclaration) fieldNode.get(); + char[] name = fd.name; + + for (int i = 0; i < len; i++) { + if (!(existing[i] instanceof MethodDeclaration)) continue; + char[] existingName = existing[i].selector; + if (Arrays.equals(name, existingName) && !isTolerate(fieldNode, existing[i])) return; + } + + String setterPrefix = prefix.isEmpty() ? "set" : prefix; + String setterName; + if(fluent) { + setterName = prefix.isEmpty() ? new String(paramName) : HandlerUtil.buildAccessorName(setterPrefix, new String(paramName)); + } else { + setterName = HandlerUtil.buildAccessorName(setterPrefix, new String(paramName)); + } + + List<Annotation> methodAnnsList = Collections.<Annotation>emptyList(); + Annotation[] methodAnns = EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); + if (methodAnns != null && methodAnns.length > 0) methodAnnsList = Arrays.asList(methodAnns); + MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, paramName, nameOfSetFlag, chain, toEclipseModifier(access), + sourceNode, methodAnnsList, annotations != null ? Arrays.asList(copyAnnotations(sourceNode.get(), annotations)) : Collections.<Annotation>emptyList()); + injectMethod(builderType, setter); + } + public EclipseNode makeBuilderClass(boolean isStatic, EclipseNode tdParent, String builderClassName, TypeParameter[] typeParams, ASTNode source, AccessLevel access) { TypeDeclaration parent = (TypeDeclaration) tdParent.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 35a6dc26..e447ace7 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -434,7 +434,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { } for (BuilderFieldData bfd : builderFields) { - makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners); + makePrefixedSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners, builderInstance.setterPrefix()); } { @@ -752,26 +752,64 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { private void makeSimpleSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, List<JCAnnotation> annosOnParam, JavacNode originalFieldNode, AccessLevel access) { Name fieldName = ((JCVariableDecl) fieldNode.get()).name; - + for (JavacNode child : builderType.down()) { if (child.getKind() != Kind.METHOD) continue; JCMethodDecl methodDecl = (JCMethodDecl) child.get(); Name existingName = methodDecl.name; if (existingName.equals(fieldName) && !isTolerate(fieldNode, methodDecl)) return; } - + String setterName = fluent ? paramName.toString() : HandlerUtil.buildAccessorName("set", paramName.toString()); - + JavacTreeMaker maker = fieldNode.getTreeMaker(); - + List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); JCMethodDecl newMethod = HandleSetter.createSetter(toJavacModifier(access), deprecate, fieldNode, maker, setterName, paramName, nameOfSetFlag, chain, source, methodAnns, annosOnParam); recursiveSetGeneratedBy(newMethod, source.get(), builderType.getContext()); copyJavadoc(originalFieldNode, newMethod, CopyJavadoc.SETTER); - + injectMethod(builderType, newMethod); } - + + public void makePrefixedSetterMethodsForBuilder(JavacNode builderType, BuilderFieldData fieldNode, JavacNode source, boolean fluent, boolean chain, AccessLevel access, String prefix) { + boolean deprecate = isFieldDeprecated(fieldNode.originalFieldNode); + if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) { + makePrefixedSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.name, fieldNode.nameOfSetFlag, source, fluent, chain, fieldNode.annotations, fieldNode.originalFieldNode, access, prefix); + } else { + // TODO prefixed version + fieldNode.singularData.getSingularizer().generateMethods(fieldNode.singularData, deprecate, builderType, source.get(), fluent, chain, access); + } + } + + private void makePrefixedSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name paramName, Name nameOfSetFlag, JavacNode source, boolean fluent, boolean chain, List<JCAnnotation> annosOnParam, JavacNode originalFieldNode, AccessLevel access, String prefix) { + Name fieldName = ((JCVariableDecl) fieldNode.get()).name; + + for (JavacNode child : builderType.down()) { + if (child.getKind() != Kind.METHOD) continue; + JCMethodDecl methodDecl = (JCMethodDecl) child.get(); + Name existingName = methodDecl.name; + if (existingName.equals(fieldName) && !isTolerate(fieldNode, methodDecl)) return; + } + + String setterPrefix = prefix.isEmpty() ? "set" : prefix; + String setterName; + if(fluent) { + setterName = prefix.isEmpty() ? paramName.toString() : HandlerUtil.buildAccessorName(setterPrefix, paramName.toString()); + } else { + setterName = HandlerUtil.buildAccessorName(setterPrefix, paramName.toString()); + } + + JavacTreeMaker maker = fieldNode.getTreeMaker(); + + List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); + JCMethodDecl newMethod = HandleSetter.createSetter(toJavacModifier(access), deprecate, fieldNode, maker, setterName, paramName, nameOfSetFlag, chain, source, methodAnns, annosOnParam); + recursiveSetGeneratedBy(newMethod, source.get(), builderType.getContext()); + copyJavadoc(originalFieldNode, newMethod, CopyJavadoc.SETTER); + + injectMethod(builderType, newMethod); + } + public JavacNode makeBuilderClass(boolean isStatic, JavacNode source, JavacNode tdParent, String builderClassName, List<JCTypeParameter> typeParams, JCAnnotation ast, AccessLevel access) { JavacTreeMaker maker = tdParent.getTreeMaker(); int modifiers = toJavacModifier(access); diff --git a/test/transform/resource/after-delombok/BuilderWithPrefix.java b/test/transform/resource/after-delombok/BuilderWithPrefix.java new file mode 100644 index 00000000..c29d2a16 --- /dev/null +++ b/test/transform/resource/after-delombok/BuilderWithPrefix.java @@ -0,0 +1,34 @@ +import java.util.List; +class BuilderWithPrefix<T> { + private int unprefixed; + @java.lang.SuppressWarnings("all") + BuilderWithPrefix(final int unprefixed) { + this.unprefixed = unprefixed; + } + @java.lang.SuppressWarnings("all") + protected static class BuilderWithPrefixBuilder<T> { + @java.lang.SuppressWarnings("all") + private int unprefixed; + @java.lang.SuppressWarnings("all") + BuilderWithPrefixBuilder() { + } + @java.lang.SuppressWarnings("all") + public BuilderWithPrefixBuilder<T> withUnprefixed(final int unprefixed) { + this.unprefixed = unprefixed; + return this; + } + @java.lang.SuppressWarnings("all") + public BuilderWithPrefix<T> build() { + return new BuilderWithPrefix<T>(unprefixed); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "BuilderWithPrefix.BuilderWithPrefixBuilder(unprefixed=" + this.unprefixed + ")"; + } + } + @java.lang.SuppressWarnings("all") + protected static <T> BuilderWithPrefixBuilder<T> builder() { + return new BuilderWithPrefixBuilder<T>(); + } +} diff --git a/test/transform/resource/after-ecj/BuilderWithPrefix.java b/test/transform/resource/after-ecj/BuilderWithPrefix.java new file mode 100644 index 00000000..98c42fe9 --- /dev/null +++ b/test/transform/resource/after-ecj/BuilderWithPrefix.java @@ -0,0 +1,27 @@ +import java.util.List; +@lombok.Builder(access = lombok.AccessLevel.PROTECTED,setterPrefix = "with") class BuilderWithPrefix<T> { + protected static @java.lang.SuppressWarnings("all") class BuilderWithPrefixBuilder<T> { + private @java.lang.SuppressWarnings("all") int unprefixed; + @java.lang.SuppressWarnings("all") BuilderWithPrefixBuilder() { + super(); + } + public @java.lang.SuppressWarnings("all") BuilderWithPrefixBuilder<T> withUnprefixed(final int unprefixed) { + this.unprefixed = unprefixed; + return this; + } + public @java.lang.SuppressWarnings("all") BuilderWithPrefix<T> build() { + return new BuilderWithPrefix<T>(unprefixed); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("BuilderWithPrefix.BuilderWithPrefixBuilder(unprefixed=" + this.unprefixed) + ")"); + } + } + private int unprefixed; + @java.lang.SuppressWarnings("all") BuilderWithPrefix(final int unprefixed) { + super(); + this.unprefixed = unprefixed; + } + protected static @java.lang.SuppressWarnings("all") <T>BuilderWithPrefixBuilder<T> builder() { + return new BuilderWithPrefixBuilder<T>(); + } +} diff --git a/test/transform/resource/before/BuilderWithPrefix.java b/test/transform/resource/before/BuilderWithPrefix.java new file mode 100644 index 00000000..38f3c029 --- /dev/null +++ b/test/transform/resource/before/BuilderWithPrefix.java @@ -0,0 +1,6 @@ +import java.util.List; + +@lombok.Builder(access = lombok.AccessLevel.PROTECTED, setterPrefix = "with") +class BuilderWithPrefix<T> { + private int unprefixed; +} |