Skip to content

Commit

Permalink
document rationale behind Jackson annotation copying
Browse files Browse the repository at this point in the history
  • Loading branch information
janrieke committed Nov 1, 2024
1 parent 26cbd8b commit b4ee8ae
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 7 deletions.
25 changes: 21 additions & 4 deletions src/core/lombok/core/handlers/HandlerUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public static int primeForNull() {
return 43;
}

public static final List<String> NONNULL_ANNOTATIONS, BASE_COPYABLE_ANNOTATIONS, COPY_TO_GETTER_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;
Expand Down Expand Up @@ -424,7 +424,22 @@ public static int primeForNull() {
"org.checkerframework.common.value.qual.UnknownVal",
"org.checkerframework.framework.qual.PurityUnqualified",
}));
COPY_TO_GETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {

// The following two lists contain all annotations that (in some cases) should 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.
// However, there are two exceptions:
// 1. When using a builder to deserialize, Jackson does _not_ consider the setter methods of the builder, i.e. annotations
// like @JsonIgnore on the field will not be respected. Thus, those annotations should be copied to the builder's setters.
// 2. If the getter/setter methods to 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 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",
Expand All @@ -437,7 +452,7 @@ public static int primeForNull() {
"com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty",
"com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText",
}));
COPY_TO_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] {
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",
Expand All @@ -454,9 +469,11 @@ public static int primeForNull() {
"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",
Expand Down
6 changes: 3 additions & 3 deletions src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -823,21 +823,21 @@ public static Annotation[] findCopyableAnnotations(EclipseNode node) {
* Searches the given field node for annotations that are specifically intentioned to be copied to the setter.
*/
public static Annotation[] findCopyableToGetterAnnotations(EclipseNode node) {
return findAnnotationsInList(node, COPY_TO_GETTER_ANNOTATIONS);
return findAnnotationsInList(node, JACKSON_COPY_TO_GETTER_ANNOTATIONS);
}

/**
* Searches the given field node for annotations that are specifically intentioned to be copied to the setter.
*/
public static Annotation[] findCopyableToSetterAnnotations(EclipseNode node) {
return findAnnotationsInList(node, COPY_TO_SETTER_ANNOTATIONS);
return findAnnotationsInList(node, JACKSON_COPY_TO_SETTER_ANNOTATIONS);
}

/**
* Searches the given field node for annotations that are specifically intentioned to be copied to the builder's singular method.
*/
public static Annotation[] findCopyableToBuilderSingularSetterAnnotations(EclipseNode node) {
return findAnnotationsInList(node, COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS);
return findAnnotationsInList(node, JACKSON_COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS);
}

/**
Expand Down

0 comments on commit b4ee8ae

Please sign in to comment.