From 1b06f4aa2960ba18d26a4d0218dd486872176971 Mon Sep 17 00:00:00 2001
From: Jan Rieke
Date: Thu, 26 Mar 2020 00:32:51 +0100
Subject: [PATCH 01/87] [SuperBuilder] fix IndexOutOfBounds (fixes #2407)
---
src/core/lombok/eclipse/handlers/HandleSuperBuilder.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
index 82af39fa..436cc6a0 100644
--- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
@@ -242,7 +242,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler {
String superclassBuilderClassName = builderClassNameTemplate.replace("*", superclassClassName);
char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1);
- tokens[tokens.length] = superclassBuilderClassName.toCharArray();
+ tokens[tokens.length-1] = superclassBuilderClassName.toCharArray();
long[] poss = new long[tokens.length];
Arrays.fill(poss, p);
From 736904298202bb75c27243f930c9e48bf2139be9 Mon Sep 17 00:00:00 2001
From: Jan Rieke
Date: Thu, 26 Mar 2020 23:21:44 +0100
Subject: [PATCH 02/87] [SuperBuilder] test qualified type references in
extends clause
---
test/transform/resource/after-delombok/SuperBuilderBasic.java | 4 ++--
test/transform/resource/after-ecj/SuperBuilderBasic.java | 4 ++--
test/transform/resource/before/SuperBuilderBasic.java | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/test/transform/resource/after-delombok/SuperBuilderBasic.java b/test/transform/resource/after-delombok/SuperBuilderBasic.java
index c347e41c..c3fa86f2 100644
--- a/test/transform/resource/after-delombok/SuperBuilderBasic.java
+++ b/test/transform/resource/after-delombok/SuperBuilderBasic.java
@@ -81,10 +81,10 @@ public class SuperBuilderBasic {
return new SuperBuilderBasic.Parent.ParentBuilderImpl();
}
}
- public static class Child extends Parent {
+ public static class Child extends SuperBuilderBasic.Parent {
double field3;
@java.lang.SuppressWarnings("all")
- public static abstract class ChildBuilder> extends Parent.ParentBuilder {
+ public static abstract class ChildBuilder> extends SuperBuilderBasic.Parent.ParentBuilder {
@java.lang.SuppressWarnings("all")
private double field3;
@java.lang.Override
diff --git a/test/transform/resource/after-ecj/SuperBuilderBasic.java b/test/transform/resource/after-ecj/SuperBuilderBasic.java
index b47f318d..7902c95f 100644
--- a/test/transform/resource/after-ecj/SuperBuilderBasic.java
+++ b/test/transform/resource/after-ecj/SuperBuilderBasic.java
@@ -71,8 +71,8 @@ public class SuperBuilderBasic {
return new SuperBuilderBasic.Parent.ParentBuilderImpl();
}
}
- public static @lombok.experimental.SuperBuilder class Child extends Parent {
- public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder> extends Parent.ParentBuilder {
+ public static @lombok.experimental.SuperBuilder class Child extends SuperBuilderBasic.Parent {
+ public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder> extends SuperBuilderBasic.Parent.ParentBuilder {
private @java.lang.SuppressWarnings("all") double field3;
public ChildBuilder() {
super();
diff --git a/test/transform/resource/before/SuperBuilderBasic.java b/test/transform/resource/before/SuperBuilderBasic.java
index f4e8c670..99d7284e 100644
--- a/test/transform/resource/before/SuperBuilderBasic.java
+++ b/test/transform/resource/before/SuperBuilderBasic.java
@@ -8,7 +8,7 @@ public class SuperBuilderBasic {
}
@lombok.experimental.SuperBuilder
- public static class Child extends Parent {
+ public static class Child extends SuperBuilderBasic.Parent {
double field3;
}
From 2566345e6108037c63383ec0287b773989d9ed33 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Thomas=20Kalm=C3=A1r?=
Date: Sat, 11 Apr 2020 14:42:11 +0200
Subject: [PATCH 03/87] Encode + sign properly. Fixes #1539
---
src/launch/lombok/launch/ShadowClassLoader.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/launch/lombok/launch/ShadowClassLoader.java b/src/launch/lombok/launch/ShadowClassLoader.java
index 30ca6e97..da377ae4 100644
--- a/src/launch/lombok/launch/ShadowClassLoader.java
+++ b/src/launch/lombok/launch/ShadowClassLoader.java
@@ -321,8 +321,9 @@ class ShadowClassLoader extends ClassLoader {
}
private static String urlDecode(String in) {
+ final String plusFixed = in.replaceAll("\\+", "%2B");
try {
- return URLDecoder.decode(in, "UTF-8");
+ return URLDecoder.decode(plusFixed, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new InternalError("UTF-8 not supported");
}
From 91cd859b72c89a47bbe145c00a9e7c1b20a5e657 Mon Sep 17 00:00:00 2001
From: Rawi01
Date: Tue, 14 Apr 2020 09:15:31 +0200
Subject: [PATCH 04/87] [fixes #2286] Set source range for vararg arrays
---
.../lombok/eclipse/agent/EclipsePatcher.java | 11 +++++++++++
src/eclipseAgent/lombok/launch/PatchFixesHider.java | 7 +++++++
2 files changed, 18 insertions(+)
diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
index 756c23fa..95d42c2c 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
@@ -103,6 +103,7 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
patchIdentifierEndReparse(sm);
patchRetrieveEllipsisStartPosition(sm);
patchRetrieveRightBraceOrSemiColonPosition(sm);
+ patchRetrieveProperRightBracketPosition(sm);
patchSetGeneratedFlag(sm);
patchDomAstReparseIssues(sm);
patchHideGeneratedNodes(sm);
@@ -445,6 +446,16 @@ public class EclipsePatcher implements AgentLauncher.AgentLaunchable {
// .transplant().request(StackRequest.RETURN_VALUE, StackRequest.PARAM2).build());
}
+ private static void patchRetrieveProperRightBracketPosition(ScriptManager sm) {
+ sm.addScript(ScriptBuilder.wrapMethodCall()
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "extractSubArrayType", "org.eclipse.jdt.core.dom.ArrayType", "org.eclipse.jdt.core.dom.ArrayType", "int", "int"))
+ .methodToWrap(new Hook("org.eclipse.jdt.core.dom.ASTConverter", "retrieveProperRightBracketPosition", "int", "int", "int"))
+ .wrapMethod(new Hook("lombok.launch.PatchFixesHider$PatchFixes", "fixRetrieveProperRightBracketPosition", "int", "int", "org.eclipse.jdt.core.dom.ArrayType"))
+ .requestExtra(StackRequest.PARAM1)
+ .transplant()
+ .build());
+ }
+
private static void patchSetGeneratedFlag(ScriptManager sm) {
sm.addScript(ScriptBuilder.addField()
.targetClass("org.eclipse.jdt.internal.compiler.ast.ASTNode")
diff --git a/src/eclipseAgent/lombok/launch/PatchFixesHider.java b/src/eclipseAgent/lombok/launch/PatchFixesHider.java
index 563beab1..deab0be1 100755
--- a/src/eclipseAgent/lombok/launch/PatchFixesHider.java
+++ b/src/eclipseAgent/lombok/launch/PatchFixesHider.java
@@ -38,6 +38,7 @@ import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.search.SearchMatch;
@@ -517,6 +518,12 @@ final class PatchFixesHider {
return -1;
}
+ public static int fixRetrieveProperRightBracketPosition(int retVal, ArrayType arrayType) {
+ if (retVal != -1 || arrayType == null) return retVal;
+ if (isGenerated(arrayType)) return arrayType.getStartPosition() + arrayType.getLength() - 1;
+ return -1;
+ }
+
public static final int ALREADY_PROCESSED_FLAG = 0x800000; //Bit 24
public static boolean checkBit24(Object node) throws Exception {
From d34fdeb3b4b44aae8c03cee0d3b1dd35a3d74e31 Mon Sep 17 00:00:00 2001
From: Rawi01
Date: Tue, 14 Apr 2020 23:15:50 +0200
Subject: [PATCH 05/87] [fixes #2246] Add null check
---
.../lombok/eclipse/handlers/EclipseHandlerUtil.java | 8 +++++---
.../resource/after-delombok/TypeUseAnnotations.java | 10 ++++++++++
.../resource/after-ecj/TypeUseAnnotations.java | 9 +++++++++
test/transform/resource/before/TypeUseAnnotations.java | 2 ++
4 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index 4df7a90b..2c6e1e77 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -660,9 +660,11 @@ public class EclipseHandlerUtil {
Annotation[][] b = new Annotation[a.length][];
for (int i = 0; i < a.length; i++) {
- b[i] = new Annotation[a[i].length];
- for (int j = 0 ; j < a[i].length; j++) {
- b[i][j] = copyAnnotation(a[i][j], a[i][j]);
+ if (a[i] != null) {
+ b[i] = new Annotation[a[i].length];
+ for (int j = 0 ; j < a[i].length; j++) {
+ b[i][j] = copyAnnotation(a[i][j], a[i][j]);
+ }
}
}
diff --git a/test/transform/resource/after-delombok/TypeUseAnnotations.java b/test/transform/resource/after-delombok/TypeUseAnnotations.java
index 1e1536bf..fbf32577 100644
--- a/test/transform/resource/after-delombok/TypeUseAnnotations.java
+++ b/test/transform/resource/after-delombok/TypeUseAnnotations.java
@@ -7,8 +7,18 @@ import java.util.List;
}
class TypeUseAnnotations {
List<@TA(x = 5) String> foo;
+ List bar;
+
+ class Inner {
+ }
+
@java.lang.SuppressWarnings("all")
public List<@TA(x = 5) String> getFoo() {
return this.foo;
}
+
+ @java.lang.SuppressWarnings("all")
+ public List getBar() {
+ return this.bar;
+ }
}
diff --git a/test/transform/resource/after-ecj/TypeUseAnnotations.java b/test/transform/resource/after-ecj/TypeUseAnnotations.java
index 156643b9..7041b59e 100644
--- a/test/transform/resource/after-ecj/TypeUseAnnotations.java
+++ b/test/transform/resource/after-ecj/TypeUseAnnotations.java
@@ -5,11 +5,20 @@ import java.util.List;
int x();
}
class TypeUseAnnotations {
+ class Inner {
+ Inner() {
+ super();
+ }
+ }
@lombok.Getter List<@TA(x = 5) String> foo;
+ @lombok.Getter List bar;
TypeUseAnnotations() {
super();
}
public @java.lang.SuppressWarnings("all") List<@TA(x = 5) String> getFoo() {
return this.foo;
}
+ public @java.lang.SuppressWarnings("all") List getBar() {
+ return this.bar;
+ }
}
\ No newline at end of file
diff --git a/test/transform/resource/before/TypeUseAnnotations.java b/test/transform/resource/before/TypeUseAnnotations.java
index c09a291d..7175930f 100644
--- a/test/transform/resource/before/TypeUseAnnotations.java
+++ b/test/transform/resource/before/TypeUseAnnotations.java
@@ -8,4 +8,6 @@ import java.util.List;
}
class TypeUseAnnotations {
@lombok.Getter List<@TA(x=5) String> foo;
+ @lombok.Getter List bar;
+ class Inner { }
}
From dede79bc224eb16566a027f83214c04e065b575b Mon Sep 17 00:00:00 2001
From: Jan Rieke
Date: Mon, 6 Apr 2020 21:43:58 +0200
Subject: [PATCH 06/87] copy more Jackson annotation to the builder, also for
@Singular methods
---
.../lombok/core/handlers/HandlerUtil.java | 9 +-
.../eclipse/handlers/EclipseHandlerUtil.java | 37 +++-
.../singulars/EclipseGuavaSingularizer.java | 12 +-
.../EclipseJavaUtilListSetSingularizer.java | 12 +-
.../EclipseJavaUtilMapSingularizer.java | 8 +-
.../javac/handlers/HandleJacksonized.java | 1 -
.../javac/handlers/JavacHandlerUtil.java | 18 +-
.../javac/handlers/JavacSingularsRecipes.java | 16 +-
.../jackson/annotation/JsonAnySetter.java | 12 ++
.../JacksonBuilderSingular.java | 177 ++++++++++++++++++
.../after-ecj/JacksonBuilderSingular.java | 164 ++++++++++++++++
.../before/JacksonBuilderSingular.java | 31 +++
12 files changed, 476 insertions(+), 21 deletions(-)
create mode 100644 test/stubs/com/fasterxml/jackson/annotation/JsonAnySetter.java
create mode 100644 test/transform/resource/after-delombok/JacksonBuilderSingular.java
create mode 100644 test/transform/resource/after-ecj/JacksonBuilderSingular.java
create mode 100644 test/transform/resource/before/JacksonBuilderSingular.java
diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java
index 94fd21d9..a8d56041 100644
--- a/src/core/lombok/core/handlers/HandlerUtil.java
+++ b/src/core/lombok/core/handlers/HandlerUtil.java
@@ -76,7 +76,7 @@ public class HandlerUtil {
return 43;
}
- public static final List NONNULL_ANNOTATIONS, BASE_COPYABLE_ANNOTATIONS, COPY_TO_SETTER_ANNOTATIONS, JACKSON_COPY_TO_BUILDER_ANNOTATIONS;
+ public static final List NONNULL_ANNOTATIONS, BASE_COPYABLE_ANNOTATIONS, COPY_TO_SETTER_ANNOTATIONS, COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS, JACKSON_COPY_TO_BUILDER_ANNOTATIONS;
static {
NONNULL_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {
"androidx.annotation.NonNull",
@@ -314,6 +314,13 @@ public class HandlerUtil {
COPY_TO_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {
"com.fasterxml.jackson.annotation.JsonProperty",
"com.fasterxml.jackson.annotation.JsonSetter",
+ "com.fasterxml.jackson.annotation.JsonDeserialize",
+ "com.fasterxml.jackson.annotation.JsonIgnore",
+ "com.fasterxml.jackson.annotation.JacksonInject",
+ "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty",
+ }));
+ COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {
+ "com.fasterxml.jackson.annotation.JsonAnySetter",
}));
JACKSON_COPY_TO_BUILDER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {
"com.fasterxml.jackson.annotation.JsonFormat",
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
index 4df7a90b..d066dc0f 100644
--- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
+++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
@@ -26,6 +26,7 @@ import static lombok.eclipse.Eclipse.*;
import static lombok.eclipse.EclipseAugments.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.EclipseReflectiveMembers.*;
+import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -817,6 +818,20 @@ public class EclipseHandlerUtil {
* Searches the given field node for annotations that are specifically intentioned to be copied to the setter.
*/
public static Annotation[] findCopyableToSetterAnnotations(EclipseNode node) {
+ return findAnnotationsInList(node, COPY_TO_SETTER_ANNOTATIONS);
+ }
+
+ /**
+ * Searches the given field node for annotations that are specifically intentioned to be copied to the builder's singular method.
+ */
+ public static Annotation[] findCopyableToBuilderSingularSetterAnnotations(EclipseNode node) {
+ return findAnnotationsInList(node, COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS);
+ }
+
+ /**
+ * Searches the given field node for annotations that are in the given list, and returns those.
+ */
+ private static Annotation[] findAnnotationsInList(EclipseNode node, java.util.List annotationsToFind) {
AbstractVariableDeclaration avd = (AbstractVariableDeclaration) node.get();
if (avd.annotations == null) return EMPTY_ANNOTATIONS_ARRAY;
List result = new ArrayList();
@@ -824,7 +839,7 @@ public class EclipseHandlerUtil {
for (Annotation annotation : avd.annotations) {
TypeReference typeRef = annotation.type;
if (typeRef != null && typeRef.getTypeName() != null) {
- for (String bn : COPY_TO_SETTER_ANNOTATIONS) if (typeMatches(bn, node, typeRef)) {
+ for (String bn : annotationsToFind) if (typeMatches(bn, node, typeRef)) {
result.add(annotation);
break;
}
@@ -2418,6 +2433,26 @@ public class EclipseHandlerUtil {
return array == null ? null : array.clone();
}
+ public static T[] concat(T[] first, T[] second, Class type) {
+ if (first == null)
+ return second;
+ if (second == null)
+ return first;
+ if (first.length == 0)
+ return second;
+ if (second.length == 0)
+ return first;
+ T[] result = newArray(type, first.length + second.length);
+ System.arraycopy(first, 0, result, 0, first.length);
+ System.arraycopy(second, 0, result, first.length, second.length);
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static T[] newArray(Class type, int length) {
+ return (T[]) Array.newInstance(type, length);
+ }
+
public static boolean isDirectDescendantOfObject(EclipseNode typeNode) {
if (!(typeNode.get() instanceof TypeDeclaration)) throw new IllegalArgumentException("not a type node");
TypeDeclaration typeDecl = (TypeDeclaration) typeNode.get();
diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java
index 392418ff..395d2e59 100755
--- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java
+++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java
@@ -175,8 +175,10 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer {
md.returnType = returnType;
char[] prefixedSingularName = data.getSetterPrefix().length == 0 ? data.getSingularName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getSingularName())).toCharArray();
md.selector = fluent ? prefixedSingularName : HandlerUtil.buildAccessorName("add", new String(data.getSingularName())).toCharArray();
- md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource());
-
+ Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource());
+ Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToBuilderSingularSetterAnnotations(data.getAnnotation().up()));
+ md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class);
+
if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md);
data.setGeneratedByRecursive(md);
HandleNonNull.INSTANCE.fix(injectMethod(builderType, md));
@@ -213,8 +215,10 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer {
md.returnType = returnType;
char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray();
md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName("addAll", new String(data.getPluralName())).toCharArray();
- md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource());
-
+ Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource());
+ Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up()));
+ md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class);
+
if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md);
data.setGeneratedByRecursive(md);
injectMethod(builderType, md);
diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java
index 375f4e2c..deab4530 100755
--- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java
+++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java
@@ -153,8 +153,10 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula
md.returnType = returnType;
char[] prefixedSingularName = data.getSetterPrefix().length == 0 ? data.getSingularName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getSingularName())).toCharArray();
md.selector = fluent ? prefixedSingularName : HandlerUtil.buildAccessorName("add", new String(data.getSingularName())).toCharArray();
- md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource());
-
+ Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource());
+ Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToBuilderSingularSetterAnnotations(data.getAnnotation().up()));
+ md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class);
+
if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md);
data.setGeneratedByRecursive(md);
HandleNonNull.INSTANCE.fix(injectMethod(builderType, md));
@@ -189,8 +191,10 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula
md.returnType = returnType;
char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray();
md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName("addAll", new String(data.getPluralName())).toCharArray();
- md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource());
-
+ Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource());
+ Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up()));
+ md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class);
+
if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md);
data.setGeneratedByRecursive(md);
injectMethod(builderType, md);
diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java
index cb7d9ed6..1a40369d 100755
--- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java
+++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java
@@ -252,7 +252,9 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer
String setterName = HandlerUtil.buildAccessorName(setterPrefix, name);
md.selector = setterName.toCharArray();
- md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource());
+ Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource());
+ Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToBuilderSingularSetterAnnotations(data.getAnnotation().up()));
+ md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class);
if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md);
data.setGeneratedByRecursive(md);
@@ -326,7 +328,9 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer
String setterName = HandlerUtil.buildAccessorName(setterPrefix, name);
md.selector = setterName.toCharArray();
- md.annotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource());
+ Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, cfv, data.getSource());
+ Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up()));
+ md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class);
if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md);
data.setGeneratedByRecursive(md);
diff --git a/src/core/lombok/javac/handlers/HandleJacksonized.java b/src/core/lombok/javac/handlers/HandleJacksonized.java
index aff0bf63..0aa02d1b 100644
--- a/src/core/lombok/javac/handlers/HandleJacksonized.java
+++ b/src/core/lombok/javac/handlers/HandleJacksonized.java
@@ -149,7 +149,6 @@ public class HandleJacksonized extends JavacAnnotationHandler {
// @SuperBuilder? Make it package-private!
if (superBuilderAnnotationNode != null)
builderClass.mods.flags = builderClass.mods.flags & ~Flags.PRIVATE;
-
}
private String getBuilderClassName(JCAnnotation ast, JavacNode annotationNode, JavacNode annotatedNode, JCClassDecl td, AnnotationValues builderAnnotation, JavacTreeMaker maker) {
diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
index a3e876c4..5241a209 100644
--- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java
+++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java
@@ -1520,6 +1520,20 @@ public class JavacHandlerUtil {
* Searches the given field node for annotations that are specifically intentioned to be copied to the setter.
*/
public static List findCopyableToSetterAnnotations(JavacNode node) {
+ return findAnnotationsInList(node, COPY_TO_SETTER_ANNOTATIONS);
+ }
+
+ /**
+ * Searches the given field node for annotations that are specifically intentioned to be copied to the builder's singular method.
+ */
+ public static List findCopyableToBuilderSingularSetterAnnotations(JavacNode node) {
+ return findAnnotationsInList(node, COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS);
+ }
+
+ /**
+ * Searches the given field node for annotations that are in the given list, and returns those.
+ */
+ private static List findAnnotationsInList(JavacNode node, java.util.List annotationsToFind) {
JCAnnotation anno = null;
String annoName = null;
for (JavacNode child : node.down()) {
@@ -1537,7 +1551,7 @@ public class JavacHandlerUtil {
if (annoName == null) return List.nil();
if (!annoName.isEmpty()) {
- for (String bn : COPY_TO_SETTER_ANNOTATIONS) if (typeMatches(bn, node, anno.annotationType)) return List.of(anno);
+ for (String bn : annotationsToFind) if (typeMatches(bn, node, anno.annotationType)) return List.of(anno);
}
ListBuffer result = new ListBuffer();
@@ -1545,7 +1559,7 @@ public class JavacHandlerUtil {
if (child.getKind() == Kind.ANNOTATION) {
JCAnnotation annotation = (JCAnnotation) child.get();
boolean match = false;
- if (!match) for (String bn : COPY_TO_SETTER_ANNOTATIONS) if (typeMatches(bn, node, annotation.annotationType)) {
+ if (!match) for (String bn : annotationsToFind) if (typeMatches(bn, node, annotation.annotationType)) {
result.append(annotation);
break;
}
diff --git a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java
index ba052b5a..7cd52c8c 100644
--- a/src/core/lombok/javac/handlers/JavacSingularsRecipes.java
+++ b/src/core/lombok/javac/handlers/JavacSingularsRecipes.java
@@ -182,11 +182,12 @@ public class JavacSingularsRecipes {
return this;
}
- protected JCModifiers makeMods(JavacTreeMaker maker, CheckerFrameworkVersion cfv, JavacNode node, boolean deprecate, AccessLevel access) {
+ protected JCModifiers makeMods(JavacTreeMaker maker, CheckerFrameworkVersion cfv, JavacNode node, boolean deprecate, AccessLevel access, List methodAnnotations) {
JCAnnotation deprecateAnn = deprecate ? maker.Annotation(genJavaLangTypeRef(node, "Deprecated"), List.nil()) : null;
JCAnnotation rrAnn = cfv.generateReturnsReceiver() ? maker.Annotation(genTypeRef(node, CheckerFrameworkVersion.NAME__RETURNS_RECEIVER), List.nil()) : null;
List annsOnMethod = (deprecateAnn != null && rrAnn != null) ? List.of(deprecateAnn, rrAnn) : deprecateAnn != null ? List.of(deprecateAnn) : rrAnn != null ? List.of(rrAnn) : List.nil();
+ annsOnMethod = mergeAnnotations(annsOnMethod,methodAnnotations);
return maker.Modifiers(toJavacModifier(access), annsOnMethod);
}
@@ -271,10 +272,10 @@ public class JavacSingularsRecipes {
generateClearMethod(cfv, deprecate, maker, returnTypeMaker.make(), returnStatementMaker.make(), data, builderType, source, access);
}
- private void finishAndInjectMethod(CheckerFrameworkVersion cfv, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean deprecate, ListBuffer statements, Name methodName, List jcVariableDecls, AccessLevel access, Boolean ignoreNullCollections) {
+ private void finishAndInjectMethod(CheckerFrameworkVersion cfv, JavacTreeMaker maker, JCExpression returnType, JCStatement returnStatement, SingularData data, JavacNode builderType, JCTree source, boolean deprecate, ListBuffer statements, Name methodName, List jcVariableDecls, List methodAnnotations, AccessLevel access, Boolean ignoreNullCollections) {
if (returnStatement != null) statements.append(returnStatement);
JCBlock body = maker.Block(0, statements.toList());
- JCModifiers mods = makeMods(maker, cfv, builderType, deprecate, access);
+ JCModifiers mods = makeMods(maker, cfv, builderType, deprecate, access, methodAnnotations);
List typeParams = List.nil();
List thrown = List.nil();
@@ -298,7 +299,7 @@ public class JavacSingularsRecipes {
statements.add(clearStatement);
Name methodName = builderType.toName(HandlerUtil.buildAccessorName("clear", data.getPluralName().toString()));
- finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, methodName, List.nil(), access, null);
+ finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, methodName, List.nil(), List.nil(), access, null);
}
protected abstract JCStatement generateClearStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType);
@@ -312,7 +313,8 @@ public class JavacSingularsRecipes {
if (!setterPrefix.isEmpty()) name = builderType.toName(HandlerUtil.buildAccessorName(setterPrefix, name.toString()));
statements.prepend(createConstructBuilderVarIfNeeded(maker, data, builderType, source));
- finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, params, access, null);
+ List methodAnnotations = copyAnnotations(findCopyableToBuilderSingularSetterAnnotations(data.annotation.up()));
+ finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, params, methodAnnotations, access, null);
}
protected JCVariableDecl generateSingularMethodParameter(int typeIndex, JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source, Name name) {
@@ -357,8 +359,10 @@ public class JavacSingularsRecipes {
} else {
statements.prepend(JavacHandlerUtil.generateNullCheck(maker, null, data.getPluralName(), builderType, "%s cannot be null"));
}
+
+ List methodAnnotations = copyAnnotations(findCopyableToSetterAnnotations(data.annotation.up()));
- finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, List.of(param), access, ignoreNullCollections);
+ finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, List.of(param), methodAnnotations, access, ignoreNullCollections);
}
protected ListBuffer generatePluralMethodStatements(JavacTreeMaker maker, SingularData data, JavacNode builderType, JCTree source) {
diff --git a/test/stubs/com/fasterxml/jackson/annotation/JsonAnySetter.java b/test/stubs/com/fasterxml/jackson/annotation/JsonAnySetter.java
new file mode 100644
index 00000000..51d2c3fa
--- /dev/null
+++ b/test/stubs/com/fasterxml/jackson/annotation/JsonAnySetter.java
@@ -0,0 +1,12 @@
+package com.fasterxml.jackson.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface JsonAnySetter {
+ boolean enabled() default true;
+}
diff --git a/test/transform/resource/after-delombok/JacksonBuilderSingular.java b/test/transform/resource/after-delombok/JacksonBuilderSingular.java
new file mode 100644
index 00000000..feaa6832
--- /dev/null
+++ b/test/transform/resource/after-delombok/JacksonBuilderSingular.java
@@ -0,0 +1,177 @@
+import java.util.List;
+import java.util.Map;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+@com.fasterxml.jackson.databind.annotation.JsonDeserialize(builder = JacksonBuilderSingular.JacksonBuilderSingularBuilder.class)
+public class JacksonBuilderSingular {
+ @JsonAnySetter
+ private Map any;
+ @JsonProperty("v_a_l_u_e_s")
+ private List values;
+ @JsonAnySetter
+ private ImmutableMap guavaAny;
+ @JsonProperty("guava_v_a_l_u_e_s")
+ private ImmutableList guavaValues;
+ @java.lang.SuppressWarnings("all")
+ JacksonBuilderSingular(final Map any, final List values, final ImmutableMap guavaAny, final ImmutableList guavaValues) {
+ this.any = any;
+ this.values = values;
+ this.guavaAny = guavaAny;
+ this.guavaValues = guavaValues;
+ }
+ @java.lang.SuppressWarnings("all")
+ @com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "", buildMethodName = "build")
+ public static class JacksonBuilderSingularBuilder {
+ @java.lang.SuppressWarnings("all")
+ private java.util.ArrayList any$key;
+ @java.lang.SuppressWarnings("all")
+ private java.util.ArrayList
@SuperBuilder's toBuilder feature and limited support for customization was added with lombok v1.18.4.
+
+ @SuperBuilder customization possibilities were extended with lombok v1.18.14.
@f.history>
@@ -13,7 +15,7 @@
The @SuperBuilder annotation produces complex builder APIs for your classes.
In contrast to @Builder, @SuperBuilder also works with fields from superclasses.
- However, it only works for types, and customization possibilities are limited.
+ However, it only works for types.
Most importantly, it requires that all superclasses also have the @SuperBuilder annotation.
@SuperBuilder lets you automatically produce the code required to have your class be instantiable with code such as:
@@ -21,7 +23,7 @@
- @SuperBuilder generates a private constructor on the class that takes a builder instance as a parameter. This constructor sets the fields of the new instance to the values from the builder.
+ @SuperBuilder generates a protected constructor on the class that takes a builder instance as a parameter. This constructor sets the fields of the new instance to the values from the builder.
@SuperBuilder is not compatible with @Builder.
@@ -32,8 +34,9 @@
To ensure type-safety, @SuperBuilder generates two inner builder classes for each annotated class, one abstract and one concrete class named FoobarBuilder and FoobarBuilderImpl (where Foobar is the name of the annotated class).
- Customizing the code generated by @SuperBuilder is limited to adding new methods or annotations to the builder classes, and providing custom implementations of the 'set', builder(), and build() methods.
- You have to make sure that the builder class declaration headers match those that would have been generated by lombok. Due to the heavy generics usage, we strongly advice to copy the builder class definition header from the uncustomized delomboked code.
+ You can customize most of the code generated by @SuperBuilder, except for internal methods (e.g. self()).
+ You have to make sure that the builder class declaration headers match those that would have been generated by lombok.
+ Due to the heavy generics usage, we strongly advice to take the uncustomized delomboked code as a reference when customizing @SuperBuilder.