diff --git a/src/core/lombok/core/configuration/JacksonVersion.java b/src/core/lombok/core/configuration/JacksonVersion.java index 58a5e52c..480dd973 100644 --- a/src/core/lombok/core/configuration/JacksonVersion.java +++ b/src/core/lombok/core/configuration/JacksonVersion.java @@ -26,6 +26,9 @@ public enum JacksonVersion implements MappedConfigEnum { THREE, ; + public static final String AMBIGUOUS_JACKSON_VERSION_WARNING_TEXT = + "Ambiguous: Jackson2 and Jackson3 exist; define which variant(s) you want in 'lombok.config'. See https://projectlombok.org/features/experimental/Jacksonized"; + @Override public boolean matches(String value) { if (this == TWO) return "2".equals(value); return "3".equals(value); diff --git a/src/core/lombok/core/handlers/HandlerUtil.java b/src/core/lombok/core/handlers/HandlerUtil.java index 091de762..4f546352 100644 --- a/src/core/lombok/core/handlers/HandlerUtil.java +++ b/src/core/lombok/core/handlers/HandlerUtil.java @@ -453,6 +453,9 @@ public class HandlerUtil { "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper", "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty", "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText", + "tools.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper", + "tools.jackson.dataformat.xml.annotation.JacksonXmlProperty", + "tools.jackson.dataformat.xml.annotation.JacksonXmlText", })); JACKSON_COPY_TO_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] { "com.fasterxml.jackson.annotation.JacksonInject", @@ -467,10 +470,13 @@ public class HandlerUtil { "com.fasterxml.jackson.annotation.JsonUnwrapped", "com.fasterxml.jackson.annotation.JsonView", "com.fasterxml.jackson.databind.annotation.JsonDeserialize", - "tools.jackson.databind.annotation.JsonDeserialize", "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper", "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty", "com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText", + "tools.jackson.databind.annotation.JsonDeserialize", + "tools.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper", + "tools.jackson.dataformat.xml.annotation.JacksonXmlProperty", + "tools.jackson.dataformat.xml.annotation.JacksonXmlText", })); JACKSON_COPY_TO_BUILDER_SINGULAR_SETTER_ANNOTATIONS = Collections.unmodifiableList(Arrays.asList(new String[] { "com.fasterxml.jackson.annotation.JsonAnySetter", diff --git a/src/core/lombok/eclipse/handlers/HandleJacksonized.java b/src/core/lombok/eclipse/handlers/HandleJacksonized.java index 360e499f..a1f34df9 100644 --- a/src/core/lombok/eclipse/handlers/HandleJacksonized.java +++ b/src/core/lombok/eclipse/handlers/HandleJacksonized.java @@ -90,9 +90,11 @@ public class HandleJacksonized extends EclipseAnnotationHandler { return; } + List jacksonVersions = readConfiguredJacksonVersions(annotationNode); + boolean jacksonizedBuilder = builderAnnotationNode != null || superBuilderAnnotationNode != null; if (jacksonizedBuilder) { - handleJacksonizedBuilder(ast, annotationNode, annotatedNode, tdNode, td, builderAnnotationNode, superBuilderAnnotationNode); + handleJacksonizedBuilder(ast, annotationNode, annotatedNode, tdNode, td, builderAnnotationNode, superBuilderAnnotationNode, jacksonVersions); } if (accessorsAnnotationNode != null) { @@ -100,7 +102,7 @@ public class HandleJacksonized extends EclipseAnnotationHandler { } } - private void handleJacksonizedBuilder(Annotation ast, EclipseNode annotationNode, EclipseNode annotatedNode, EclipseNode tdNode, TypeDeclaration td, EclipseNode builderAnnotationNode, EclipseNode superBuilderAnnotationNode) { + private void handleJacksonizedBuilder(Annotation ast, EclipseNode annotationNode, EclipseNode annotatedNode, EclipseNode tdNode, TypeDeclaration td, EclipseNode builderAnnotationNode, EclipseNode superBuilderAnnotationNode, List jacksonVersions) { boolean isAbstract = (td.modifiers & ClassFileConstants.AccAbstract) != 0; if (isAbstract) { annotationNode.addError("Builders on abstract classes cannot be @Jacksonized (the builder would never be used)."); @@ -141,13 +143,6 @@ public class HandleJacksonized extends EclipseAnnotationHandler { ClassLiteralAccess builderClassLiteralAccess = new ClassLiteralAccess(td.sourceEnd, builderClassExpression); MemberValuePair builderMvp = new MemberValuePair("builder".toCharArray(), td.sourceStart, td.sourceEnd, builderClassLiteralAccess); - List jacksonVersions = annotationNode.getAst().readConfigurationOr(ConfigurationKeys.JACKSONIZED_JACKSON_VERSION, Arrays.asList()); - - if (jacksonVersions.isEmpty()) { - annotationNode.addWarning("Ambiguous: Jackson2 and Jackson3 exist; define which variant(s) you want in 'lombok.config'. See https://projectlombok.org/features/experimental/Jacksonized"); - jacksonVersions = Arrays.asList(JacksonVersion.TWO); - } - if (jacksonVersions.contains(JacksonVersion.TWO)) { td.annotations = addAnnotation(td, td.annotations, JacksonAnnotationType.JSON_DESERIALIZE2.getQualifiednameAsCharArrayArray(), builderMvp); } @@ -193,7 +188,7 @@ public class HandleJacksonized extends EclipseAnnotationHandler { // 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) { - if (hasAnnotation(eclipseNode, JacksonAnnotationType.JSON_PROPERTY2) || + if (hasAnnotation(eclipseNode, JacksonAnnotationType.JSON_PROPERTY2) || hasAnnotation(eclipseNode, JacksonAnnotationType.JSON_IGNORE2)) { continue; } @@ -212,7 +207,7 @@ public class HandleJacksonized extends EclipseAnnotationHandler { 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, JacksonAnnotationType.JSON_PROPERTY2.getQualifiednameAsCharArrayArray(), fieldName); + fd.annotations = addAnnotation(fieldNode.get(), fd.annotations, JacksonAnnotationType.JSON_PROPERTY2.getQualifiednameAsCharArrayArray(), fieldName); } } @@ -220,7 +215,7 @@ public class HandleJacksonized extends EclipseAnnotationHandler { ASTNode astNode = fieldNode.get(); if (astNode instanceof FieldDeclaration) { FieldDeclaration fd = (FieldDeclaration) astNode; - ((FieldDeclaration) astNode).annotations = addAnnotation(fieldNode.get(), fd.annotations, JacksonAnnotationType.JSON_IGNORE2.getQualifiednameAsCharArrayArray()); + fd.annotations = addAnnotation(fieldNode.get(), fd.annotations, JacksonAnnotationType.JSON_IGNORE2.getQualifiednameAsCharArrayArray()); } } @@ -248,6 +243,13 @@ public class HandleJacksonized extends EclipseAnnotationHandler { return builderClassName; } + private List readConfiguredJacksonVersions(EclipseNode annotationNode) { + List jacksonVersions = annotationNode.getAst().readConfigurationOr(ConfigurationKeys.JACKSONIZED_JACKSON_VERSION, Arrays.asList()); + if (!jacksonVersions.isEmpty()) return jacksonVersions; + annotationNode.addWarning(JacksonVersion.AMBIGUOUS_JACKSON_VERSION_WARNING_TEXT); + return Arrays.asList(JacksonVersion.TWO); + } + private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY = new Annotation[0]; private static Annotation[] findJacksonAnnotationsOnClass(TypeDeclaration td, EclipseNode node) { diff --git a/src/core/lombok/javac/handlers/HandleJacksonized.java b/src/core/lombok/javac/handlers/HandleJacksonized.java index e5484d38..b2e2a9b7 100644 --- a/src/core/lombok/javac/handlers/HandleJacksonized.java +++ b/src/core/lombok/javac/handlers/HandleJacksonized.java @@ -114,9 +114,10 @@ public class HandleJacksonized extends JavacAnnotationHandler { // Add @JsonProperty to all non-transient fields. It will be automatically copied to the getter/setters later. // Add @JsonIgnore to all transient fields. It will be automatically copied to the getter/setters later. + readConfiguredJacksonVersions(annotationNode); for (JavacNode javacNode : tdNode.down()) { if (javacNode.getKind() == Kind.FIELD) { - if (hasAnnotation(javacNode, JacksonAnnotationType.JSON_PROPERTY2) || + if (hasAnnotation(javacNode, JacksonAnnotationType.JSON_PROPERTY2) || hasAnnotation(javacNode, JacksonAnnotationType.JSON_IGNORE2)) { continue; } @@ -131,22 +132,21 @@ public class HandleJacksonized extends JavacAnnotationHandler { private void createJsonPropertyForField(JavacNode fieldNode, JavacNode annotationNode) { JavacTreeMaker maker = fieldNode.getTreeMaker(); - - JCExpression jsonPropertyType = chainDots(fieldNode, JacksonAnnotationType.JSON_PROPERTY2); - JCAnnotation annotationJsonProperty = maker.Annotation(jsonPropertyType, List.of(maker.Literal(fieldNode.getName()))); - recursiveSetGeneratedBy(annotationJsonProperty, annotationNode); - JCVariableDecl fieldDecl = ((JCVariableDecl)fieldNode.get()); - fieldDecl.mods.annotations = fieldDecl.mods.annotations.append(annotationJsonProperty); + List args = List.of(maker.Literal(fieldNode.getName())); + addFieldAnnotation(fieldNode, annotationNode, JacksonAnnotationType.JSON_PROPERTY2, args); } private void createJsonIgnoreForField(JavacNode fieldNode, JavacNode annotationNode) { + addFieldAnnotation(fieldNode, annotationNode, JacksonAnnotationType.JSON_IGNORE2, List.nil()); + } + + private void addFieldAnnotation(JavacNode fieldNode, JavacNode annotationNode, JacksonAnnotationType annotationType, List args) { JavacTreeMaker maker = fieldNode.getTreeMaker(); - - JCExpression jsonPropertyType = chainDots(fieldNode, JacksonAnnotationType.JSON_IGNORE2); - JCAnnotation annotationJsonProperty = maker.Annotation(jsonPropertyType, List.nil()); - recursiveSetGeneratedBy(annotationJsonProperty, annotationNode); - JCVariableDecl fieldDecl = ((JCVariableDecl)fieldNode.get()); - fieldDecl.mods.annotations = fieldDecl.mods.annotations.append(annotationJsonProperty); + JCExpression type = chainDots(fieldNode, annotationType); + JCAnnotation annotation = maker.Annotation(type, args); + recursiveSetGeneratedBy(annotation, annotationNode); + JCVariableDecl fieldDecl = (JCVariableDecl) fieldNode.get(); + fieldDecl.mods.annotations = fieldDecl.mods.annotations.append(annotation); } private void handleJacksonizedBuilder(JavacNode annotationNode, JavacNode annotatedNode, JavacNode tdNode, JCClassDecl td, JavacNode builderAnnotationNode, JavacNode superBuilderAnnotationNode) { @@ -191,19 +191,14 @@ public class HandleJacksonized extends JavacAnnotationHandler { return; } + Collection jacksonVersions = readConfiguredJacksonVersions(annotationNode); + // Insert @JsonDeserialize on annotated class. if (hasAnnotation(tdNode, JacksonAnnotationType.JSON_DESERIALIZE2) || hasAnnotation(tdNode, JacksonAnnotationType.JSON_DESERIALIZE3)) { annotationNode.addError("@JsonDeserialize already exists on class. Either delete @JsonDeserialize, or remove @Jacksonized and manually configure Jackson."); return; } - Collection jacksonVersions = annotationNode.getAst().readConfigurationOr(ConfigurationKeys.JACKSONIZED_JACKSON_VERSION, Arrays.asList()); - - if (jacksonVersions.isEmpty()) { - annotationNode.addWarning("Ambiguous: Jackson2 and Jackson3 exist; define which variant(s) you want in 'lombok.config'. See https://projectlombok.org/features/experimental/Jacksonized"); - jacksonVersions = Arrays.asList(JacksonVersion.TWO); - } - if (jacksonVersions.contains(JacksonVersion.TWO)) { JCExpression jsonDeserializeType = chainDots(annotatedNode, JacksonAnnotationType.JSON_DESERIALIZE2); insertJsonDeserializeAnnotation(annotationNode, annotatedNode, tdNode, td, maker, builderClassName, jsonDeserializeType); @@ -280,6 +275,13 @@ public class HandleJacksonized extends JavacAnnotationHandler { return builderClassName; } + private Collection readConfiguredJacksonVersions(JavacNode annotationNode) { + Collection jacksonVersions = annotationNode.getAst().readConfigurationOr(ConfigurationKeys.JACKSONIZED_JACKSON_VERSION, Arrays.asList()); + if (!jacksonVersions.isEmpty()) return jacksonVersions; + annotationNode.addWarning(JacksonVersion.AMBIGUOUS_JACKSON_VERSION_WARNING_TEXT); + return Arrays.asList(JacksonVersion.TWO); + } + private static List findJacksonAnnotationsOnClass(JavacNode node) { ListBuffer result = new ListBuffer(); for (JavacNode child : node.down()) { diff --git a/test/transform/resource/after-delombok/JacksonizedAccessorsJackson3.java b/test/transform/resource/after-delombok/JacksonizedAccessorsJackson3.java new file mode 100644 index 00000000..b30650e7 --- /dev/null +++ b/test/transform/resource/after-delombok/JacksonizedAccessorsJackson3.java @@ -0,0 +1,109 @@ +//version 8: Jackson deps are at least Java7+. +//CONF: lombok.jacksonized.jacksonVersion += 3 +class JacksonizedAccessorsJackson3 { + @com.fasterxml.jackson.annotation.JsonProperty("name") + private String name; + @com.fasterxml.jackson.annotation.JsonProperty("age") + private int age; + @com.fasterxml.jackson.annotation.JsonIgnore + private transient String password; + + @java.lang.SuppressWarnings("all") + @lombok.Generated + public JacksonizedAccessorsJackson3() { + } + + @com.fasterxml.jackson.annotation.JsonProperty("name") + @java.lang.SuppressWarnings("all") + @lombok.Generated + public String name() { + return this.name; + } + + @com.fasterxml.jackson.annotation.JsonProperty("age") + @java.lang.SuppressWarnings("all") + @lombok.Generated + public int age() { + return this.age; + } + + @com.fasterxml.jackson.annotation.JsonIgnore + @java.lang.SuppressWarnings("all") + @lombok.Generated + public String password() { + return this.password; + } + + /** + * @return {@code this}. + */ + @com.fasterxml.jackson.annotation.JsonProperty("name") + @java.lang.SuppressWarnings("all") + @lombok.Generated + public JacksonizedAccessorsJackson3 name(final String name) { + this.name = name; + return this; + } + + /** + * @return {@code this}. + */ + @com.fasterxml.jackson.annotation.JsonProperty("age") + @java.lang.SuppressWarnings("all") + @lombok.Generated + public JacksonizedAccessorsJackson3 age(final int age) { + this.age = age; + return this; + } + + /** + * @return {@code this}. + */ + @com.fasterxml.jackson.annotation.JsonIgnore + @java.lang.SuppressWarnings("all") + @lombok.Generated + public JacksonizedAccessorsJackson3 password(final String password) { + this.password = password; + return this; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + @lombok.Generated + public boolean equals(final java.lang.Object o) { + if (o == this) return true; + if (!(o instanceof JacksonizedAccessorsJackson3)) return false; + final JacksonizedAccessorsJackson3 other = (JacksonizedAccessorsJackson3) o; + if (!other.canEqual((java.lang.Object) this)) return false; + if (this.age() != other.age()) return false; + final java.lang.Object this$name = this.name(); + final java.lang.Object other$name = other.name(); + if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false; + return true; + } + + @java.lang.SuppressWarnings("all") + @lombok.Generated + protected boolean canEqual(final java.lang.Object other) { + return other instanceof JacksonizedAccessorsJackson3; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + @lombok.Generated + public int hashCode() { + final int PRIME = 59; + int result = 1; + result = result * PRIME + this.age(); + final java.lang.Object $name = this.name(); + result = result * PRIME + ($name == null ? 43 : $name.hashCode()); + return result; + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + @lombok.Generated + public java.lang.String toString() { + return "JacksonizedAccessorsJackson3(name=" + this.name() + ", age=" + this.age() + ", password=" + this.password() + ")"; + } +} diff --git a/test/transform/resource/after-ecj/JacksonizedAccessorsJackson3.java b/test/transform/resource/after-ecj/JacksonizedAccessorsJackson3.java new file mode 100644 index 00000000..d68ebfd4 --- /dev/null +++ b/test/transform/resource/after-ecj/JacksonizedAccessorsJackson3.java @@ -0,0 +1,68 @@ +@lombok.Data @lombok.experimental.Accessors(fluent = true) @lombok.extern.jackson.Jacksonized class JacksonizedAccessorsJackson3 { + private @com.fasterxml.jackson.annotation.JsonProperty("name") String name; + private @com.fasterxml.jackson.annotation.JsonProperty("age") int age; + private transient @com.fasterxml.jackson.annotation.JsonIgnore String password; + public @com.fasterxml.jackson.annotation.JsonProperty("name") @java.lang.SuppressWarnings("all") @lombok.Generated String name() { + return this.name; + } + public @com.fasterxml.jackson.annotation.JsonProperty("age") @java.lang.SuppressWarnings("all") @lombok.Generated int age() { + return this.age; + } + public @com.fasterxml.jackson.annotation.JsonIgnore @java.lang.SuppressWarnings("all") @lombok.Generated String password() { + return this.password; + } + /** + * @return {@code this}. + */ + public @com.fasterxml.jackson.annotation.JsonProperty("name") @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedAccessorsJackson3 name(final String name) { + this.name = name; + return this; + } + /** + * @return {@code this}. + */ + public @com.fasterxml.jackson.annotation.JsonProperty("age") @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedAccessorsJackson3 age(final int age) { + this.age = age; + return this; + } + /** + * @return {@code this}. + */ + public @com.fasterxml.jackson.annotation.JsonIgnore @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedAccessorsJackson3 password(final String password) { + this.password = password; + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") @lombok.Generated boolean equals(final java.lang.Object o) { + if ((o == this)) + return true; + if ((! (o instanceof JacksonizedAccessorsJackson3))) + return false; + final JacksonizedAccessorsJackson3 other = (JacksonizedAccessorsJackson3) o; + if ((! other.canEqual((java.lang.Object) this))) + return false; + if ((this.age() != other.age())) + return false; + final java.lang.Object this$name = this.name(); + final java.lang.Object other$name = other.name(); + if (((this$name == null) ? (other$name != null) : (! this$name.equals(other$name)))) + return false; + return true; + } + protected @java.lang.SuppressWarnings("all") @lombok.Generated boolean canEqual(final java.lang.Object other) { + return (other instanceof JacksonizedAccessorsJackson3); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") @lombok.Generated int hashCode() { + final int PRIME = 59; + int result = 1; + result = ((result * PRIME) + this.age()); + final java.lang.Object $name = this.name(); + result = ((result * PRIME) + (($name == null) ? 43 : $name.hashCode())); + return result; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") @lombok.Generated java.lang.String toString() { + return (((((("JacksonizedAccessorsJackson3(name=" + this.name()) + ", age=") + this.age()) + ", password=") + this.password()) + ")"); + } + public @java.lang.SuppressWarnings("all") @lombok.Generated JacksonizedAccessorsJackson3() { + super(); + } +} diff --git a/test/transform/resource/before/JacksonizedAccessorsJackson3.java b/test/transform/resource/before/JacksonizedAccessorsJackson3.java new file mode 100644 index 00000000..2cad2104 --- /dev/null +++ b/test/transform/resource/before/JacksonizedAccessorsJackson3.java @@ -0,0 +1,10 @@ +//version 8: Jackson deps are at least Java7+. +//CONF: lombok.jacksonized.jacksonVersion += 3 +@lombok.Data +@lombok.experimental.Accessors(fluent = true) +@lombok.extern.jackson.Jacksonized +class JacksonizedAccessorsJackson3 { + private String name; + private int age; + private transient String password; +} \ No newline at end of file diff --git a/test/transform/resource/messages-delombok/JacksonizedAccessors.java.messages b/test/transform/resource/messages-delombok/JacksonizedAccessors.java.messages new file mode 100644 index 00000000..afa020b7 --- /dev/null +++ b/test/transform/resource/messages-delombok/JacksonizedAccessors.java.messages @@ -0,0 +1 @@ +1 Ambiguous: Jackson2 and Jackson3 exist; define which variant(s) you want in 'lombok.config'. See https://projectlombok.org/features/experimental/Jacksonized \ No newline at end of file diff --git a/test/transform/resource/messages-delombok/JacksonizedAccessorsTransient.java.messages b/test/transform/resource/messages-delombok/JacksonizedAccessorsTransient.java.messages new file mode 100644 index 00000000..afa020b7 --- /dev/null +++ b/test/transform/resource/messages-delombok/JacksonizedAccessorsTransient.java.messages @@ -0,0 +1 @@ +1 Ambiguous: Jackson2 and Jackson3 exist; define which variant(s) you want in 'lombok.config'. See https://projectlombok.org/features/experimental/Jacksonized \ No newline at end of file diff --git a/test/transform/resource/messages-ecj/JacksonizedAccessors.java.messages b/test/transform/resource/messages-ecj/JacksonizedAccessors.java.messages new file mode 100644 index 00000000..d61a0044 --- /dev/null +++ b/test/transform/resource/messages-ecj/JacksonizedAccessors.java.messages @@ -0,0 +1 @@ +1 Ambiguous: Jackson2 and Jackson3 exist; define which variant(s) you want in 'lombok.config'. See https://projectlombok.org/features/experimental/Jacksonized diff --git a/test/transform/resource/messages-ecj/JacksonizedAccessorsTransient.java.messages b/test/transform/resource/messages-ecj/JacksonizedAccessorsTransient.java.messages new file mode 100644 index 00000000..d61a0044 --- /dev/null +++ b/test/transform/resource/messages-ecj/JacksonizedAccessorsTransient.java.messages @@ -0,0 +1 @@ +1 Ambiguous: Jackson2 and Jackson3 exist; define which variant(s) you want in 'lombok.config'. See https://projectlombok.org/features/experimental/Jacksonized diff --git a/test/transform/resource/messages-ecj/JacksonizedSuperBuilderWithJsonDeserialize.java.messages b/test/transform/resource/messages-ecj/JacksonizedSuperBuilderWithJsonDeserialize.java.messages index 1947a26e..168feeb6 100644 --- a/test/transform/resource/messages-ecj/JacksonizedSuperBuilderWithJsonDeserialize.java.messages +++ b/test/transform/resource/messages-ecj/JacksonizedSuperBuilderWithJsonDeserialize.java.messages @@ -1 +1,2 @@ +2 Ambiguous: Jackson2 and Jackson3 exist; define which variant(s) you want in 'lombok.config'. See https://projectlombok.org/features/experimental/Jacksonized 2 @JsonDeserialize already exists on class. Either delete @JsonDeserialize, or remove @Jacksonized and manually configure Jackson.