diff options
author | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2019-05-07 00:08:49 +0200 |
---|---|---|
committer | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2019-05-07 00:08:49 +0200 |
commit | 42f36e66fec9554205ed7caaab33c1c7be0db90b (patch) | |
tree | a0b1034dbbec38cc2326ae32741dafe5e3efba4b /src | |
parent | e69a991fcb141fb24de8afb433c753d35821b1c3 (diff) | |
download | lombok-42f36e66fec9554205ed7caaab33c1c7be0db90b.tar.gz lombok-42f36e66fec9554205ed7caaab33c1c7be0db90b.tar.bz2 lombok-42f36e66fec9554205ed7caaab33c1c7be0db90b.zip |
[fixes #1981][fixes #1961] Hardcoded some knowledge about how to copy jackson’s `@JsonProperty`.
Diffstat (limited to 'src')
9 files changed, 105 insertions, 18 deletions
diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index 64d17cd9..6e28f65d 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<String> NONNULL_ANNOTATIONS, BASE_COPYABLE_ANNOTATIONS; + public static final List<String> NONNULL_ANNOTATIONS, BASE_COPYABLE_ANNOTATIONS, COPY_TO_SETTER_ANNOTATIONS; static { NONNULL_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] { "android.annotation.NonNull", @@ -92,7 +92,7 @@ public class HandlerUtil { "org.jetbrains.annotations.NotNull", "org.jmlspecs.annotation.NonNull", "org.netbeans.api.annotations.common.NonNull", - "org.springframework.lang.NonNull" + "org.springframework.lang.NonNull", })); BASE_COPYABLE_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] { "android.support.annotation.NonNull", @@ -298,8 +298,11 @@ public class HandlerUtil { "org.jetbrains.annotations.NotNull", "org.jetbrains.annotations.Nullable", "org.springframework.lang.NonNull", - "org.springframework.lang.Nullable" + "org.springframework.lang.Nullable", })); + COPY_TO_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] { + "com.fasterxml.jackson.annotation.JsonProperty", + })); } /** Checks if the given name is a valid identifier. diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index ddb2f198..c8e7b60a 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -649,6 +649,15 @@ public class EclipseHandlerUtil { return result == null ? null : result.toArray(new Annotation[0]); } + public static Annotation[] mergeAnnotations(Annotation[] a, Annotation[] b) { + if (a == null || a.length == 0) return (b == null || b.length == 0) ? null : b; + if (b == null || b.length == 0) return a.length == 0 ? null : a; + Annotation[] c = new Annotation[a.length + b.length]; + System.arraycopy(a, 0, c, 0, a.length); + System.arraycopy(b, 0, c, a.length, b.length); + return c; + } + public static boolean hasAnnotation(Class<? extends java.lang.annotation.Annotation> type, EclipseNode node) { if (node == null) return false; if (type == null) return false; @@ -766,6 +775,26 @@ 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) { + AbstractVariableDeclaration avd = (AbstractVariableDeclaration) node.get(); + if (avd.annotations == null) return EMPTY_ANNOTATIONS_ARRAY; + List<Annotation> result = new ArrayList<Annotation>(); + + 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)) { + result.add(annotation); + break; + } + } + } + return result.toArray(EMPTY_ANNOTATIONS_ARRAY); + } + + /** * Checks if the provided annotation type is likely to be the intended type for the given annotation node. * * This is a guess, but a decent one. diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index 4659e9a3..96431a83 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -476,7 +476,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { } for (BuilderFieldData bfd : builderFields) { - makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners); + makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain, accessForInners, bfd.originalFieldNode); } { @@ -802,16 +802,16 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { private static final AbstractMethodDeclaration[] EMPTY = {}; - public void makeSetterMethodsForBuilder(EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, boolean fluent, boolean chain, AccessLevel access) { + public void makeSetterMethodsForBuilder(EclipseNode builderType, BuilderFieldData bfd, EclipseNode sourceNode, boolean fluent, boolean chain, AccessLevel access, EclipseNode originalFieldNode) { boolean deprecate = isFieldDeprecated(bfd.originalFieldNode); if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) { - makeSimpleSetterMethodForBuilder(builderType, deprecate, bfd.createdFields.get(0), bfd.nameOfSetFlag, sourceNode, fluent, chain, bfd.annotations, access); + makeSimpleSetterMethodForBuilder(builderType, deprecate, bfd.createdFields.get(0), bfd.nameOfSetFlag, sourceNode, fluent, chain, bfd.annotations, access, originalFieldNode); } else { bfd.singularData.getSingularizer().generateMethods(bfd.singularData, deprecate, builderType, fluent, chain, access); } } - private void makeSimpleSetterMethodForBuilder(EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] nameOfSetFlag, EclipseNode sourceNode, boolean fluent, boolean chain, Annotation[] annotations, AccessLevel access) { + private void makeSimpleSetterMethodForBuilder(EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] nameOfSetFlag, EclipseNode sourceNode, boolean fluent, boolean chain, Annotation[] annotations, AccessLevel access, EclipseNode originalFieldNode) { TypeDeclaration td = (TypeDeclaration) builderType.get(); AbstractMethodDeclaration[] existing = td.methods; if (existing == null) existing = EMPTY; @@ -827,8 +827,11 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { String setterName = fluent ? fieldNode.getName() : HandlerUtil.buildAccessorName("set", fieldNode.getName()); + 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, nameOfSetFlag, chain, toEclipseModifier(access), - sourceNode, Collections.<Annotation>emptyList(), annotations != null ? Arrays.asList(copyAnnotations(sourceNode.get(), annotations)) : Collections.<Annotation>emptyList()); + sourceNode, methodAnnsList, annotations != null ? Arrays.asList(copyAnnotations(sourceNode.get(), annotations)) : Collections.<Annotation>emptyList()); injectMethod(builderType, setter); } diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index d70d4acd..4ea83cf6 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -220,7 +220,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { if (isFieldDeprecated(fieldNode) || deprecate) { deprecated = new Annotation[] { generateDeprecatedAnnotation(source) }; } - method.annotations = copyAnnotations(source, onMethod.toArray(new Annotation[0]), deprecated); + method.annotations = mergeAnnotations(copyAnnotations(source, onMethod.toArray(new Annotation[0]), deprecated), findCopyableToSetterAnnotations(fieldNode)); Argument param = new Argument(field.name, p, copyType(field.type, source), Modifier.FINAL); param.sourceStart = pS; param.sourceEnd = pE; method.arguments = new Argument[] { param }; diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 3a387688..9a86d372 100755 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -886,13 +886,13 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { }; if (bfd.singularData == null || bfd.singularData.getSingularizer() == null) { - generateSimpleSetterMethodForBuilder(builderType, deprecate, bfd.createdFields.get(0), bfd.nameOfSetFlag, returnTypeMaker.make(), returnStatementMaker.make(), sourceNode, bfd.annotations); + generateSimpleSetterMethodForBuilder(builderType, deprecate, bfd.createdFields.get(0), bfd.nameOfSetFlag, returnTypeMaker.make(), returnStatementMaker.make(), sourceNode, bfd.annotations, bfd.originalFieldNode); } else { bfd.singularData.getSingularizer().generateMethods(bfd.singularData, deprecate, builderType, true, returnTypeMaker, returnStatementMaker, AccessLevel.PUBLIC); } } - private void generateSimpleSetterMethodForBuilder(EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] nameOfSetFlag, TypeReference returnType, Statement returnStatement, EclipseNode sourceNode, Annotation[] annosOnParam) { + private void generateSimpleSetterMethodForBuilder(EclipseNode builderType, boolean deprecate, EclipseNode fieldNode, char[] nameOfSetFlag, TypeReference returnType, Statement returnStatement, EclipseNode sourceNode, Annotation[] annosOnParam, EclipseNode originalFieldNode) { TypeDeclaration td = (TypeDeclaration) builderType.get(); AbstractMethodDeclaration[] existing = td.methods; if (existing == null) existing = EMPTY_METHODS; @@ -908,8 +908,11 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { String setterName = fieldNode.getName(); + 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, nameOfSetFlag, returnType, returnStatement, ClassFileConstants.AccPublic, - sourceNode, Collections.<Annotation>emptyList(), annosOnParam != null ? Arrays.asList(copyAnnotations(sourceNode.get(), annosOnParam)) : Collections.<Annotation>emptyList()); + sourceNode, methodAnnsList, annosOnParam != null ? Arrays.asList(copyAnnotations(sourceNode.get(), annosOnParam)) : Collections.<Annotation>emptyList()); injectMethod(builderType, setter); } diff --git a/src/core/lombok/javac/handlers/HandleBuilder.java b/src/core/lombok/javac/handlers/HandleBuilder.java index 2eaba0fb..d758f602 100644 --- a/src/core/lombok/javac/handlers/HandleBuilder.java +++ b/src/core/lombok/javac/handlers/HandleBuilder.java @@ -750,10 +750,11 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> { JavacTreeMaker maker = fieldNode.getTreeMaker(); - JCMethodDecl newMethod = HandleSetter.createSetter(toJavacModifier(access), deprecate, fieldNode, maker, setterName, nameOfSetFlag, chain, source, List.<JCAnnotation>nil(), annosOnParam); + List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); + JCMethodDecl newMethod = HandleSetter.createSetter(toJavacModifier(access), deprecate, fieldNode, maker, setterName, nameOfSetFlag, chain, source, methodAnns, annosOnParam); recursiveSetGeneratedBy(newMethod, source.get(), builderType.getContext()); copyJavadoc(originalFieldNode, newMethod, CopyJavadoc.SETTER); - + injectMethod(builderType, newMethod); } diff --git a/src/core/lombok/javac/handlers/HandleSetter.java b/src/core/lombok/javac/handlers/HandleSetter.java index c661ab89..5482cccc 100644 --- a/src/core/lombok/javac/handlers/HandleSetter.java +++ b/src/core/lombok/javac/handlers/HandleSetter.java @@ -261,7 +261,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> { List<JCExpression> throwsClauses = List.nil(); JCExpression annotationMethodDefaultValue = null; - List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod); + List<JCAnnotation> annsOnMethod = mergeAnnotations(copyAnnotations(onMethod), findCopyableToSetterAnnotations(field)); if (isFieldDeprecated(field) || deprecate) { annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>nil())); } diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index 290ef89f..0fcaa5f8 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -861,13 +861,13 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { }}; if (fieldNode.singularData == null || fieldNode.singularData.getSingularizer() == null) { - generateSimpleSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.nameOfSetFlag, source, true, returnTypeMaker.make(), returnStatementMaker.make(), fieldNode.annotations); + generateSimpleSetterMethodForBuilder(builderType, deprecate, fieldNode.createdFields.get(0), fieldNode.nameOfSetFlag, source, true, returnTypeMaker.make(), returnStatementMaker.make(), fieldNode.annotations, fieldNode.originalFieldNode); } else { fieldNode.singularData.getSingularizer().generateMethods(fieldNode.singularData, deprecate, builderType, source.get(), true, returnTypeMaker, returnStatementMaker, AccessLevel.PUBLIC); } } - private void generateSimpleSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name nameOfSetFlag, JavacNode source, boolean fluent, JCExpression returnType, JCStatement returnStatement, List<JCAnnotation> annosOnParam) { + private void generateSimpleSetterMethodForBuilder(JavacNode builderType, boolean deprecate, JavacNode fieldNode, Name nameOfSetFlag, JavacNode source, boolean fluent, JCExpression returnType, JCStatement returnStatement, List<JCAnnotation> annosOnParam, JavacNode originalFieldNode) { Name fieldName = ((JCVariableDecl) fieldNode.get()).name; for (JavacNode child : builderType.down()) { @@ -881,7 +881,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> { JavacTreeMaker maker = fieldNode.getTreeMaker(); - JCMethodDecl newMethod = HandleSetter.createSetter(Flags.PUBLIC, deprecate, fieldNode, maker, setterName, nameOfSetFlag, returnType, returnStatement, source, List.<JCAnnotation>nil(), annosOnParam); + List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode); + JCMethodDecl newMethod = HandleSetter.createSetter(Flags.PUBLIC, deprecate, fieldNode, maker, setterName, nameOfSetFlag, returnType, returnStatement, source, methodAnns, annosOnParam); injectMethod(builderType, newMethod); } diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index e923c5c0..ee012d2b 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -1474,6 +1474,44 @@ public class JavacHandlerUtil { } /** + * Searches the given field node for annotations that are specifically intentioned to be copied to the setter. + */ + public static List<JCAnnotation> findCopyableToSetterAnnotations(JavacNode node) { + JCAnnotation anno = null; + String annoName = null; + for (JavacNode child : node.down()) { + if (child.getKind() == Kind.ANNOTATION) { + if (anno != null) { + annoName = ""; + break; + } + JCAnnotation annotation = (JCAnnotation) child.get(); + annoName = annotation.annotationType.toString(); + anno = annotation; + } + } + + 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); + } + + ListBuffer<JCAnnotation> result = new ListBuffer<JCAnnotation>(); + for (JavacNode child : node.down()) { + 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)) { + result.append(annotation); + break; + } + } + } + return result.toList(); + } + + /** * Generates a new statement that checks if the given variable is null, and if so, throws a configured exception with the * variable name as message. */ @@ -1713,6 +1751,15 @@ public class JavacHandlerUtil { return out.toList(); } + static List<JCAnnotation> mergeAnnotations(List<JCAnnotation> a, List<JCAnnotation> b) { + if (a == null || a.isEmpty()) return b; + if (b == null || b.isEmpty()) return a; + ListBuffer<JCAnnotation> out = new ListBuffer<JCAnnotation>(); + for (JCAnnotation ann : a) out.append(ann); + for (JCAnnotation ann : b) out.append(ann); + return out.toList(); + } + static boolean isClass(JavacNode typeNode) { return isClassAndDoesNotHaveFlags(typeNode, Flags.INTERFACE | Flags.ENUM | Flags.ANNOTATION); } |