mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-19 18:15:56 +00:00
Merge branch 'JR-jacksonisedAccessors'
# Conflicts: # doc/changelog.markdown
This commit is contained in:
36 files changed
+469
-247
No files matched your search
@@ -2,7 +2,8 @@ Lombok Changelog
|
||||
----------------
|
||||
|
||||
### v1.18.39 "Edgy Guinea Pig"
|
||||
* No changes since v1.18.38 yet.
|
||||
* FEATURE: `@Jacksonized @Accessors(fluent=true)` automatically creates the relevant annotations such that Jackson correctly identifies fluent accessors.
|
||||
* IMPROBABLE BREAKING CHANGE: From versions 1.18.16 to 1.18.38, lombok automatically copies certain Jackson annotations (e.g., `@JsonProperty`) from fields to the corresponding accessors (getters/setters). However, it turned out to be harmful in certain situations. Thus, Lombok does not automatically copy those annotations any more. You can restore the old behavior using the [config key](https://projectlombok.org/features/configuration) `lombok.copyJacksonAnnotationsToAccessors = true`.
|
||||
|
||||
### v1.18.38 (March 31st, 2025)
|
||||
* PLATFORM: JDK24 support added.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2018 The Project Lombok Authors.
|
||||
* Copyright (C) 2013-2025 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
|
||||
@@ -46,7 +46,7 @@ import java.lang.annotation.Target;
|
||||
* <p>
|
||||
* The <code><strong>T</strong>Builder</code> class contains 1 method for each parameter of the annotated
|
||||
* constructor / method (each field, when annotating a class), which returns the builder itself.
|
||||
* The builder also has a <code>build()</code> method which returns a completed instance of the original type,
|
||||
* The builder also has a {@code build()} method which returns a completed instance of the original type,
|
||||
* created by passing all parameters as set via the various other methods in the builder to the constructor
|
||||
* or method that was annotated with {@code @Builder}. The return type of this method will be the same
|
||||
* as the relevant class, unless a method has been annotated, in which case it'll be equal to the
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2023 The Project Lombok Authors.
|
||||
* Copyright (C) 2013-2025 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
|
||||
@@ -606,14 +606,14 @@ public class ConfigurationKeys {
|
||||
/**
|
||||
* lombok configuration: {@code lombok.fieldDefaults.defaultPrivate} = {@code true} | {@code false}.
|
||||
*
|
||||
* If set to <code>true</code> <em>any</em> field without an access modifier or {@code @PackagePrivate} is marked as {@code private} by lombok, in all source files compiled.
|
||||
* If set to {@code true} <em>any</em> field without an access modifier or {@code @PackagePrivate} is marked as {@code private} by lombok, in all source files compiled.
|
||||
*/
|
||||
public static final ConfigurationKey<Boolean> FIELD_DEFAULTS_PRIVATE_EVERYWHERE = new ConfigurationKey<Boolean>("lombok.fieldDefaults.defaultPrivate", "If true, fields without any access modifier, in any file (lombok annotated or not) are marked as private. Use @PackagePrivate or an explicit modifier to override this.") {};
|
||||
|
||||
/**
|
||||
* lombok configuration: {@code lombok.fieldDefaults.defaultFinal} = {@code true} | {@code false}.
|
||||
*
|
||||
* If set to <code>true</code> <em>any</em> field without {@code @NonFinal} is marked as {@code final} by lombok, in all source files compiled.
|
||||
* If set to {@code true} <em>any</em> field without {@code @NonFinal} is marked as {@code final} by lombok, in all source files compiled.
|
||||
*/
|
||||
public static final ConfigurationKey<Boolean> FIELD_DEFAULTS_FINAL_EVERYWHERE = new ConfigurationKey<Boolean>("lombok.fieldDefaults.defaultFinal", "If true, fields, in any file (lombok annotated or not) are marked as final. Use @NonFinal to override this.") {};
|
||||
|
||||
@@ -721,7 +721,7 @@ public class ConfigurationKeys {
|
||||
* If set to {@code true}, no further {@code lombok.config} files will be checked.
|
||||
*/
|
||||
public static final ConfigurationKey<Boolean> STOP_BUBBLING = new ConfigurationKey<Boolean>("config.stopBubbling", "Tell the configuration system it should stop looking for other configuration files (default: false).") {};
|
||||
|
||||
|
||||
/**
|
||||
* lombok configuration: {@code lombok.copyableAnnotations} += <TypeName: fully-qualified annotation class name>.
|
||||
*
|
||||
@@ -737,11 +737,19 @@ public class ConfigurationKeys {
|
||||
* checkerframework.org version will be generated.
|
||||
*/
|
||||
public static final ConfigurationKey<CheckerFrameworkVersion> CHECKER_FRAMEWORK = new ConfigurationKey<CheckerFrameworkVersion>("checkerframework", "If set with the version of checkerframework.org (in major.minor, or just 'true' for the latest supported version), create relevant checkerframework.org annotations for code lombok generates (default: false).") {};
|
||||
|
||||
|
||||
/**
|
||||
* lombok configuration: {@code lombok.standardException.flagUsage} = {@code WARNING} | {@code ERROR}.
|
||||
*
|
||||
* If set, <em>any</em> usage of {@code @StandardException} results in a warning / error.
|
||||
*/
|
||||
public static final ConfigurationKey<FlagUsageType> STANDARD_EXCEPTION_FLAG_USAGE = new ConfigurationKey<FlagUsageType>("lombok.standardException.flagUsage", "Emit a warning or error if @StandardException is used.") {};
|
||||
|
||||
/**
|
||||
* lombok configuration: {@code lombok.copyJacksonAnnotationsToAccessors} = {@code true} | {@code false}.
|
||||
*
|
||||
* If {@code true}, copy certain Jackson annotations from a field to its corresponding accessors (getter/setters). This was the behavior from lombok 1.18.16 to 1.18.38.
|
||||
* However, it turned out to be harmful in certain situations. Thus, the default is now {@code false}.
|
||||
*/
|
||||
public static final ConfigurationKey<Boolean> COPY_JACKSON_ANNOTATIONS_TO_ACCESSORS = new ConfigurationKey<Boolean>("lombok.copyJacksonAnnotationsToAccessors", "Copy Jackson annotations from fields to the corresponding getters and setters.") {};
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Project Lombok Authors.
|
||||
* Copyright (C) 2019-2025 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
|
||||
@@ -25,9 +25,9 @@ package lombok.core.configuration;
|
||||
* If a type used in {@link ConfigurationKey} type argument implements this interface,
|
||||
* it is expected to provide the following three static methods:
|
||||
* <ul>
|
||||
* <li><code>public static SELF valueOf(String value)</code>
|
||||
* <li><code>public static String description()</code>
|
||||
* <li><code>public static String exampleValue()</code>
|
||||
* <li><code>public static SELF valueOf(String value)</code></li>
|
||||
* <li><code>public static String description()</code></li>
|
||||
* <li><code>public static String exampleValue()</code></li>
|
||||
* </ul>
|
||||
* None of them should throw checked exceptions.
|
||||
* Based on these methods, an instance of {@link ConfigurationValueParser} is created
|
||||
|
||||
@@ -79,7 +79,7 @@ public class HandlerUtil {
|
||||
return 43;
|
||||
}
|
||||
|
||||
public static final List<String> NONNULL_ANNOTATIONS, BASE_COPYABLE_ANNOTATIONS, COPY_TO_SETTER_ANNOTATIONS, COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS, JACKSON_COPY_TO_BUILDER_ANNOTATIONS;
|
||||
public static final List<String> NONNULL_ANNOTATIONS, BASE_COPYABLE_ANNOTATIONS, JACKSON_COPY_TO_GETTER_ANNOTATIONS, JACKSON_COPY_TO_SETTER_ANNOTATIONS, JACKSON_COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS, JACKSON_COPY_TO_BUILDER_ANNOTATIONS;
|
||||
static {
|
||||
// This is a list of annotations with a __highly specific meaning__: All annotations in this list indicate that passing null for the relevant item is __never__ acceptable, regardless of settings or circumstance.
|
||||
// In other words, things like 'this models a database table, and the db table column has a nonnull constraint', or 'this represents a web form, and if this is null, the form is invalid' __do not count__ and should not be in this list;
|
||||
@@ -424,7 +424,37 @@ public class HandlerUtil {
|
||||
"org.checkerframework.common.value.qual.UnknownVal",
|
||||
"org.checkerframework.framework.qual.PurityUnqualified",
|
||||
}));
|
||||
COPY_TO_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {
|
||||
|
||||
// The following two lists contain all annotations that can be copied from the field to the getter or setter.
|
||||
// Right now, it only contains Jackson annotations.
|
||||
// Jackson's annotation processing roughly works as follows: To calculate the annotation for a JSON property, Jackson
|
||||
// builds a triple of the Java field and the corresponding setter and getter methods. It is sufficient for an annotation
|
||||
// to be present on one of those to become effective. E.g., a @JsonIgnore on a setter completely ignores the JSON property,
|
||||
// not only during deserialization, but also when serializing. Therefore, in most cases it is _not_ necessary to copy the
|
||||
// annotations. It may even harm, as Jackson considers some annotations inheritable, and this "virtual inheritance" only
|
||||
// affects annotations on setter/getter, but not on private fields.
|
||||
// However, there are two exceptions where we have to copy the annotations:
|
||||
// 1. When using a builder to deserialize, Jackson does _not_ "propagate" the annotations to the setter methods of the
|
||||
// builder, i.e. annotations like @JsonIgnore on the field will not be respected when deserializing with a builder.
|
||||
// Thus, those annotations should be copied to the builder's setters.
|
||||
// 2. If the getter/setter methods do not follow the exact beanspec naming strategy, Jackson will not correctly detect the
|
||||
// field-getter-setter triple, and annotations may not work as intended.
|
||||
// However, we cannot always know what the user's intention is. Thus, lombok should only fix those cases where it is
|
||||
// obvious what the user wants. That is the case for a `@Jacksonized @Accessors(fluent=true)`.
|
||||
JACKSON_COPY_TO_GETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {
|
||||
"com.fasterxml.jackson.annotation.JsonFormat",
|
||||
"com.fasterxml.jackson.annotation.JsonIgnore",
|
||||
"com.fasterxml.jackson.annotation.JsonIgnoreProperties",
|
||||
"com.fasterxml.jackson.annotation.JsonProperty",
|
||||
"com.fasterxml.jackson.annotation.JsonSubTypes",
|
||||
"com.fasterxml.jackson.annotation.JsonTypeInfo",
|
||||
"com.fasterxml.jackson.annotation.JsonUnwrapped",
|
||||
"com.fasterxml.jackson.annotation.JsonView",
|
||||
"com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper",
|
||||
"com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty",
|
||||
"com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText",
|
||||
}));
|
||||
JACKSON_COPY_TO_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {
|
||||
"com.fasterxml.jackson.annotation.JacksonInject",
|
||||
"com.fasterxml.jackson.annotation.JsonAlias",
|
||||
"com.fasterxml.jackson.annotation.JsonFormat",
|
||||
@@ -441,9 +471,11 @@ public class HandlerUtil {
|
||||
"com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty",
|
||||
"com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText",
|
||||
}));
|
||||
COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {
|
||||
JACKSON_COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {
|
||||
"com.fasterxml.jackson.annotation.JsonAnySetter",
|
||||
}));
|
||||
// In order to let Jackson recognize certain configuration annotations when deserializing using a builder, those must
|
||||
// be copied to the generated builder class.
|
||||
JACKSON_COPY_TO_BUILDER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {
|
||||
"com.fasterxml.jackson.annotation.JsonAutoDetect",
|
||||
"com.fasterxml.jackson.annotation.JsonFormat",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2023 The Project Lombok Authors.
|
||||
* Copyright (C) 2009-2025 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
|
||||
@@ -129,14 +129,14 @@ public class TransformEclipseAST {
|
||||
|
||||
/**
|
||||
* Check if lombok already handled the given AST. This method will return
|
||||
* <code>true</code> once for diet mode and once for full mode.
|
||||
* {@code true} once for diet mode and once for full mode.
|
||||
*
|
||||
* The reason for this is that Eclipse invokes the transform method multiple
|
||||
* times during compilation and it is enough to transform it once and not
|
||||
* repeat the whole thing over and over again.
|
||||
*
|
||||
* @param ast The AST node belonging to the compilation unit (java speak for a single source file).
|
||||
* @return <code>true</code> if this AST was already handled by lombok.
|
||||
* @return {@code true} if this AST was already handled by lombok.
|
||||
*/
|
||||
public static boolean alreadyTransformed(CompilationUnitDeclaration ast) {
|
||||
TransformationState state = CompilationUnitDeclaration_transformationState.get(ast);
|
||||
|
||||
@@ -820,17 +820,36 @@ public class EclipseHandlerUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the given field node for annotations that are specifically intentioned to be copied to the setter.
|
||||
* Searches the given field node for annotations that are specifically intended to be copied to the getter.
|
||||
*
|
||||
* @param forceCopyJacksonAnnotations If {@code true}, always copy the annotations regardless of regardless of lombok configuration key {@code lombok.copyJacksonAnnotationsToAccessors}.
|
||||
*/
|
||||
public static Annotation[] findCopyableToSetterAnnotations(EclipseNode node) {
|
||||
return findAnnotationsInList(node, COPY_TO_SETTER_ANNOTATIONS);
|
||||
public static Annotation[] findCopyableToGetterAnnotations(EclipseNode node, boolean forceCopyJacksonAnnotations) {
|
||||
if (!forceCopyJacksonAnnotations) {
|
||||
Boolean copyAnnotations = node.getAst().readConfiguration(ConfigurationKeys.COPY_JACKSON_ANNOTATIONS_TO_ACCESSORS);
|
||||
if (copyAnnotations == null || !copyAnnotations) return EMPTY_ANNOTATIONS_ARRAY;
|
||||
}
|
||||
return findAnnotationsInList(node, JACKSON_COPY_TO_GETTER_ANNOTATIONS);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Searches the given field node for annotations that are specifically intentioned to be copied to the builder's singular method.
|
||||
* Searches the given field node for annotations that are specifically intended to be copied to the setter.
|
||||
*
|
||||
* @param forceCopyJacksonAnnotations If {@code true}, always copy the annotations regardless of regardless of lombok configuration key {@code lombok.copyJacksonAnnotationsToAccessors}.
|
||||
*/
|
||||
public static Annotation[] findCopyableToSetterAnnotations(EclipseNode node, boolean forceCopyJacksonAnnotations) {
|
||||
if (!forceCopyJacksonAnnotations) {
|
||||
Boolean copyAnnotations = node.getAst().readConfiguration(ConfigurationKeys.COPY_JACKSON_ANNOTATIONS_TO_ACCESSORS);
|
||||
if (copyAnnotations == null || !copyAnnotations) return EMPTY_ANNOTATIONS_ARRAY;
|
||||
}
|
||||
return findAnnotationsInList(node, JACKSON_COPY_TO_SETTER_ANNOTATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the given field node for annotations that are specifically intended to be copied to the builder's singular method.
|
||||
*/
|
||||
public static Annotation[] findCopyableToBuilderSingularSetterAnnotations(EclipseNode node) {
|
||||
return findAnnotationsInList(node, COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS);
|
||||
return findAnnotationsInList(node, JACKSON_COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2021 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-2025 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
|
||||
@@ -422,7 +422,7 @@ public class EclipseSingularsRecipes {
|
||||
return new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, NULL_POSS);
|
||||
}
|
||||
|
||||
/** @return a {@code SingleNameReference} to the builder in the variable <code>builderVariable</code>. If {@ code builderVariable == "this"}, a {@code ThisReference} is returned. */
|
||||
/** @return a {@code SingleNameReference} to the builder in the variable {@code builderVariable}. If {@code builderVariable == "this"}, a {@code ThisReference} is returned. */
|
||||
protected static Reference getBuilderReference(String builderVariable) {
|
||||
if ("this".equals(builderVariable)) {
|
||||
return new ThisReference(0, 0);
|
||||
|
||||
@@ -1042,7 +1042,7 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> {
|
||||
}
|
||||
|
||||
List<Annotation> methodAnnsList = Collections.<Annotation>emptyList();
|
||||
Annotation[] methodAnns = EclipseHandlerUtil.findCopyableToSetterAnnotations(bfd.originalFieldNode);
|
||||
Annotation[] methodAnns = EclipseHandlerUtil.findCopyableToSetterAnnotations(bfd.originalFieldNode, true);
|
||||
if (methodAnns != null && methodAnns.length > 0) methodAnnsList = Arrays.asList(methodAnns);
|
||||
ASTNode source = job.sourceNode.get();
|
||||
MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, bfd.name, bfd.nameOfSetFlag, job.oldChain, toEclipseModifier(job.accessInners),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2024 The Project Lombok Authors.
|
||||
* Copyright (C) 2009-2025 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
|
||||
@@ -83,7 +83,7 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
|
||||
public class HandleGetter extends EclipseAnnotationHandler<Getter> {
|
||||
private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY = new Annotation[0];
|
||||
private static final String GETTER_NODE_NOT_SUPPORTED_ERR = "@Getter is only supported on a class, an enum, or a field.";
|
||||
|
||||
|
||||
public boolean generateGetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelGetter, List<Annotation> onMethod) {
|
||||
if (checkForTypeLevelGetter) {
|
||||
if (hasAnnotation(Getter.class, typeNode)) {
|
||||
@@ -279,9 +279,15 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> {
|
||||
if (getCheckerFrameworkVersion(fieldNode).generateSideEffectFree()) checkerFramework = new Annotation[] { generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE) };
|
||||
}
|
||||
|
||||
// Copying Jackson annotations is required for fluent accessors (otherwise Jackson would not find the accessor).
|
||||
boolean fluent = accessors.isExplicit("fluent");
|
||||
Boolean fluentConfig = fieldNode.getAst().readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT);
|
||||
if (fluentConfig != null && fluentConfig) fluent = fluentConfig;
|
||||
|
||||
method.annotations = copyAnnotations(source,
|
||||
onMethod.toArray(new Annotation[0]),
|
||||
findCopyableAnnotations(fieldNode),
|
||||
findCopyableToGetterAnnotations(fieldNode, fluent),
|
||||
findDelegatesAndMarkAsHandled(fieldNode),
|
||||
checkerFramework,
|
||||
deprecated);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2021 The Project Lombok Authors.
|
||||
* Copyright (C) 2020-2025 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
|
||||
@@ -31,6 +31,7 @@ import java.util.List;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
|
||||
import org.eclipse.jdt.internal.compiler.ast.Annotation;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
|
||||
@@ -47,6 +48,7 @@ import lombok.core.handlers.HandlerUtil;
|
||||
import lombok.eclipse.Eclipse;
|
||||
import lombok.eclipse.EclipseAnnotationHandler;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
import lombok.spi.Provides;
|
||||
@@ -62,23 +64,24 @@ public class HandleJacksonized extends EclipseAnnotationHandler<Jacksonized> {
|
||||
|
||||
private static final char[][] JSON_POJO_BUILDER_ANNOTATION = Eclipse.fromQualifiedName("com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder");
|
||||
private static final char[][] JSON_DESERIALIZE_ANNOTATION = Eclipse.fromQualifiedName("com.fasterxml.jackson.databind.annotation.JsonDeserialize");
|
||||
|
||||
private static final char[][] JSON_PROPERTY_ANNOTATION = Eclipse.fromQualifiedName("com.fasterxml.jackson.annotation.JsonProperty");
|
||||
|
||||
@Override public void handle(AnnotationValues<Jacksonized> annotation, Annotation ast, EclipseNode annotationNode) {
|
||||
handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.JACKSONIZED_FLAG_USAGE, "@Jacksonized");
|
||||
|
||||
|
||||
EclipseNode annotatedNode = annotationNode.up();
|
||||
|
||||
EclipseNode tdNode;
|
||||
if (annotatedNode.getKind() != Kind.TYPE)
|
||||
tdNode = annotatedNode.up(); // @Jacksonized on a constructor or a static factory method.
|
||||
else
|
||||
tdNode = annotatedNode; // @Jacksonized on the class.
|
||||
if (annotatedNode.getKind() != Kind.TYPE) tdNode = annotatedNode.up(); // @Jacksonized on a constructor or a static factory method.
|
||||
else tdNode = annotatedNode; // @Jacksonized on the class.
|
||||
TypeDeclaration td = (TypeDeclaration) tdNode.get();
|
||||
|
||||
EclipseNode builderAnnotationNode = findAnnotation(Builder.class, annotatedNode);
|
||||
EclipseNode superBuilderAnnotationNode = findAnnotation(SuperBuilder.class, annotatedNode);
|
||||
if (builderAnnotationNode == null && superBuilderAnnotationNode == null) {
|
||||
annotationNode.addWarning("@Jacksonized requires @Builder or @SuperBuilder for it to mean anything.");
|
||||
EclipseNode accessorsAnnotationNode = (annotatedNode.getKind() == Kind.TYPE) ? findAnnotation(Accessors.class, annotatedNode) : null;
|
||||
|
||||
if (builderAnnotationNode == null && superBuilderAnnotationNode == null && accessorsAnnotationNode == null) {
|
||||
annotationNode.addWarning("@Jacksonized requires @Builder, @SuperBuilder, or @Accessors for it to mean anything.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -87,6 +90,17 @@ public class HandleJacksonized extends EclipseAnnotationHandler<Jacksonized> {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean jacksonizedBuilder = builderAnnotationNode != null || superBuilderAnnotationNode != null;
|
||||
if (jacksonizedBuilder) {
|
||||
handleJacksonizedBuilder(ast, annotationNode, annotatedNode, tdNode, td, builderAnnotationNode, superBuilderAnnotationNode);
|
||||
}
|
||||
|
||||
if (accessorsAnnotationNode != null) {
|
||||
handleJacksonizedAccessors(ast, annotationNode, annotatedNode, tdNode, td, accessorsAnnotationNode, jacksonizedBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleJacksonizedBuilder(Annotation ast, EclipseNode annotationNode, EclipseNode annotatedNode, EclipseNode tdNode, TypeDeclaration td, EclipseNode builderAnnotationNode, EclipseNode superBuilderAnnotationNode) {
|
||||
boolean isAbstract = (td.modifiers & ClassFileConstants.AccAbstract) != 0;
|
||||
if (isAbstract) {
|
||||
annotationNode.addError("Builders on abstract classes cannot be @Jacksonized (the builder would never be used).");
|
||||
@@ -144,14 +158,45 @@ public class HandleJacksonized extends EclipseAnnotationHandler<Jacksonized> {
|
||||
builderClass.modifiers = builderClass.modifiers & ~ClassFileConstants.AccPrivate;
|
||||
}
|
||||
|
||||
private void handleJacksonizedAccessors(Annotation ast, EclipseNode annotationNode, EclipseNode annotatedNode, EclipseNode tdNode, TypeDeclaration td, EclipseNode accessorsAnnotationNode, boolean jacksonizedBuilder) {
|
||||
AnnotationValues<Accessors> accessorsAnnotation = accessorsAnnotationNode != null ?
|
||||
createAnnotation(Accessors.class, accessorsAnnotationNode) : null;
|
||||
boolean fluent = accessorsAnnotation != null && accessorsAnnotation.getInstance().fluent();
|
||||
|
||||
if (!fluent) {
|
||||
// No changes required for chained-only accessors.
|
||||
if (!jacksonizedBuilder) {
|
||||
annotationNode.addWarning("@Jacksonized only affects fluent accessors (@Accessors(fluent=true)).");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Add @JsonProperty to all fields. It will be automatically copied to the getter/setters later.
|
||||
for (EclipseNode eclipseNode : tdNode.down()) {
|
||||
if (eclipseNode.getKind() == Kind.FIELD) {
|
||||
createJsonPropertyForField(eclipseNode, annotationNode);
|
||||
}
|
||||
}
|
||||
tdNode.rebuild();
|
||||
}
|
||||
|
||||
private void createJsonPropertyForField(EclipseNode fieldNode, EclipseNode annotationNode) {
|
||||
if (hasAnnotation("com.fasterxml.jackson.annotation.JsonProperty", fieldNode)) return;
|
||||
ASTNode astNode = fieldNode.get();
|
||||
if (astNode instanceof FieldDeclaration) {
|
||||
FieldDeclaration fd = (FieldDeclaration)astNode;
|
||||
StringLiteral fieldName = new StringLiteral(fd.name, 0, 0, 0);
|
||||
((FieldDeclaration) astNode).annotations = addAnnotation(fieldNode.get(), fd.annotations, JSON_PROPERTY_ANNOTATION, fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
private String getBuilderClassName(Annotation ast, EclipseNode annotationNode, EclipseNode annotatedNode, TypeDeclaration td, AnnotationValues<Builder> builderAnnotation) {
|
||||
String builderClassName = builderAnnotation != null ?
|
||||
builderAnnotation.getInstance().builderClassName() : null;
|
||||
if (builderClassName == null || builderClassName.isEmpty()) {
|
||||
builderClassName = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME);
|
||||
if (builderClassName == null || builderClassName.isEmpty())
|
||||
builderClassName = "*Builder";
|
||||
|
||||
if (builderClassName == null || builderClassName.isEmpty()) builderClassName = "*Builder";
|
||||
|
||||
MethodDeclaration fillParametersFrom = annotatedNode.get() instanceof MethodDeclaration ? (MethodDeclaration) annotatedNode.get() : null;
|
||||
char[] replacement;
|
||||
if (fillParametersFrom != null) {
|
||||
@@ -163,23 +208,22 @@ public class HandleJacksonized extends EclipseAnnotationHandler<Jacksonized> {
|
||||
}
|
||||
builderClassName = builderClassName.replace("*", new String(replacement));
|
||||
}
|
||||
|
||||
if (builderAnnotation == null)
|
||||
builderClassName += "Impl"; // For @SuperBuilder, all Jackson annotations must be put on the BuilderImpl class.
|
||||
|
||||
if (builderAnnotation == null) builderClassName += "Impl"; // For @SuperBuilder, all Jackson annotations must be put on the BuilderImpl class.
|
||||
|
||||
return builderClassName;
|
||||
}
|
||||
|
||||
private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY = new Annotation[0];
|
||||
|
||||
|
||||
private static Annotation[] findJacksonAnnotationsOnClass(TypeDeclaration td, EclipseNode node) {
|
||||
if (td.annotations == null) return EMPTY_ANNOTATIONS_ARRAY;
|
||||
|
||||
|
||||
List<Annotation> result = new ArrayList<Annotation>();
|
||||
for (Annotation annotation : td.annotations) {
|
||||
TypeReference typeRef = annotation.type;
|
||||
if (typeRef != null && typeRef.getTypeName() != null) {
|
||||
for (String bn : HandlerUtil.JACKSON_COPY_TO_BUILDER_ANNOTATIONS) {
|
||||
for (String bn : HandlerUtil.JACKSON_COPY_TO_BUILDER_ANNOTATIONS) {
|
||||
if (typeMatches(bn, node, typeRef)) {
|
||||
result.add(annotation);
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2024 The Project Lombok Authors.
|
||||
* Copyright (C) 2009-2025 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
|
||||
@@ -27,6 +27,7 @@ import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@@ -109,6 +110,14 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> {
|
||||
//The annotation will make it happen, so we can skip it.
|
||||
return;
|
||||
}
|
||||
|
||||
// If a fluent setter should be generated, force-copy annotations from the field.
|
||||
AnnotationValues<Accessors> accessorsForField = EclipseHandlerUtil.getAccessorsForField(fieldNode);
|
||||
// Copying Jackson annotations is required for fluent accessors (otherwise Jackson would not find the accessor).
|
||||
Annotation[] copyableToSetterAnnotations = findCopyableToSetterAnnotations(fieldNode, accessorsForField.isExplicit("fluent"));
|
||||
onMethod = new ArrayList<Annotation>(onMethod);
|
||||
onMethod.addAll(Arrays.asList(copyableToSetterAnnotations));
|
||||
|
||||
createSetterForField(level, fieldNode, sourceNode, false, onMethod, onParam);
|
||||
}
|
||||
|
||||
@@ -228,7 +237,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, findCopyableToSetterAnnotations(fieldNode));
|
||||
method.annotations = copyAnnotations(source, onMethod.toArray(new Annotation[0]), deprecated, findCopyableToSetterAnnotations(fieldNode, false));
|
||||
Argument param = new Argument(paramName, p, copyType(field.type, source), Modifier.FINAL);
|
||||
param.sourceStart = pS; param.sourceEnd = pE;
|
||||
method.arguments = new Argument[] { param };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2021 The Project Lombok Authors.
|
||||
* Copyright (C) 2013-2025 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
|
||||
@@ -162,13 +162,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
job.init(annotation, annInstance, annotationNode);
|
||||
|
||||
boolean generateBuilderMethod;
|
||||
if (job.builderMethodName.isEmpty()) {
|
||||
generateBuilderMethod = false;
|
||||
} else if (!checkName("builderMethodName", job.builderMethodName, annotationNode)) {
|
||||
return;
|
||||
} else {
|
||||
generateBuilderMethod = true;
|
||||
}
|
||||
if (job.builderMethodName.isEmpty()) generateBuilderMethod = false;
|
||||
else if (!checkName("builderMethodName", job.builderMethodName, annotationNode)) return;
|
||||
else generateBuilderMethod = true;
|
||||
|
||||
if (!checkName("buildMethodName", job.buildMethodName, annotationNode)) return;
|
||||
|
||||
@@ -343,9 +339,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
if (sd == null) continue;
|
||||
EclipseSingularizer singularizer = sd.getSingularizer();
|
||||
if (singularizer == null) continue;
|
||||
if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderAbstractType, sd)) {
|
||||
bfd.singularData = null;
|
||||
}
|
||||
if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderAbstractType, sd)) bfd.singularData = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,9 +401,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
}
|
||||
// Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder.
|
||||
MethodDeclaration md = HandleToString.createToString(job.builderType, fieldNodes, true, superclassBuilderClass != null, ast, FieldAccess.ALWAYS_FIELD);
|
||||
if (md != null) {
|
||||
injectMethod(job.builderType, md);
|
||||
}
|
||||
if (md != null) injectMethod(job.builderType, md);
|
||||
}
|
||||
|
||||
if (addCleaning) {
|
||||
@@ -593,7 +585,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
char[][] setVariableInBuilder = new char[][] {BUILDER_VARIABLE_NAME, fieldNode.nameOfSetFlag};
|
||||
long[] positions = new long[] {p, p};
|
||||
QualifiedNameReference setVariableInBuilderRef = new QualifiedNameReference(setVariableInBuilder, positions, s, e);
|
||||
|
||||
|
||||
MessageSend defaultMethodCall = new MessageSend();
|
||||
defaultMethodCall.sourceStart = job.source.sourceStart;
|
||||
defaultMethodCall.sourceEnd = job.source.sourceEnd;
|
||||
@@ -657,7 +649,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a <code>toBuilder()</code> method in the annotated class that looks like this:
|
||||
* Generates a {@code toBuilder()} method in the annotated class that looks like this:
|
||||
* <pre>
|
||||
* public <i>Foobar</i>.<i>Foobar</i>Builder<?, ?> toBuilder() {
|
||||
* return new <i.Foobar</i>.<i>Foobar</i>BuilderImpl().$fillValuesFrom(this);
|
||||
@@ -696,10 +688,10 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
out.traverse(new SetGeneratedByVisitor(job.source), ((TypeDeclaration) job.parentType.get()).scope);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a <code>$fillValuesFrom()</code> method in the abstract builder class that looks
|
||||
* like this:
|
||||
* Generates a {@code $fillValuesFrom()} method in the abstract builder class.
|
||||
* It looks like:
|
||||
* <pre>
|
||||
* protected B $fillValuesFrom(final C instance) {
|
||||
* super.$fillValuesFrom(instance);
|
||||
@@ -718,9 +710,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
|
||||
TypeReference builderType = new SingleTypeReference(classGenericName.toCharArray(), 0);
|
||||
out.arguments = new Argument[] {new Argument(INSTANCE_VARIABLE_NAME, 0, builderType, Modifier.FINAL)};
|
||||
|
||||
|
||||
List<Statement> body = new ArrayList<Statement>();
|
||||
|
||||
|
||||
if (inherited) {
|
||||
// Call super.
|
||||
MessageSend callToSuper = new MessageSend();
|
||||
@@ -729,14 +721,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
callToSuper.arguments = new Expression[] {new SingleNameReference(INSTANCE_VARIABLE_NAME, 0)};
|
||||
body.add(callToSuper);
|
||||
}
|
||||
|
||||
|
||||
// Call the builder implemention's helper method that actually fills the values from the instance.
|
||||
MessageSend callStaticFillValuesMethod = new MessageSend();
|
||||
callStaticFillValuesMethod.receiver = generateNameReference(job.parentType, job.builderAbstractClassNameArr, 0);
|
||||
callStaticFillValuesMethod.selector = FILL_VALUES_STATIC_METHOD_NAME;
|
||||
callStaticFillValuesMethod.arguments = new Expression[] {new SingleNameReference(INSTANCE_VARIABLE_NAME, 0), new ThisReference(0, 0)};
|
||||
body.add(callStaticFillValuesMethod);
|
||||
|
||||
|
||||
// Return self().
|
||||
MessageSend returnCall = new MessageSend();
|
||||
returnCall.receiver = ThisReference.implicitThis();
|
||||
@@ -747,9 +739,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a <code>$fillValuesFromInstanceIntoBuilder()</code> method in
|
||||
* Generates a {@code $fillValuesFromInstanceIntoBuilder()} method in
|
||||
* the builder implementation class that copies all fields from the instance
|
||||
* to the builder. It looks like this:
|
||||
*
|
||||
@@ -1007,7 +999,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
if (Arrays.equals(setterName.toCharArray(), existingName) && !isTolerate(fieldNode, existing[i])) return;
|
||||
}
|
||||
|
||||
List<Annotation> methodAnnsList = Arrays.asList(EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode));
|
||||
List<Annotation> methodAnnsList = Arrays.asList(EclipseHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode, true));
|
||||
addCheckerFrameworkReturnsReceiver(returnType, job.source, job.checkerFramework);
|
||||
MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, paramName, nameOfSetFlag, returnType, returnStatement, ClassFileConstants.AccPublic,
|
||||
job.sourceNode, methodAnnsList, annosOnParam != null ? Arrays.asList(copyAnnotations(job.source, annosOnParam)) : Collections.<Annotation>emptyList());
|
||||
@@ -1095,8 +1087,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
java.util.HashSet<String> usedNames = new HashSet<String>();
|
||||
|
||||
// 1. Add type parameter names.
|
||||
for (TypeParameter typeParam : typeParams)
|
||||
usedNames.add(typeParam.toString());
|
||||
for (TypeParameter typeParam : typeParams) usedNames.add(typeParam.toString());
|
||||
|
||||
// 2. Add class name.
|
||||
usedNames.add(String.valueOf(td.name));
|
||||
@@ -1119,14 +1110,12 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
|
||||
return usedNames;
|
||||
}
|
||||
|
||||
|
||||
private void addFirstToken(java.util.Set<String> usedNames, TypeReference type) {
|
||||
if (type == null)
|
||||
return;
|
||||
if (type == null) return;
|
||||
// Add the first token, because only that can collide.
|
||||
char[][] typeName = type.getTypeName();
|
||||
if (typeName != null && typeName.length >= 1)
|
||||
usedNames.add(String.valueOf(typeName[0]));
|
||||
if (typeName != null && typeName.length >= 1) usedNames.add(String.valueOf(typeName[0]));
|
||||
}
|
||||
|
||||
private String generateNonclashingNameFor(String classGenericName, java.util.Set<String> typeParamStrings) {
|
||||
@@ -1227,8 +1216,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
// Cannot use typeMatches() here, because the parameter could be fully-qualified, partially-qualified, or not qualified.
|
||||
// A string-compare of the last part should work. If it's a false-positive, users could still @Tolerate it.
|
||||
char[] typeName = def.arguments[0].type.getLastToken();
|
||||
if (builderClassName.equals(String.valueOf(typeName)))
|
||||
return true;
|
||||
if (builderClassName.equals(String.valueOf(typeName))) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2021 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-2025 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
|
||||
@@ -219,7 +219,7 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer {
|
||||
char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(builderType, new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray();
|
||||
md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName(builderType, "addAll", new String(data.getPluralName())).toCharArray();
|
||||
Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, data.getSource());
|
||||
Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up()));
|
||||
Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up(), true));
|
||||
md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class);
|
||||
|
||||
if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md);
|
||||
|
||||
@@ -195,7 +195,7 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula
|
||||
char[] prefixedSelector = data.getSetterPrefix().length == 0 ? data.getPluralName() : HandlerUtil.buildAccessorName(builderType, new String(data.getSetterPrefix()), new String(data.getPluralName())).toCharArray();
|
||||
md.selector = fluent ? prefixedSelector : HandlerUtil.buildAccessorName(builderType, "addAll", new String(data.getPluralName())).toCharArray();
|
||||
Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, data.getSource());
|
||||
Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up()));
|
||||
Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up(), true));
|
||||
md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class);
|
||||
|
||||
if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2021 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-2025 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
|
||||
@@ -332,7 +332,7 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer
|
||||
|
||||
md.selector = setterName.toCharArray();
|
||||
Annotation[] selfReturnAnnotations = generateSelfReturnAnnotations(deprecate, data.getSource());
|
||||
Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up()));
|
||||
Annotation[] copyToSetterAnnotations = copyAnnotations(md, findCopyableToSetterAnnotations(data.getAnnotation().up(), true));
|
||||
md.annotations = concat(selfReturnAnnotations, copyToSetterAnnotations, Annotation.class);
|
||||
|
||||
if (returnStatement != null) createRelevantNonNullAnnotation(builderType, md);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2021 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-2025 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Project Lombok Authors.
|
||||
* Copyright (C) 2018-2025 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
|
||||
@@ -40,7 +40,7 @@ import lombok.Singular;
|
||||
* <p>
|
||||
* The <code><strong>T</strong>Builder</code> class contains 1 method for each parameter of the annotated
|
||||
* constructor / method (each field, when annotating a class), which returns the builder itself.
|
||||
* The builder also has a <code>build()</code> method which returns a completed instance of the original type.
|
||||
* The builder also has a {@code build()} method which returns a completed instance of the original type.
|
||||
* <p>
|
||||
* Complete documentation is found at <a href="https://projectlombok.org/features/experimental/SuperBuilder">the project lombok features page for @SuperBuilder</a>.
|
||||
*
|
||||
@@ -56,8 +56,8 @@ public @interface SuperBuilder {
|
||||
String buildMethodName() default "build";
|
||||
|
||||
/**
|
||||
* If <code>true</code>, generate an instance method to obtain a builder that is initialized with the values of this instance.
|
||||
* In this case, all superclasses must also have <code>toBuilder=true</code>.
|
||||
* If {@code true}, generate an instance method to obtain a builder that is initialized with the values of this instance.
|
||||
* In this case, all superclasses must also have {@code toBuilder=true}.
|
||||
*
|
||||
* @return Whether to generate a {@code toBuilder()} method.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2019 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-2025 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
|
||||
@@ -34,7 +34,7 @@ import java.lang.annotation.Target;
|
||||
* <li>If any constructors are declared in it, an error is generated. Otherwise, a private no-args constructor is generated; it throws a {@code UnsupportedOperationException}.</li>
|
||||
* <li>All methods, inner classes, and fields in the class are marked static.</li>
|
||||
* <li><em>WARNING:</em> Do not use non-star static imports to import these members; javac won't be able to figure it out. Use either:
|
||||
* <code>import static ThisType.*;</code> or don't static-import.</li>
|
||||
* {@code import static ThisType.*;} or don't static-import.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
|
||||
+17
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Project Lombok Authors.
|
||||
* Copyright (C) 2020-2025 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
|
||||
@@ -28,12 +28,21 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* The {@code @Jacksonized} annotation is an add-on annotation for
|
||||
* {@code @}{@link Builder} and {@code @}{@link SuperBuilder}. It automatically
|
||||
* configures the generated builder class to be used by Jackson's
|
||||
* {@code @}{@link Builder}, {@code @}{@link SuperBuilder}, and
|
||||
* {@code @}{@link Accessors}.
|
||||
* <p>
|
||||
* For {@code @}{@link Accessors}{@code (fluent = true)} on a type, it automatically
|
||||
* configures Jackson to use the generated setters and getters for
|
||||
* (de-)serialization by inserting {@code @}{@link JsonProperty} annotations.
|
||||
* (Note that {@code @Jacksonized} {@code @Accessors} on fields are not supported.)
|
||||
* <p>
|
||||
* For {@code @}{@link Builder} and {@code @}{@link SuperBuilder}, it
|
||||
* automatically configures the generated builder class to be used by Jackson's
|
||||
* deserialization. It only has an effect if present at a context where there is
|
||||
* also a {@code @Builder} or a {@code @SuperBuilder}; a warning is emitted
|
||||
* otherwise.
|
||||
@@ -41,8 +50,8 @@ import lombok.experimental.SuperBuilder;
|
||||
* In particular, the annotation does the following:
|
||||
* <ul>
|
||||
* <li>Configure Jackson to use the builder for deserialization using
|
||||
* {@code @JsonDeserialize(builder=Foobar.FoobarBuilder[Impl].class)}
|
||||
* on the class (where <em>Foobar</em> is the name of the annotated class).</li>
|
||||
* {@code @JsonDeserialize(builder=Foobar.FoobarBuilder[Impl].class)} on the
|
||||
* class (where <em>Foobar</em> is the name of the annotated class).</li>
|
||||
* <li>Copy Jackson-related configuration annotations (like
|
||||
* {@code @JsonIgnoreProperties}) from the class to the builder class. This is
|
||||
* necessary so that Jackson recognizes them when using the builder.</li>
|
||||
@@ -54,9 +63,9 @@ import lombok.experimental.SuperBuilder;
|
||||
* <li>For {@code @SuperBuilder}, make the builder implementation class
|
||||
* package-private.</li>
|
||||
* </ul>
|
||||
* This annotation does <em>not</em> change the behavior of the generated builder.
|
||||
* A {@code @Jacksonized} {@code @SuperBuilder} remains fully compatible to
|
||||
* regular {@code @SuperBuilder}s.
|
||||
* This annotation does <em>not</em> change the behavior of the generated
|
||||
* builder. A {@code @Jacksonized} {@code @SuperBuilder} remains fully
|
||||
* compatible to regular {@code @SuperBuilder}s.
|
||||
*/
|
||||
@Target({TYPE, METHOD, CONSTRUCTOR})
|
||||
@Retention(SOURCE)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2021 The Project Lombok Authors.
|
||||
* Copyright (C) 2013-2025 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
|
||||
@@ -930,7 +930,7 @@ public class HandleBuilder extends JavacAnnotationHandler<Builder> {
|
||||
|
||||
JavacTreeMaker maker = fieldNode.getTreeMaker();
|
||||
|
||||
List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(bfd.originalFieldNode);
|
||||
List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(bfd.originalFieldNode, true);
|
||||
JCMethodDecl newMethod = HandleSetter.createSetter(toJavacModifier(job.accessInners), deprecate, fieldNode, maker, setterName, bfd.name, bfd.nameOfSetFlag, job.oldChain, job.sourceNode, methodAnns, bfd.annotations);
|
||||
recursiveSetGeneratedBy(newMethod, job.sourceNode);
|
||||
if (job.sourceNode.up().getKind() == Kind.METHOD) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2024 The Project Lombok Authors.
|
||||
* Copyright (C) 2009-2025 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
|
||||
@@ -249,8 +249,15 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
|
||||
JCExpression annotationMethodDefaultValue = null;
|
||||
|
||||
List<JCAnnotation> copyableAnnotations = findCopyableAnnotations(field);
|
||||
|
||||
// Copying Jackson annotations is required for fluent accessors (otherwise Jackson would not find the accessor).
|
||||
boolean fluent = accessors.isExplicit("fluent");
|
||||
Boolean fluentConfig = field.getAst().readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT);
|
||||
if (fluentConfig != null && fluentConfig) fluent = fluentConfig;
|
||||
List<JCAnnotation> copyableToGetterAnnotations = copyAnnotations(findCopyableToGetterAnnotations(field, fluent), treeMaker);
|
||||
|
||||
List<JCAnnotation> delegates = findDelegatesAndRemoveFromField(field);
|
||||
List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod, treeMaker).appendList(copyableAnnotations);
|
||||
List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod, treeMaker).appendList(copyableAnnotations).appendList(copyableToGetterAnnotations);
|
||||
if (field.isFinal()) {
|
||||
if (getCheckerFrameworkVersion(field).generatePure()) annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genTypeRef(field, CheckerFrameworkVersion.NAME__PURE), List.<JCExpression>nil()));
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2021 The Project Lombok Authors.
|
||||
* Copyright (C) 2020-2025 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
|
||||
@@ -33,6 +33,7 @@ import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
|
||||
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
|
||||
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.ListBuffer;
|
||||
|
||||
@@ -42,6 +43,7 @@ import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.core.handlers.HandlerUtil;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
import lombok.javac.JavacAnnotationHandler;
|
||||
@@ -55,34 +57,76 @@ import lombok.spi.Provides;
|
||||
* needs for builders.
|
||||
*/
|
||||
@Provides
|
||||
@HandlerPriority(-512) // Above Handle(Super)Builder's level (builders must be already generated).
|
||||
@HandlerPriority(-512) // Above Handle(Super)Builder's level (builders must be already generated), but before all handlers generating getters/setters.
|
||||
public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> {
|
||||
|
||||
@Override public void handle(AnnotationValues<Jacksonized> annotation, JCAnnotation ast, JavacNode annotationNode) {
|
||||
handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.JACKSONIZED_FLAG_USAGE, "@Jacksonized");
|
||||
|
||||
|
||||
JavacNode annotatedNode = annotationNode.up();
|
||||
deleteAnnotationIfNeccessary(annotationNode, Jacksonized.class);
|
||||
|
||||
JavacNode tdNode;
|
||||
if (annotatedNode.getKind() != Kind.TYPE)
|
||||
tdNode = annotatedNode.up(); // @Jacksonized on a constructor or a static factory method.
|
||||
else
|
||||
tdNode = annotatedNode; // @Jacksonized on the class.
|
||||
if (annotatedNode.getKind() != Kind.TYPE) tdNode = annotatedNode.up(); // @Jacksonized on a constructor or a static factory method.
|
||||
else tdNode = annotatedNode; // @Jacksonized on the class.
|
||||
JCClassDecl td = (JCClassDecl) tdNode.get();
|
||||
|
||||
|
||||
JavacNode builderAnnotationNode = findAnnotation(Builder.class, annotatedNode);
|
||||
JavacNode superBuilderAnnotationNode = findAnnotation(SuperBuilder.class, annotatedNode);
|
||||
if (builderAnnotationNode == null && superBuilderAnnotationNode == null) {
|
||||
annotationNode.addWarning("@Jacksonized requires @Builder or @SuperBuilder for it to mean anything.");
|
||||
JavacNode accessorsAnnotationNode = findAnnotation(Accessors.class, annotatedNode);
|
||||
if (builderAnnotationNode == null && superBuilderAnnotationNode == null && accessorsAnnotationNode == null) {
|
||||
annotationNode.addWarning("@Jacksonized requires @Builder, @SuperBuilder, or @Accessors for it to mean anything.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (builderAnnotationNode != null || superBuilderAnnotationNode != null) {
|
||||
handleJacksonizedBuilder(annotationNode, annotatedNode, tdNode, td, builderAnnotationNode, superBuilderAnnotationNode);
|
||||
}
|
||||
|
||||
if (accessorsAnnotationNode != null) {
|
||||
handleJacksonizedAccessors(annotationNode, annotatedNode, tdNode, td, accessorsAnnotationNode, builderAnnotationNode != null || superBuilderAnnotationNode != null);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleJacksonizedAccessors(JavacNode annotationNode, JavacNode annotatedNode, JavacNode tdNode, JCClassDecl td, JavacNode accessorsAnnotationNode, boolean jacksonizedBuilder) {
|
||||
AnnotationValues<Accessors> accessorsAnnotation = accessorsAnnotationNode != null ?
|
||||
createAnnotation(Accessors.class, accessorsAnnotationNode) : null;
|
||||
boolean fluent = accessorsAnnotation != null && accessorsAnnotation.getInstance().fluent();
|
||||
|
||||
if (!fluent) {
|
||||
// No changes required for chained-only accessors.
|
||||
if (!jacksonizedBuilder)
|
||||
annotationNode.addWarning("@Jacksonized only affects fluent accessors (@Accessors(fluent=true)).");
|
||||
return;
|
||||
}
|
||||
|
||||
// Add @JsonProperty to all fields. It will be automatically copied to the getter/setters later.
|
||||
for (JavacNode javacNode : tdNode.down()) {
|
||||
if (javacNode.getKind() == Kind.FIELD) {
|
||||
createJsonPropertyForField(javacNode, annotationNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createJsonPropertyForField(JavacNode fieldNode, JavacNode annotationNode) {
|
||||
if (hasAnnotation("com.fasterxml.jackson.annotation.JsonProperty", fieldNode)) {
|
||||
return;
|
||||
}
|
||||
JavacTreeMaker maker = fieldNode.getTreeMaker();
|
||||
|
||||
JCExpression jsonPropertyType = chainDots(fieldNode, "com", "fasterxml", "jackson", "annotation", "JsonProperty");
|
||||
JCAnnotation annotationJsonProperty = maker.Annotation(jsonPropertyType, List.<JCExpression>of(maker.Literal(fieldNode.getName())));
|
||||
recursiveSetGeneratedBy(annotationJsonProperty, annotationNode);
|
||||
JCVariableDecl fieldDecl = ((JCVariableDecl)fieldNode.get());
|
||||
fieldDecl.mods.annotations = fieldDecl.mods.annotations.append(annotationJsonProperty);
|
||||
}
|
||||
|
||||
private void handleJacksonizedBuilder(JavacNode annotationNode, JavacNode annotatedNode, JavacNode tdNode, JCClassDecl td, JavacNode builderAnnotationNode, JavacNode superBuilderAnnotationNode) {
|
||||
if (builderAnnotationNode != null && superBuilderAnnotationNode != null) {
|
||||
annotationNode.addError("@Jacksonized cannot process both @Builder and @SuperBuilder on the same class.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
boolean isAbstract = (td.mods.flags & Flags.ABSTRACT) != 0;
|
||||
if (isAbstract) {
|
||||
annotationNode.addError("Builders on abstract classes cannot be @Jacksonized (the builder would never be used).");
|
||||
@@ -90,24 +134,22 @@ public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> {
|
||||
}
|
||||
|
||||
AnnotationValues<Builder> builderAnnotation = builderAnnotationNode != null ?
|
||||
createAnnotation(Builder.class, builderAnnotationNode) :
|
||||
null;
|
||||
createAnnotation(Builder.class, builderAnnotationNode) : null;
|
||||
AnnotationValues<SuperBuilder> superBuilderAnnotation = superBuilderAnnotationNode != null ?
|
||||
createAnnotation(SuperBuilder.class, superBuilderAnnotationNode) :
|
||||
null;
|
||||
createAnnotation(SuperBuilder.class, superBuilderAnnotationNode) : null;
|
||||
|
||||
String setPrefix = builderAnnotation != null ?
|
||||
builderAnnotation.getInstance().setterPrefix() :
|
||||
superBuilderAnnotation.getInstance().setterPrefix();
|
||||
superBuilderAnnotation.getInstance().setterPrefix();
|
||||
String buildMethodName = builderAnnotation != null ?
|
||||
builderAnnotation.getInstance().buildMethodName() :
|
||||
superBuilderAnnotation.getInstance().buildMethodName();
|
||||
superBuilderAnnotation.getInstance().buildMethodName();
|
||||
|
||||
JavacTreeMaker maker = annotatedNode.getTreeMaker();
|
||||
|
||||
|
||||
// Now lets find the generated builder class.
|
||||
String builderClassName = getBuilderClassName(annotationNode, annotatedNode, td, builderAnnotation, maker);
|
||||
|
||||
|
||||
JCClassDecl builderClass = null;
|
||||
for (JCTree member : td.getMembers()) {
|
||||
if (member instanceof JCClassDecl && ((JCClassDecl) member).getSimpleName().contentEquals(builderClassName)) {
|
||||
@@ -149,20 +191,17 @@ public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> {
|
||||
JCAnnotation annotationJsonPOJOBuilder = maker.Annotation(jsonPOJOBuilderType, List.of(withPrefixExpr, buildMethodNameExpr));
|
||||
recursiveSetGeneratedBy(annotationJsonPOJOBuilder, annotatedNode);
|
||||
builderClass.mods.annotations = builderClass.mods.annotations.append(annotationJsonPOJOBuilder);
|
||||
|
||||
|
||||
// @SuperBuilder? Make it package-private!
|
||||
if (superBuilderAnnotationNode != null)
|
||||
builderClass.mods.flags = builderClass.mods.flags & ~Flags.PRIVATE;
|
||||
}
|
||||
|
||||
if (superBuilderAnnotationNode != null) builderClass.mods.flags = builderClass.mods.flags & ~Flags.PRIVATE;
|
||||
}
|
||||
|
||||
private String getBuilderClassName(JavacNode annotationNode, JavacNode annotatedNode, JCClassDecl td, AnnotationValues<Builder> builderAnnotation, JavacTreeMaker maker) {
|
||||
String builderClassName = builderAnnotation != null ?
|
||||
builderAnnotation.getInstance().builderClassName() : null;
|
||||
String builderClassName = builderAnnotation != null ? builderAnnotation.getInstance().builderClassName() : null;
|
||||
if (builderClassName == null || builderClassName.isEmpty()) {
|
||||
builderClassName = annotationNode.getAst().readConfiguration(ConfigurationKeys.BUILDER_CLASS_NAME);
|
||||
if (builderClassName == null || builderClassName.isEmpty())
|
||||
builderClassName = "*Builder";
|
||||
|
||||
if (builderClassName == null || builderClassName.isEmpty()) builderClassName = "*Builder";
|
||||
|
||||
JCMethodDecl fillParametersFrom = annotatedNode.get() instanceof JCMethodDecl ? (JCMethodDecl)annotatedNode.get() : null;
|
||||
String replacement;
|
||||
if (fillParametersFrom != null && !fillParametersFrom.getName().toString().equals("<init>")) {
|
||||
@@ -179,9 +218,8 @@ public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> {
|
||||
}
|
||||
builderClassName = builderClassName.replace("*", replacement);
|
||||
}
|
||||
|
||||
if (builderAnnotation == null)
|
||||
builderClassName += "Impl"; // For @SuperBuilder, all Jackson annotations must be put on the BuilderImpl class.
|
||||
|
||||
if (builderAnnotation == null) builderClassName += "Impl"; // For @SuperBuilder, all Jackson annotations must be put on the BuilderImpl class.
|
||||
|
||||
return builderClassName;
|
||||
}
|
||||
@@ -191,7 +229,7 @@ public class HandleJacksonized extends JavacAnnotationHandler<Jacksonized> {
|
||||
for (JavacNode child : node.down()) {
|
||||
if (child.getKind() == Kind.ANNOTATION) {
|
||||
JCAnnotation annotation = (JCAnnotation) child.get();
|
||||
for (String bn : HandlerUtil.JACKSON_COPY_TO_BUILDER_ANNOTATIONS) {
|
||||
for (String bn : HandlerUtil.JACKSON_COPY_TO_BUILDER_ANNOTATIONS) {
|
||||
if (typeMatches(bn, node, annotation.annotationType)) {
|
||||
result.append(annotation);
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2024 The Project Lombok Authors.
|
||||
* Copyright (C) 2009-2025 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
|
||||
@@ -211,7 +211,7 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
|
||||
return createSetter(access, deprecate, field, treeMaker, setterName, paramName, booleanFieldToSet, returnType, returnStatement, source, onMethod, onParam);
|
||||
}
|
||||
|
||||
public static JCMethodDecl createSetterWithRecv(long access, boolean deprecate, JavacNode field, JavacTreeMaker treeMaker, String setterName, Name paramName, Name booleanFieldToSet, boolean shouldReturnThis, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam, JCVariableDecl recv) {
|
||||
public static JCMethodDecl createSetterWithRecv(long access, boolean deprecate, JavacNode field, JavacTreeMaker treeMaker, String setterName, Name paramName, Name booleanFieldToSet, boolean shouldReturnThis, JavacNode source, List<JCAnnotation> onMethod, List<JCAnnotation> onParam, JCVariableDecl recv, boolean forceAnnotationCopying) {
|
||||
JCExpression returnType = null;
|
||||
JCReturn returnStatement = null;
|
||||
if (shouldReturnThis) {
|
||||
@@ -274,12 +274,17 @@ public class HandleSetter extends JavacAnnotationHandler<Setter> {
|
||||
List<JCExpression> throwsClauses = List.nil();
|
||||
JCExpression annotationMethodDefaultValue = null;
|
||||
|
||||
List<JCAnnotation> annsOnMethod = mergeAnnotations(copyAnnotations(onMethod, treeMaker), findCopyableToSetterAnnotations(field));
|
||||
// Copying Jackson annotations is required for fluent accessors (otherwise Jackson would not find the accessor).
|
||||
AnnotationValues<Accessors> accessors = JavacHandlerUtil.getAccessorsForField(field);
|
||||
boolean fluent = accessors.isExplicit("fluent");
|
||||
Boolean fluentConfig = field.getAst().readConfiguration(ConfigurationKeys.ACCESSORS_FLUENT);
|
||||
if (fluentConfig != null && fluentConfig) fluent = fluentConfig;
|
||||
|
||||
List<JCAnnotation> annsOnMethod = mergeAnnotations(copyAnnotations(onMethod, treeMaker), findCopyableToSetterAnnotations(field, fluent));
|
||||
if (isFieldDeprecated(field) || deprecate) {
|
||||
annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>nil()));
|
||||
}
|
||||
|
||||
AnnotationValues<Accessors> accessors = JavacHandlerUtil.getAccessorsForField(field);
|
||||
if (shouldMakeFinal(field, accessors)) access |= Flags.FINAL;
|
||||
JCMethodDecl methodDef;
|
||||
if (recv != null && treeMaker.hasMethodDefWithRecvParam()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2021 The Project Lombok Authors.
|
||||
* Copyright (C) 2013-2025 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
|
||||
@@ -143,13 +143,10 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
job.init(annotation, annInstance, annotationNode);
|
||||
|
||||
boolean generateBuilderMethod;
|
||||
if (job.builderMethodName.isEmpty()) {
|
||||
generateBuilderMethod = false;
|
||||
} else if (!checkName("builderMethodName", job.builderMethodName, annotationNode)) {
|
||||
return;
|
||||
} else {
|
||||
generateBuilderMethod = true;
|
||||
}
|
||||
if (job.builderMethodName.isEmpty()) generateBuilderMethod = false;
|
||||
else if (!checkName("builderMethodName", job.builderMethodName, annotationNode)) return;
|
||||
else generateBuilderMethod = true;
|
||||
|
||||
if (!checkName("buildMethodName", job.buildMethodName, annotationNode)) return;
|
||||
|
||||
// Do not delete the SuperBuilder annotation here, we need it for @Jacksonized.
|
||||
@@ -313,9 +310,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
if (sd == null) continue;
|
||||
JavacSingularizer singularizer = sd.getSingularizer();
|
||||
if (singularizer == null) continue;
|
||||
if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderAbstractType, sd)) {
|
||||
bfd.singularData = null;
|
||||
}
|
||||
if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderAbstractType, sd)) bfd.singularData = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,7 +384,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
}
|
||||
sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderImplType, annotationNode);
|
||||
}
|
||||
|
||||
|
||||
// Create a simple constructor for the BuilderImpl class.
|
||||
JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, List.<JCAnnotation>nil(), job.builderImplType, List.<JavacNode>nil(), false, annotationNode);
|
||||
if (cd != null) injectMethod(job.builderImplType, cd);
|
||||
@@ -515,7 +510,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
recursiveSetGeneratedBy(builder, job.sourceNode);
|
||||
return injectType(job.parentType, builder);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a constructor that has a builder as the only parameter.
|
||||
* The values from the builder are used to initialize the fields of new instances.
|
||||
@@ -582,8 +577,8 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
if (callBuilderBasedSuperConstructor) {
|
||||
// The first statement must be the call to the super constructor.
|
||||
JCMethodInvocation callToSuperConstructor = maker.Apply(List.<JCExpression>nil(),
|
||||
maker.Ident(job.toName("super")),
|
||||
List.<JCExpression>of(maker.Ident(builderVariableName)));
|
||||
maker.Ident(job.toName("super")),
|
||||
List.<JCExpression>of(maker.Ident(builderVariableName)));
|
||||
statements.prepend(maker.Exec(callToSuperConstructor));
|
||||
}
|
||||
|
||||
@@ -624,7 +619,9 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a <code>toBuilder()</code> method in the annotated class that looks like this:
|
||||
* Generates a {@code toBuilder()} method in the annotated class.
|
||||
*
|
||||
* It looks like:
|
||||
* <pre>
|
||||
* public ParentBuilder<?, ?> toBuilder() {
|
||||
* return new <i>Foobar</i>BuilderImpl().$fillValuesFrom(this);
|
||||
@@ -657,10 +654,11 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
createRelevantNonNullAnnotation(job.parentType, methodDef);
|
||||
return methodDef;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a <code>$fillValuesFrom()</code> method in the abstract builder class that looks
|
||||
* like this:
|
||||
* Generates a {@code $fillValuesFrom()} method in the abstract builder class.
|
||||
*
|
||||
* It looks like:
|
||||
* <pre>
|
||||
* protected B $fillValuesFrom(final C instance) {
|
||||
* super.$fillValuesFrom(instance);
|
||||
@@ -682,7 +680,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
|
||||
JCExpression classGenericNameExpr = maker.Ident(job.toName(classGenericName));
|
||||
JCVariableDecl param = maker.VarDef(maker.Modifiers(Flags.PARAMETER | Flags.FINAL), job.toName(INSTANCE_VARIABLE_NAME), classGenericNameExpr, null);
|
||||
|
||||
|
||||
ListBuffer<JCStatement> body = new ListBuffer<JCStatement>();
|
||||
|
||||
if (inherited) {
|
||||
@@ -706,11 +704,12 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
|
||||
return maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), List.of(param), List.<JCExpression>nil(), bodyBlock, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a <code>$fillValuesFromInstanceIntoBuilder()</code> method in
|
||||
* Generates a {@code $fillValuesFromInstanceIntoBuilder()} method in
|
||||
* the builder implementation class that copies all fields from the instance
|
||||
* to the builder. It looks like this:
|
||||
* to the builder.
|
||||
* It looks like:
|
||||
*
|
||||
* <pre>
|
||||
* protected B $fillValuesFromInstanceIntoBuilder(Foobar instance, FoobarBuilder<?, ?> b) {
|
||||
@@ -727,7 +726,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
|
||||
// 1st parameter: "Foobar instance"
|
||||
JCVariableDecl paramInstance = maker.VarDef(maker.Modifiers(Flags.PARAMETER | Flags.FINAL), job.toName(INSTANCE_VARIABLE_NAME), cloneSelfType(job.parentType), null);
|
||||
|
||||
|
||||
// 2nd parameter: "FoobarBuilder<?, ?> b" (plus generics on the annotated type)
|
||||
// First add all generics that are present on the parent type.
|
||||
ListBuffer<JCExpression> typeParamsForBuilderParameter = getTypeParamExpressions(job.typeParams, maker, job.sourceNode);
|
||||
@@ -800,7 +799,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
Name name = job.toName(SELF_METHOD);
|
||||
JCExpression returnType = maker.Ident(job.toName(builderGenericName));
|
||||
returnType = addCheckerFrameworkReturnsReceiver(returnType, maker, job.builderType, job.checkerFramework);
|
||||
|
||||
|
||||
return maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null);
|
||||
}
|
||||
|
||||
@@ -965,7 +964,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
|
||||
JavacTreeMaker maker = fieldNode.getTreeMaker();
|
||||
|
||||
List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode);
|
||||
List<JCAnnotation> methodAnns = JavacHandlerUtil.findCopyableToSetterAnnotations(originalFieldNode, true);
|
||||
returnType = addCheckerFrameworkReturnsReceiver(returnType, maker, job.builderType, job.checkerFramework);
|
||||
|
||||
JCMethodDecl newMethod = HandleSetter.createSetter(Flags.PUBLIC, deprecate, fieldNode, maker, setterName, paramName, nameOfSetFlag, returnType, returnStatement, job.sourceNode, methodAnns, annosOnParam);
|
||||
@@ -1046,8 +1045,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
java.util.HashSet<String> usedNames = new HashSet<String>();
|
||||
|
||||
// 1. Add type parameter names.
|
||||
for (JCTypeParameter typeParam : typeParams)
|
||||
usedNames.add(typeParam.getName().toString());
|
||||
for (JCTypeParameter typeParam : typeParams) usedNames.add(typeParam.getName().toString());
|
||||
|
||||
// 2. Add class name.
|
||||
usedNames.add(td.name.toString());
|
||||
@@ -1056,16 +1054,13 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
for (JCTree member : td.getMembers()) {
|
||||
if (member.getKind() == com.sun.source.tree.Tree.Kind.VARIABLE && member instanceof JCVariableDecl) {
|
||||
JCTree type = ((JCVariableDecl)member).getType();
|
||||
if (type instanceof JCIdent)
|
||||
usedNames.add(((JCIdent)type).getName().toString());
|
||||
if (type instanceof JCIdent) usedNames.add(((JCIdent)type).getName().toString());
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Add extends and implements clauses.
|
||||
addFirstToken(usedNames, Javac.getExtendsClause(td));
|
||||
for (JCExpression impl : td.getImplementsClause()) {
|
||||
addFirstToken(usedNames, impl);
|
||||
}
|
||||
for (JCExpression impl : td.getImplementsClause()) addFirstToken(usedNames, impl);
|
||||
|
||||
return usedNames;
|
||||
}
|
||||
@@ -1078,7 +1073,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
}
|
||||
while (type instanceof JCFieldAccess && ((JCFieldAccess)type).selected != null) {
|
||||
// Add the first token, because only that can collide.
|
||||
type = ((JCFieldAccess)type).selected;
|
||||
type = ((JCFieldAccess) type).selected;
|
||||
}
|
||||
usedNames.add(type.toString());
|
||||
}
|
||||
@@ -1118,7 +1113,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
}
|
||||
return typeParamsForBuilderParameter;
|
||||
}
|
||||
|
||||
|
||||
private JCExpression copySelect(JavacTreeMaker maker, JCFieldAccess typeParam) {
|
||||
java.util.List<Name> chainNames = new ArrayList<Name>();
|
||||
JCExpression expression = typeParam;
|
||||
@@ -1131,7 +1126,7 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
expression = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Collections.reverse(chainNames);
|
||||
JCExpression typeParameter = null;
|
||||
for (Name name : chainNames) {
|
||||
@@ -1154,18 +1149,16 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
JCMethodDecl md = (JCMethodDecl) def;
|
||||
String name = md.name.toString();
|
||||
boolean matches = name.equals("<init>");
|
||||
if (isTolerate(type, md))
|
||||
continue;
|
||||
if (isTolerate(type, md)) continue;
|
||||
if (matches && md.params != null && md.params.length() == 1) {
|
||||
// Cannot use typeMatches() here, because the parameter could be fully-qualified, partially-qualified, or not qualified.
|
||||
// A string-compare of the last part should work. If it's a false-positive, users could still @Tolerate it.
|
||||
String typeName = md.params.get(0).getType().toString();
|
||||
int lastIndexOfDot = typeName.lastIndexOf('.');
|
||||
if (lastIndexOfDot >= 0) {
|
||||
typeName = typeName.substring(lastIndexOfDot+1);
|
||||
typeName = typeName.substring(lastIndexOfDot + 1);
|
||||
}
|
||||
if ((builderClassName+"<?, ?>").equals(typeName))
|
||||
return true;
|
||||
if ((builderClassName+"<?, ?>").equals(typeName)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1757,17 +1757,36 @@ public class JavacHandlerUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the given field node for annotations that are specifically intentioned to be copied to the setter.
|
||||
* Searches the given field node for annotations that are specifically intended to be copied to the getter.
|
||||
*
|
||||
* @param forceCopyJacksonAnnotations If {@code true}, always copy the annotations regardless of lombok configuration key {@code lombok.copyJacksonAnnotationsToAccessors}.
|
||||
*/
|
||||
public static List<JCAnnotation> findCopyableToSetterAnnotations(JavacNode node) {
|
||||
return findAnnotationsInList(node, COPY_TO_SETTER_ANNOTATIONS);
|
||||
public static List<JCAnnotation> findCopyableToGetterAnnotations(JavacNode node, boolean forceCopyJacksonAnnotations) {
|
||||
if (!forceCopyJacksonAnnotations) {
|
||||
Boolean copyAnnotations = node.getAst().readConfiguration(ConfigurationKeys.COPY_JACKSON_ANNOTATIONS_TO_ACCESSORS);
|
||||
if (copyAnnotations == null || !copyAnnotations) return List.nil();
|
||||
}
|
||||
return findAnnotationsInList(node, JACKSON_COPY_TO_GETTER_ANNOTATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the given field node for annotations that are specifically intentioned to be copied to the builder's singular method.
|
||||
* Searches the given field node for annotations that are specifically intended to be copied to the setter.
|
||||
*
|
||||
* @param forceCopyJacksonAnnotations If {@code true}, always copy the annotations regardless of lombok configuration key {@code lombok.copyJacksonAnnotationsToAccessors}.
|
||||
*/
|
||||
public static List<JCAnnotation> findCopyableToSetterAnnotations(JavacNode node, boolean forceCopyJacksonAnnotations) {
|
||||
if (!forceCopyJacksonAnnotations) {
|
||||
Boolean copyAnnotations = node.getAst().readConfiguration(ConfigurationKeys.COPY_JACKSON_ANNOTATIONS_TO_ACCESSORS);
|
||||
if (copyAnnotations == null || !copyAnnotations) return List.nil();
|
||||
}
|
||||
return findAnnotationsInList(node, JACKSON_COPY_TO_SETTER_ANNOTATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the given field node for annotations that are specifically intended to be copied to the builder's singular method.
|
||||
*/
|
||||
public static List<JCAnnotation> findCopyableToBuilderSingularSetterAnnotations(JavacNode node) {
|
||||
return findAnnotationsInList(node, COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS);
|
||||
return findAnnotationsInList(node, JACKSON_COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2021 The Project Lombok Authors.
|
||||
* Copyright (C) 2015-2025 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
|
||||
@@ -362,7 +362,7 @@ public class JavacSingularsRecipes {
|
||||
statements.prepend(JavacHandlerUtil.generateNullCheck(maker, null, data.getPluralName(), builderType, "%s cannot be null"));
|
||||
}
|
||||
|
||||
List<JCAnnotation> methodAnnotations = copyAnnotations(findCopyableToSetterAnnotations(data.annotation.up()), maker);
|
||||
List<JCAnnotation> methodAnnotations = copyAnnotations(findCopyableToSetterAnnotations(data.annotation.up(), true), maker);
|
||||
|
||||
finishAndInjectMethod(cfv, maker, returnType, returnStatement, data, builderType, source, deprecate, statements, name, List.of(param), methodAnnotations, access, ignoreNullCollections);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2024 The Project Lombok Authors.
|
||||
* Copyright (C) 2020-2025 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
|
||||
@@ -78,8 +78,8 @@ public class PatchJavadoc {
|
||||
}
|
||||
|
||||
/**
|
||||
* The method <code>javadoc2HTML</code> changed 2014-12 to accept an
|
||||
* additional IJavaElement parameter. To support older versions, try to
|
||||
* The method {@code javadoc2HTML} changed 2014-12 to accept an
|
||||
* additional {@code IJavaElement} parameter. To support older versions, try to
|
||||
* find that one too.
|
||||
*/
|
||||
private static class Reflection {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2023 The Project Lombok Authors.
|
||||
* Copyright (C) 2014-2025 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
|
||||
@@ -67,14 +67,14 @@ import java.util.zip.ZipInputStream;
|
||||
* <p>
|
||||
* Load order is as follows if at least one override is present:
|
||||
* <li>First, if the resource is found in one of the paths stated in the shadow classpath, find that.
|
||||
* <li>Next, ask the <code>parent</code> loader, which is passed during construction of the ShadowClassLoader.
|
||||
* <li>Next, ask the {@code parent} loader, which is passed during construction of the ShadowClassLoader.
|
||||
* <li>Notably, this jar's contents are always skipped! (The idea of the shadow classpath is that this jar only functions as a launcher, not as a source of your actual application).
|
||||
* </ul>
|
||||
*
|
||||
* If no overrides are present, the load order is as follows:
|
||||
* <li>First, if the resource is found in our own jar (trying ".SCL.<em>sclSuffix</em>" first for any resource request ending in ".class"), return that.
|
||||
* <li>Next, check any jar files other than our own, loading them via this classloader, if they have a file <code>META-INF/ShadowClassLoader</code> that contains a line of text with <em>sclSuffix</em>.
|
||||
* <li>Next, ask the <code>parent</code> loader.
|
||||
* <li>Next, check any jar files other than our own, loading them via this classloader, if they have a file {@code META-INF/ShadowClassLoader} that contains a line of text with <em>sclSuffix</em>.
|
||||
* <li>Next, ask the {@code parent} loader.
|
||||
* </ul>
|
||||
*
|
||||
* Use ShadowClassLoader to accomplish the following things:<ul>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
public class JacksonizedAccessors {
|
||||
@com.fasterxml.jackson.annotation.JsonProperty("intValue")
|
||||
private int intValue;
|
||||
@com.fasterxml.jackson.annotation.JsonProperty("intValue")
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public int intValue() {
|
||||
return this.intValue;
|
||||
}
|
||||
/**
|
||||
* @return {@code this}.
|
||||
*/
|
||||
@com.fasterxml.jackson.annotation.JsonProperty("intValue")
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonizedAccessors intValue(final int intValue) {
|
||||
this.intValue = intValue;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
+23
-23
@@ -5,8 +5,8 @@ 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 {
|
||||
@com.fasterxml.jackson.databind.annotation.JsonDeserialize(builder = JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder.class)
|
||||
public class JacksonizedBuilderSingular {
|
||||
@JsonAnySetter
|
||||
private Map<String, Object> any;
|
||||
@JsonProperty("v_a_l_u_e_s")
|
||||
@@ -17,7 +17,7 @@ public class JacksonBuilderSingular {
|
||||
private ImmutableList<String> guavaValues;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
JacksonBuilderSingular(final Map<String, Object> any, final List<String> values, final ImmutableMap<String, Object> guavaAny, final ImmutableList<String> guavaValues) {
|
||||
JacksonizedBuilderSingular(final Map<String, Object> any, final List<String> values, final ImmutableMap<String, Object> guavaAny, final ImmutableList<String> guavaValues) {
|
||||
this.any = any;
|
||||
this.values = values;
|
||||
this.guavaAny = guavaAny;
|
||||
@@ -26,7 +26,7 @@ public class JacksonBuilderSingular {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
@com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "", buildMethodName = "build")
|
||||
public static class JacksonBuilderSingularBuilder {
|
||||
public static class JacksonizedBuilderSingularBuilder {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
private java.util.ArrayList<String> any$key;
|
||||
@@ -44,12 +44,12 @@ public class JacksonBuilderSingular {
|
||||
private com.google.common.collect.ImmutableList.Builder<String> guavaValues;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
JacksonBuilderSingularBuilder() {
|
||||
JacksonizedBuilderSingularBuilder() {
|
||||
}
|
||||
@JsonAnySetter
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular.JacksonBuilderSingularBuilder any(final String anyKey, final Object anyValue) {
|
||||
public JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder any(final String anyKey, final Object anyValue) {
|
||||
if (this.any$key == null) {
|
||||
this.any$key = new java.util.ArrayList<String>();
|
||||
this.any$value = new java.util.ArrayList<Object>();
|
||||
@@ -60,7 +60,7 @@ public class JacksonBuilderSingular {
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular.JacksonBuilderSingularBuilder any(final java.util.Map<? extends String, ? extends Object> any) {
|
||||
public JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder any(final java.util.Map<? extends String, ? extends Object> any) {
|
||||
if (any == null) {
|
||||
throw new java.lang.NullPointerException("any cannot be null");
|
||||
}
|
||||
@@ -76,7 +76,7 @@ public class JacksonBuilderSingular {
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular.JacksonBuilderSingularBuilder clearAny() {
|
||||
public JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder clearAny() {
|
||||
if (this.any$key != null) {
|
||||
this.any$key.clear();
|
||||
this.any$value.clear();
|
||||
@@ -85,7 +85,7 @@ public class JacksonBuilderSingular {
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular.JacksonBuilderSingularBuilder value(final String value) {
|
||||
public JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder value(final String value) {
|
||||
if (this.values == null) this.values = new java.util.ArrayList<String>();
|
||||
this.values.add(value);
|
||||
return this;
|
||||
@@ -93,7 +93,7 @@ public class JacksonBuilderSingular {
|
||||
@JsonProperty("v_a_l_u_e_s")
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular.JacksonBuilderSingularBuilder values(final java.util.Collection<? extends String> values) {
|
||||
public JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder values(final java.util.Collection<? extends String> values) {
|
||||
if (values == null) {
|
||||
throw new java.lang.NullPointerException("values cannot be null");
|
||||
}
|
||||
@@ -103,21 +103,21 @@ public class JacksonBuilderSingular {
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular.JacksonBuilderSingularBuilder clearValues() {
|
||||
public JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder clearValues() {
|
||||
if (this.values != null) this.values.clear();
|
||||
return this;
|
||||
}
|
||||
@JsonAnySetter
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaAny(final String key, final Object value) {
|
||||
public JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder guavaAny(final String key, final Object value) {
|
||||
if (this.guavaAny == null) this.guavaAny = com.google.common.collect.ImmutableMap.builder();
|
||||
this.guavaAny.put(key, value);
|
||||
return this;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaAny(final java.util.Map<? extends String, ? extends Object> guavaAny) {
|
||||
public JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder guavaAny(final java.util.Map<? extends String, ? extends Object> guavaAny) {
|
||||
if (guavaAny == null) {
|
||||
throw new java.lang.NullPointerException("guavaAny cannot be null");
|
||||
}
|
||||
@@ -127,13 +127,13 @@ public class JacksonBuilderSingular {
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular.JacksonBuilderSingularBuilder clearGuavaAny() {
|
||||
public JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder clearGuavaAny() {
|
||||
this.guavaAny = null;
|
||||
return this;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaValue(final String guavaValue) {
|
||||
public JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder guavaValue(final String guavaValue) {
|
||||
if (this.guavaValues == null) this.guavaValues = com.google.common.collect.ImmutableList.builder();
|
||||
this.guavaValues.add(guavaValue);
|
||||
return this;
|
||||
@@ -141,7 +141,7 @@ public class JacksonBuilderSingular {
|
||||
@JsonProperty("guava_v_a_l_u_e_s")
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaValues(final java.lang.Iterable<? extends String> guavaValues) {
|
||||
public JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder guavaValues(final java.lang.Iterable<? extends String> guavaValues) {
|
||||
if (guavaValues == null) {
|
||||
throw new java.lang.NullPointerException("guavaValues cannot be null");
|
||||
}
|
||||
@@ -151,13 +151,13 @@ public class JacksonBuilderSingular {
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular.JacksonBuilderSingularBuilder clearGuavaValues() {
|
||||
public JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder clearGuavaValues() {
|
||||
this.guavaValues = null;
|
||||
return this;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public JacksonBuilderSingular build() {
|
||||
public JacksonizedBuilderSingular build() {
|
||||
java.util.Map<String, Object> any;
|
||||
switch (this.any$key == null ? 0 : this.any$key.size()) {
|
||||
case 0:
|
||||
@@ -184,18 +184,18 @@ public class JacksonBuilderSingular {
|
||||
}
|
||||
com.google.common.collect.ImmutableMap<String, Object> guavaAny = this.guavaAny == null ? com.google.common.collect.ImmutableMap.<String, Object>of() : this.guavaAny.build();
|
||||
com.google.common.collect.ImmutableList<String> guavaValues = this.guavaValues == null ? com.google.common.collect.ImmutableList.<String>of() : this.guavaValues.build();
|
||||
return new JacksonBuilderSingular(any, values, guavaAny, guavaValues);
|
||||
return new JacksonizedBuilderSingular(any, values, guavaAny, guavaValues);
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public java.lang.String toString() {
|
||||
return "JacksonBuilderSingular.JacksonBuilderSingularBuilder(any$key=" + this.any$key + ", any$value=" + this.any$value + ", values=" + this.values + ", guavaAny=" + this.guavaAny + ", guavaValues=" + this.guavaValues + ")";
|
||||
return "JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder(any$key=" + this.any$key + ", any$value=" + this.any$value + ", values=" + this.values + ", guavaAny=" + this.guavaAny + ", guavaValues=" + this.guavaValues + ")";
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
@lombok.Generated
|
||||
public static JacksonBuilderSingular.JacksonBuilderSingularBuilder builder() {
|
||||
return new JacksonBuilderSingular.JacksonBuilderSingularBuilder();
|
||||
public static JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder builder() {
|
||||
return new JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
public @lombok.extern.jackson.Jacksonized @lombok.experimental.Accessors(fluent = true) @lombok.Getter @lombok.Setter class JacksonizedAccessors {
|
||||
private @com.fasterxml.jackson.annotation.JsonProperty("intValue") int intValue;
|
||||
public JacksonizedAccessors() {
|
||||
super();
|
||||
}
|
||||
public @com.fasterxml.jackson.annotation.JsonProperty("intValue") @java.lang.SuppressWarnings("all") @lombok.Generated int intValue() {
|
||||
return this.intValue;
|
||||
}
|
||||
/**
|
||||
* @return {@code this}.
|
||||
*/
|
||||
public @com.fasterxml.jackson.annotation.JsonProperty("intValue") @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedAccessors intValue(final int intValue) {
|
||||
this.intValue = intValue;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
+22
-22
@@ -7,17 +7,17 @@ import com.google.common.collect.ImmutableMap;
|
||||
import lombok.Builder;
|
||||
import lombok.Singular;
|
||||
import lombok.extern.jackson.Jacksonized;
|
||||
public @Jacksonized @Builder @com.fasterxml.jackson.databind.annotation.JsonDeserialize(builder = JacksonBuilderSingular.JacksonBuilderSingularBuilder.class) class JacksonBuilderSingular {
|
||||
public static @java.lang.SuppressWarnings("all") @lombok.Generated @com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "",buildMethodName = "build") class JacksonBuilderSingularBuilder {
|
||||
public @Jacksonized @Builder @com.fasterxml.jackson.databind.annotation.JsonDeserialize(builder = JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder.class) class JacksonizedBuilderSingular {
|
||||
public static @java.lang.SuppressWarnings("all") @lombok.Generated @com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder(withPrefix = "",buildMethodName = "build") class JacksonizedBuilderSingularBuilder {
|
||||
private @java.lang.SuppressWarnings("all") @lombok.Generated java.util.ArrayList<String> any$key;
|
||||
private @java.lang.SuppressWarnings("all") @lombok.Generated java.util.ArrayList<Object> any$value;
|
||||
private @java.lang.SuppressWarnings("all") @lombok.Generated java.util.ArrayList<String> values;
|
||||
private @java.lang.SuppressWarnings("all") @lombok.Generated com.google.common.collect.ImmutableMap.Builder<String, Object> guavaAny;
|
||||
private @java.lang.SuppressWarnings("all") @lombok.Generated com.google.common.collect.ImmutableList.Builder<String> guavaValues;
|
||||
@java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingularBuilder() {
|
||||
@java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingularBuilder() {
|
||||
super();
|
||||
}
|
||||
public @JsonAnySetter @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder any(final String anyKey, final Object anyValue) {
|
||||
public @JsonAnySetter @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder any(final String anyKey, final Object anyValue) {
|
||||
if ((this.any$key == null))
|
||||
{
|
||||
this.any$key = new java.util.ArrayList<String>();
|
||||
@@ -27,7 +27,7 @@ public @Jacksonized @Builder @com.fasterxml.jackson.databind.annotation.JsonDese
|
||||
this.any$value.add(anyValue);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder any(final java.util.Map<? extends String, ? extends Object> any) {
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder any(final java.util.Map<? extends String, ? extends Object> any) {
|
||||
if ((any == null))
|
||||
{
|
||||
throw new java.lang.NullPointerException("any cannot be null");
|
||||
@@ -44,7 +44,7 @@ public @Jacksonized @Builder @com.fasterxml.jackson.databind.annotation.JsonDese
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder clearAny() {
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder clearAny() {
|
||||
if ((this.any$key != null))
|
||||
{
|
||||
this.any$key.clear();
|
||||
@@ -52,13 +52,13 @@ public @Jacksonized @Builder @com.fasterxml.jackson.databind.annotation.JsonDese
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder value(final String value) {
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder value(final String value) {
|
||||
if ((this.values == null))
|
||||
this.values = new java.util.ArrayList<String>();
|
||||
this.values.add(value);
|
||||
return this;
|
||||
}
|
||||
public @JsonProperty("v_a_l_u_e_s") @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder values(final java.util.Collection<? extends String> values) {
|
||||
public @JsonProperty("v_a_l_u_e_s") @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder values(final java.util.Collection<? extends String> values) {
|
||||
if ((values == null))
|
||||
{
|
||||
throw new java.lang.NullPointerException("values cannot be null");
|
||||
@@ -68,18 +68,18 @@ public @Jacksonized @Builder @com.fasterxml.jackson.databind.annotation.JsonDese
|
||||
this.values.addAll(values);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder clearValues() {
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder clearValues() {
|
||||
if ((this.values != null))
|
||||
this.values.clear();
|
||||
return this;
|
||||
}
|
||||
public @JsonAnySetter @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaAny(final String key, final Object value) {
|
||||
public @JsonAnySetter @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder guavaAny(final String key, final Object value) {
|
||||
if ((this.guavaAny == null))
|
||||
this.guavaAny = com.google.common.collect.ImmutableMap.builder();
|
||||
this.guavaAny.put(key, value);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaAny(final java.util.Map<? extends String, ? extends Object> guavaAny) {
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder guavaAny(final java.util.Map<? extends String, ? extends Object> guavaAny) {
|
||||
if ((guavaAny == null))
|
||||
{
|
||||
throw new java.lang.NullPointerException("guavaAny cannot be null");
|
||||
@@ -89,17 +89,17 @@ public @Jacksonized @Builder @com.fasterxml.jackson.databind.annotation.JsonDese
|
||||
this.guavaAny.putAll(guavaAny);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder clearGuavaAny() {
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder clearGuavaAny() {
|
||||
this.guavaAny = null;
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaValue(final String guavaValue) {
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder guavaValue(final String guavaValue) {
|
||||
if ((this.guavaValues == null))
|
||||
this.guavaValues = com.google.common.collect.ImmutableList.builder();
|
||||
this.guavaValues.add(guavaValue);
|
||||
return this;
|
||||
}
|
||||
public @JsonProperty("guava_v_a_l_u_e_s") @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder guavaValues(final java.lang.Iterable<? extends String> guavaValues) {
|
||||
public @JsonProperty("guava_v_a_l_u_e_s") @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder guavaValues(final java.lang.Iterable<? extends String> guavaValues) {
|
||||
if ((guavaValues == null))
|
||||
{
|
||||
throw new java.lang.NullPointerException("guavaValues cannot be null");
|
||||
@@ -109,11 +109,11 @@ public @Jacksonized @Builder @com.fasterxml.jackson.databind.annotation.JsonDese
|
||||
this.guavaValues.addAll(guavaValues);
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder clearGuavaValues() {
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder clearGuavaValues() {
|
||||
this.guavaValues = null;
|
||||
return this;
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular build() {
|
||||
public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular build() {
|
||||
java.util.Map<String, Object> any;
|
||||
switch (((this.any$key == null) ? 0 : this.any$key.size())) {
|
||||
case 0 :
|
||||
@@ -141,24 +141,24 @@ public @Jacksonized @Builder @com.fasterxml.jackson.databind.annotation.JsonDese
|
||||
}
|
||||
com.google.common.collect.ImmutableMap<String, Object> guavaAny = ((this.guavaAny == null) ? com.google.common.collect.ImmutableMap.<String, Object>of() : this.guavaAny.build());
|
||||
com.google.common.collect.ImmutableList<String> guavaValues = ((this.guavaValues == null) ? com.google.common.collect.ImmutableList.<String>of() : this.guavaValues.build());
|
||||
return new JacksonBuilderSingular(any, values, guavaAny, guavaValues);
|
||||
return new JacksonizedBuilderSingular(any, values, guavaAny, guavaValues);
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") @lombok.Generated java.lang.String toString() {
|
||||
return (((((((((("JacksonBuilderSingular.JacksonBuilderSingularBuilder(any$key=" + this.any$key) + ", any$value=") + this.any$value) + ", values=") + this.values) + ", guavaAny=") + this.guavaAny) + ", guavaValues=") + this.guavaValues) + ")");
|
||||
return (((((((((("JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder(any$key=" + this.any$key) + ", any$value=") + this.any$value) + ", values=") + this.values) + ", guavaAny=") + this.guavaAny) + ", guavaValues=") + this.guavaValues) + ")");
|
||||
}
|
||||
}
|
||||
private @JsonAnySetter @Singular("any") Map<String, Object> any;
|
||||
private @JsonProperty("v_a_l_u_e_s") @Singular List<String> values;
|
||||
private @JsonAnySetter @Singular("guavaAny") ImmutableMap<String, Object> guavaAny;
|
||||
private @JsonProperty("guava_v_a_l_u_e_s") @Singular ImmutableList<String> guavaValues;
|
||||
@java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular(final Map<String, Object> any, final List<String> values, final ImmutableMap<String, Object> guavaAny, final ImmutableList<String> guavaValues) {
|
||||
@java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular(final Map<String, Object> any, final List<String> values, final ImmutableMap<String, Object> guavaAny, final ImmutableList<String> guavaValues) {
|
||||
super();
|
||||
this.any = any;
|
||||
this.values = values;
|
||||
this.guavaAny = guavaAny;
|
||||
this.guavaValues = guavaValues;
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") @lombok.Generated JacksonBuilderSingular.JacksonBuilderSingularBuilder builder() {
|
||||
return new JacksonBuilderSingular.JacksonBuilderSingularBuilder();
|
||||
public static @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder builder() {
|
||||
return new JacksonizedBuilderSingular.JacksonizedBuilderSingularBuilder();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
//CONF: lombok.copyJacksonAnnotationsToAccessors = true
|
||||
//version 8: Jackson deps are at least Java7+.
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
@lombok.extern.jackson.Jacksonized
|
||||
@lombok.experimental.Accessors(fluent = true)
|
||||
@lombok.Getter
|
||||
@lombok.Setter
|
||||
public class JacksonizedAccessors {
|
||||
private int intValue;
|
||||
}
|
||||
+1
-1
@@ -13,7 +13,7 @@ import lombok.extern.jackson.Jacksonized;
|
||||
|
||||
@Jacksonized
|
||||
@Builder
|
||||
public class JacksonBuilderSingular {
|
||||
public class JacksonizedBuilderSingular {
|
||||
@JsonAnySetter
|
||||
@Singular("any")
|
||||
private Map<String, Object> any;
|
||||
Reference in new issue
Block a user