aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rwxr-xr-xAUTHORS1
-rw-r--r--src/core/lombok/Builder.java13
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java21
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/HandleBuilder.java299
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java6
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java6
-rwxr-xr-xsrc/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java18
-rw-r--r--src/core/lombok/javac/handlers/HandleBuilder.java81
-rw-r--r--src/core/lombok/javac/handlers/JavacSingularsRecipes.java28
-rw-r--r--test/transform/resource/after-delombok/BuilderSimpleWithSetterPrefix.java34
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularAnnotatedTypesWithSetterPrefix.java124
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularGuavaListsSetsWithSetterPrefix.java140
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularGuavaMapsWithSetterPrefix.java94
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularListsWithSetterPrefix.java123
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularMapsWithSetterPrefix.java213
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularNoAutoWithSetterPrefix.java121
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularRedirectToGuavaWithSetterPrefix.java93
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularSetsWithSetterPrefix.java153
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularToBuilderWithNullWithSetterPrefix.java65
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularWildcardListsWithToBuilderWithSetterPrefix.java97
-rw-r--r--test/transform/resource/after-delombok/BuilderSingularWithPrefixesWithSetterPrefix.java56
-rw-r--r--test/transform/resource/after-delombok/BuilderTypeAnnosWithSetterPrefix.java45
-rw-r--r--test/transform/resource/after-delombok/BuilderValueDataWithSetterPrefix.java109
-rw-r--r--test/transform/resource/after-delombok/BuilderWithAccessorsWithSetterPrefix.java60
-rw-r--r--test/transform/resource/after-delombok/BuilderWithBadNamesWithSetterPrefix.java42
-rw-r--r--test/transform/resource/after-delombok/BuilderWithDeprecatedWithSetterPrefix.java114
-rw-r--r--test/transform/resource/after-delombok/BuilderWithExistingBuilderClassWithSetterPrefix.java40
-rw-r--r--test/transform/resource/after-delombok/BuilderWithNoBuilderMethodWithSetterPrefix.java33
-rw-r--r--test/transform/resource/after-delombok/BuilderWithNonNullWithSetterPrefix.java40
-rw-r--r--test/transform/resource/after-delombok/BuilderWithRecursiveGenericsWithSetterPrefix.java85
-rw-r--r--test/transform/resource/after-delombok/BuilderWithToBuilderWithSetterPrefix.java146
-rw-r--r--test/transform/resource/after-delombok/BuilderWithTolerateWithSetterPrefix.java40
-rw-r--r--test/transform/resource/after-ecj/BuilderSimpleWithSetterPrefix.java27
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularAnnotatedTypesWithSetterPrefix.java121
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularGuavaListsSetsWithSetterPrefix.java125
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularGuavaMapsWithSetterPrefix.java83
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularListsWithSetterPrefix.java116
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularMapsWithSetterPrefix.java209
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularNoAutoWithSetterPrefix.java114
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularRedirectToGuavaWithSetterPrefix.java83
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularSetsWithSetterPrefix.java145
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularToBuilderWithNullWithSetterPrefix.java60
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularWildcardListsWithToBuilderWithSetterPrefix.java92
-rw-r--r--test/transform/resource/after-ecj/BuilderSingularWithPrefixesWithSetterPrefix.java51
-rw-r--r--test/transform/resource/after-ecj/BuilderTypeAnnosWithSetterPrefix.java33
-rw-r--r--test/transform/resource/after-ecj/BuilderValueDataWithSetterPrefix.java90
-rw-r--r--test/transform/resource/after-ecj/BuilderWithAccessorsWithSetterPrefix.java47
-rw-r--r--test/transform/resource/after-ecj/BuilderWithBadNamesWithSetterPrefix.java33
-rw-r--r--test/transform/resource/after-ecj/BuilderWithDeprecatedWithSetterPrefix.java87
-rw-r--r--test/transform/resource/after-ecj/BuilderWithExistingBuilderClassWithSetterPrefix.java36
-rw-r--r--test/transform/resource/after-ecj/BuilderWithNoBuilderMethodWithSetterPrefix.java27
-rw-r--r--test/transform/resource/after-ecj/BuilderWithNonNullWithSetterPrefix.java34
-rw-r--r--test/transform/resource/after-ecj/BuilderWithRecursiveGenericsWithSetterPrefix.java78
-rw-r--r--test/transform/resource/after-ecj/BuilderWithToBuilderWithSetterPrefix.java124
-rw-r--r--test/transform/resource/after-ecj/BuilderWithTolerateWithSetterPrefix.java34
-rw-r--r--test/transform/resource/before/BuilderSimpleWithSetterPrefix.java6
-rw-r--r--test/transform/resource/before/BuilderSingularAnnotatedTypesWithSetterPrefix.java14
-rw-r--r--test/transform/resource/before/BuilderSingularGuavaListsSetsWithSetterPrefix.java16
-rw-r--r--test/transform/resource/before/BuilderSingularGuavaMapsWithSetterPrefix.java12
-rw-r--r--test/transform/resource/before/BuilderSingularListsWithSetterPrefix.java11
-rw-r--r--test/transform/resource/before/BuilderSingularMapsWithSetterPrefix.java15
-rw-r--r--test/transform/resource/before/BuilderSingularNoAutoWithSetterPrefix.java11
-rw-r--r--test/transform/resource/before/BuilderSingularRedirectToGuavaWithSetterPrefix.java13
-rw-r--r--test/transform/resource/before/BuilderSingularSetsWithSetterPrefix.java12
-rw-r--r--test/transform/resource/before/BuilderSingularToBuilderWithNullWithSetterPrefix.java10
-rw-r--r--test/transform/resource/before/BuilderSingularWildcardListsWithToBuilderWithSetterPrefix.java10
-rw-r--r--test/transform/resource/before/BuilderSingularWithPrefixesWithSetterPrefix.java7
-rw-r--r--test/transform/resource/before/BuilderTypeAnnosWithSetterPrefix.java14
-rw-r--r--test/transform/resource/before/BuilderValueDataWithSetterPrefix.java11
-rw-r--r--test/transform/resource/before/BuilderWithAccessorsWithSetterPrefix.java7
-rw-r--r--test/transform/resource/before/BuilderWithBadNamesWithSetterPrefix.java5
-rw-r--r--test/transform/resource/before/BuilderWithDeprecatedWithSetterPrefix.java11
-rw-r--r--test/transform/resource/before/BuilderWithExistingBuilderClassWithSetterPrefix.java15
-rw-r--r--test/transform/resource/before/BuilderWithNoBuilderMethodWithSetterPrefix.java5
-rw-r--r--test/transform/resource/before/BuilderWithNonNullWithSetterPrefix.java5
-rw-r--r--test/transform/resource/before/BuilderWithRecursiveGenericsWithSetterPrefix.java13
-rw-r--r--test/transform/resource/before/BuilderWithToBuilderWithSetterPrefix.java20
-rw-r--r--test/transform/resource/before/BuilderWithTolerateWithSetterPrefix.java18
-rw-r--r--test/transform/resource/messages-delombok/BuilderSingularNoAutoWithSetterPrefix.java.messages2
-rw-r--r--test/transform/resource/messages-ecj/BuilderSingularNoAutoWithSetterPrefix.java.messages2
81 files changed, 4507 insertions, 150 deletions
diff --git a/.gitignore b/.gitignore
index b3f7b18d..824ae9c2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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/AUTHORS b/AUTHORS
index 91ef1793..77cbbfe9 100755
--- a/AUTHORS
+++ b/AUTHORS
@@ -2,6 +2,7 @@ Lombok contributors in alphabetical order:
Adam Juraszek <juriad@gmail.com>
Bulgakov Alexander <buls@yandex.ru>
+Caleb Brinkman <floralvikings@gmail.com>
Christian Nüssgens <christian@nuessgens.com>
Christian Sterzl <christian.sterzl@gmail.com>
DaveLaw <project.lombok@apconsult.de>
diff --git a/src/core/lombok/Builder.java b/src/core/lombok/Builder.java
index dfa5ecb5..fcbe1a09 100644
--- a/src/core/lombok/Builder.java
+++ b/src/core/lombok/Builder.java
@@ -153,6 +153,19 @@ 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)}
+ *
+ * Note that using "with" to prefix builder setter methods is strongly discouraged as as "with" normally
+ * suggests immutable data structures, and builders by definition are mutable objects.
+ *
+ * @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/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java
index 483431cc..ce5a1b4c 100755
--- a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java
+++ b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java
@@ -122,6 +122,7 @@ public class EclipseSingularsRecipes {
private final EclipseNode annotation;
private final char[] singularName;
private final char[] pluralName;
+ private final char[] setterPrefix;
private final List<TypeReference> typeArgs;
private final String targetFqn;
private final EclipseSingularizer singularizer;
@@ -135,8 +136,20 @@ public class EclipseSingularsRecipes {
this.targetFqn = targetFqn;
this.singularizer = singularizer;
this.source = source;
+ this.setterPrefix = new char[0];
}
-
+
+ public SingularData(EclipseNode annotation, char[] singularName, char[] pluralName, List<TypeReference> typeArgs, String targetFqn, EclipseSingularizer singularizer, ASTNode source, char[] setterPrefix) {
+ this.annotation = annotation;
+ this.singularName = singularName;
+ this.pluralName = pluralName;
+ this.typeArgs = typeArgs;
+ this.targetFqn = targetFqn;
+ this.singularizer = singularizer;
+ this.source = source;
+ this.setterPrefix = setterPrefix;
+ }
+
public void setGeneratedByRecursive(ASTNode target) {
SetGeneratedByVisitor visitor = new SetGeneratedByVisitor(source);
@@ -164,7 +177,11 @@ public class EclipseSingularsRecipes {
public char[] getPluralName() {
return pluralName;
}
-
+
+ public char[] getSetterPrefix() {
+ return setterPrefix;
+ }
+
public List<TypeReference> getTypeArgs() {
return typeArgs;
}
diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java
index 8bfdeb65..aab97e18 100755
--- a/src/core/lombok/eclipse/handlers/HandleBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java
@@ -1,16 +1,16 @@
/*
* Copyright (C) 2013-2019 The Project Lombok Authors.
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -101,17 +101,17 @@ import lombok.experimental.NonFinal;
@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 HandleBuilder extends EclipseAnnotationHandler<Builder> {
private HandleConstructor handleConstructor = new HandleConstructor();
-
+
private static final char[] CLEAN_FIELD_NAME = "$lombokUnclean".toCharArray();
private static final char[] CLEAN_METHOD_NAME = "$lombokClean".toCharArray();
-
+
private static final boolean toBoolean(Object expr, boolean defaultValue) {
if (expr == null) return defaultValue;
if (expr instanceof FalseLiteral) return false;
if (expr instanceof TrueLiteral) return true;
return ((Boolean) expr).booleanValue();
}
-
+
static class BuilderFieldData {
Annotation[] annotations;
TypeReference type;
@@ -124,10 +124,10 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
ObtainVia obtainVia;
EclipseNode obtainViaNode;
EclipseNode originalFieldNode;
-
+
List<EclipseNode> createdFields = new ArrayList<EclipseNode>();
}
-
+
private static boolean equals(String a, char[] b) {
if (a.length() != b.length) return false;
for (int i = 0; i < b.length; i++) {
@@ -135,7 +135,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
return true;
}
-
+
private static boolean equals(String a, char[][] b) {
if (a == null || a.isEmpty()) return b.length == 0;
String[] aParts = a.split("\\.");
@@ -145,24 +145,24 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
}
return true;
}
-
+
private static final char[] DEFAULT_PREFIX = {'$', 'd', 'e', 'f', 'a', 'u', 'l', 't', '$'};
private static final char[] SET_PREFIX = {'$', 's', 'e', 't'};
private static final char[] VALUE_PREFIX = {'$', 'v', 'a', 'l', 'u', 'e'};
-
+
private static final char[] prefixWith(char[] prefix, char[] name) {
char[] out = new char[prefix.length + name.length];
System.arraycopy(prefix, 0, out, 0, prefix.length);
System.arraycopy(name, 0, out, prefix.length, name.length);
return out;
}
-
+
@Override public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
CheckerFrameworkVersion cfv = getCheckerFrameworkVersion(annotationNode);
-
+
long p = (long) ast.sourceStart << 32 | ast.sourceEnd;
-
+
Builder builderInstance = annotation.getInstance();
AccessLevel accessForOuters = builderInstance.access();
if (accessForOuters == null) accessForOuters = AccessLevel.PUBLIC;
@@ -171,22 +171,22 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
accessForOuters = AccessLevel.PUBLIC;
}
AccessLevel accessForInners = accessForOuters == AccessLevel.PROTECTED ? AccessLevel.PUBLIC : accessForOuters;
-
+
// These exist just to support the 'old' lombok.experimental.Builder, which had these properties. lombok.Builder no longer has them.
boolean fluent = toBoolean(annotation.getActualExpression("fluent"), true);
boolean chain = toBoolean(annotation.getActualExpression("chain"), true);
-
+
String builderMethodName = builderInstance.builderMethodName();
String buildMethodName = builderInstance.buildMethodName();
String builderClassName = builderInstance.builderClassName();
String toBuilderMethodName = "toBuilder";
boolean toBuilder = builderInstance.toBuilder();
List<char[]> typeArgsForToBuilder = null;
-
+
if (builderMethodName == null) builderMethodName = "builder";
if (buildMethodName == null) buildMethodName = "build";
if (builderClassName == null) builderClassName = "";
-
+
boolean generateBuilderMethod;
if (builderMethodName.isEmpty()) {
generateBuilderMethod = false;
@@ -195,74 +195,74 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
} else {
generateBuilderMethod = true;
}
-
+
if (!checkName("buildMethodName", buildMethodName, annotationNode)) return;
if (!builderClassName.isEmpty()) {
if (!checkName("builderClassName", builderClassName, annotationNode)) return;
}
-
+
EclipseNode parent = annotationNode.up();
-
+
List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>();
TypeReference returnType;
TypeParameter[] typeParams;
TypeReference[] thrownExceptions;
char[] nameOfStaticBuilderMethod;
EclipseNode tdParent;
-
+
EclipseNode fillParametersFrom = parent.get() instanceof AbstractMethodDeclaration ? parent : null;
boolean addCleaning = false;
boolean isStatic = true;
-
+
List<EclipseNode> nonFinalNonDefaultedFields = null;
-
+
if (builderClassName.isEmpty()) builderClassName = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME);
if (builderClassName == null || builderClassName.isEmpty()) builderClassName = "*Builder";
boolean replaceNameInBuilderClassName = builderClassName.contains("*");
-
+
if (parent.get() instanceof TypeDeclaration) {
tdParent = parent;
TypeDeclaration td = (TypeDeclaration) tdParent.get();
-
+
List<EclipseNode> allFields = new ArrayList<EclipseNode>();
boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent));
for (EclipseNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) {
FieldDeclaration fd = (FieldDeclaration) fieldNode.get();
EclipseNode isDefault = findAnnotation(Builder.Default.class, fieldNode);
boolean isFinal = ((fd.modifiers & ClassFileConstants.AccFinal) != 0) || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode));
-
+
Annotation[] copyableAnnotations = findCopyableAnnotations(fieldNode);
-
+
BuilderFieldData bfd = new BuilderFieldData();
bfd.rawName = fieldNode.getName().toCharArray();
bfd.name = removePrefixFromField(fieldNode);
bfd.builderFieldName = bfd.name;
bfd.annotations = copyAnnotations(fd, copyableAnnotations);
bfd.type = fd.type;
- bfd.singularData = getSingularData(fieldNode, ast);
+ bfd.singularData = getSingularData(fieldNode, ast, builderInstance.setterPrefix());
bfd.originalFieldNode = fieldNode;
-
+
if (bfd.singularData != null && isDefault != null) {
isDefault.addError("@Builder.Default and @Singular cannot be mixed.");
isDefault = null;
}
-
+
if (fd.initialization == null && isDefault != nu