Ich experimentiere mit der Kombination von Jackson und Lombok. Das sind meine Klassen:
package testelombok;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Value;
import lombok.experimental.Wither;
@Value
@Wither
@AllArgsConstructor(onConstructor=@__(@JsonCreator))
public class TestFoo {
@JsonProperty("xoom")
private String x;
private int z;
}
package testelombok;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xebia.jacksonlombok.JacksonLombokAnnotationIntrospector;
import java.io.IOException;
public class TestLombok {
public static void main(String[] args) throws IOException {
TestFoo tf = new TestFoo("a", 5);
System.out.println(tf.withX("b"));
ObjectMapper om = new ObjectMapper().setAnnotationIntrospector(new JacksonLombokAnnotationIntrospector());
System.out.println(om.writeValueAsString(tf));
TestFoo tf2 = om.readValue(om.writeValueAsString(tf), TestFoo.class);
System.out.println(tf2);
}
}
Das sind die JARs, die ich der Klasse hinzufüge:
Lombok: https://projectlombok.org/downloads/lombok.jar (Version 1.16.10)
Anmerkungen zu Jackson: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.8.2/jackson-annotations-2.8.2.jar
Jackson-Kern: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.8.2/jackson-core-2.8.2.jar
Jackson-Datenbindung: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.8.2/jackson-databind-2.8.2.jar
Jackson-lombok: http://repo1.maven.org/maven2/io/paradoxical/jackson-lombok/1.1/jackson-lombok-1.1.jar
Ich kompiliere es mit Netbeans (ich denke nicht, dass dies wirklich relevant ist, aber ich melde dies trotzdem, um es perfekt und originalgetreu reproduzierbar zu machen). Die fünf oben genannten JARs werden in einem Ordner mit dem Namen " lib
" im Projektordner gespeichert (zusammen mit " src
", " nbproject
", " test
" und " build
"). Ich habe sie Netbeans über die Schaltfläche " JAR / Ordner hinzufügen " in den Projekteigenschaften hinzugefügt und sie werden in der genauen Reihenfolge wie in der obigen Liste aufgeführt. Das Projekt ist ein Standardprojekt vom Typ "Java-Anwendung".
Darüber hinaus ist das Netbeans-Projekt so konfiguriert, dass " beim Speichern NICHT kompiliert werden ", " Debugging-Informationen generieren ", " veraltete APIs melden ", " Java-Abhängigkeiten verfolgen ", " Aktivieren von Annotationsprozessen " und " Aktivieren von Annotationsprozessen im Editor " konfiguriert werden . In Netbeans ist kein Annotationsprozessor oder keine Annotationsverarbeitungsoption explizit konfiguriert. Außerdem wird die -Xlint:all
Befehlszeilenoption " " in der Compiler-Befehlszeile übergeben, und der Compiler wird auf einer externen VM ausgeführt.
Die Version meines Java ist 1.8.0_72 und die Version meines Java ist 1.8.0_72-b15. Meine Netbeans sind 8.1.
Mein Projekt lässt sich gut kompilieren. Es wird jedoch eine Ausnahme bei der Ausführung ausgelöst. Die Ausnahme scheint nichts zu sein, was leicht oder offensichtlich reparierbar aussieht. Hier ist die Ausgabe, einschließlich der Stapelverfolgung:
TestFoo(x=b, z=5)
{"z":5,"xoom":"a"}
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Argument #0 of constructor [constructor for testelombok.TestFoo, annotations: {interface java.beans.ConstructorProperties=@java.beans.ConstructorProperties(value=[x, z]), interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}] has no property name annotation; must have name when multiple-parameter constructor annotated as Creator
at [Source: {"z":5,"xoom":"a"}; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:296)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:269)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:475)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:3890)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3785)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2833)
at testelombok.TestLombok.main(TestLombok.java:14)
Caused by: java.lang.IllegalArgumentException: Argument #0 of constructor [constructor for testelombok.TestFoo, annotations: {interface java.beans.ConstructorProperties=@java.beans.ConstructorProperties(value=[x, z]), interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}] has no property name annotation; must have name when multiple-parameter constructor annotated as Creator
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._addDeserializerConstructors(BasicDeserializerFactory.java:511)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:323)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:253)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:219)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:141)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:406)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:352)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
... 7 more
Ich habe bereits versucht, zufällig mit den @Value
und @AllArgsConstructor
Anmerkungen zu stöbern, aber ich konnte es nicht besser machen.
Ich googelte die Ausnahme und fand einen alten Fehlerbericht über Jackson und einen anderen, der offen ist, aber mit etwas anderem in Verbindung zu stehen scheint . Dies sagt jedoch immer noch nichts darüber aus, was dieser Fehler ist oder wie er behoben werden kann. Außerdem konnte ich nichts Nützliches finden, das woanders aussah.
Da ich versuche, sowohl Lombok als auch Jackson sehr einfach zu verwenden, scheint es seltsam, dass ich keine nützlicheren Informationen zur Umgehung dieses Problems finden konnte. Vielleicht habe ich etwas verpasst?
Hat jemand eine Idee, wie man das löst, außer nur zu sagen " benutze keinen Lombok " oder " benutze keinen Jackson "?
Unveränderlich + Lombok + Jackson kann auf folgende Weise erreicht werden:
import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.Value; @Value @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) @AllArgsConstructor public class LocationDto { double longitude; double latitude; } class ImmutableWithLombok { public static void main(String[] args) throws Exception { ObjectMapper objectMapper = new ObjectMapper(); String stringJsonRepresentation = objectMapper.writeValueAsString(new LocationDto(22.11, 33.33)); System.out.println(stringJsonRepresentation); LocationDto locationDto = objectMapper.readValue(stringJsonRepresentation, LocationDto.class); System.out.println(locationDto); } }
quelle
AllArgsConstructor
schon Teil der@Value
Annotation?@NoArgsConstructor
Überschreibung überschreibt den Konstruktor, der durch die@Value
Annotation generiert wird. Sie müssen also das Extra hinzufügen@AllArgsConstructor
Ich habe einige der oben genannten ausprobiert und sie waren alle temperamentvoll. Was für mich wirklich funktioniert hat, ist die Antwort, die ich hier gefunden habe .
Fügen Sie im Stammverzeichnis Ihres Projekts eine lombok.config- Datei hinzu (falls Sie dies noch nicht getan haben).
und innen einfügen
lombok.anyConstructor.addConstructorProperties=true
Dann können Sie Ihre Pojos wie folgt definieren:
@Data @AllArgsConstructor public class MyPojo { @JsonProperty("Description") private String description; @JsonProperty("ErrorCode") private String errorCode; }
quelle
Ich hatte genau das gleiche Problem, "löste" es durch Hinzufügen des
suppressConstructorProperties = true
Parameters (anhand Ihres Beispiels):@Value @Wither @AllArgsConstructor(suppressConstructorProperties = true) public class TestFoo { @JsonProperty("xoom") private String x; private int z; }
Jackson mag anscheinend die
java.beans.ConstructorProperties
Annotation, die Konstruktoren hinzugefügt wurde, nicht. DersuppressConstructorProperties = true
Parameter weist Lombok an, ihn nicht hinzuzufügen (standardmäßig).quelle
suppressConstructorProperties
ist jetzt veraltet :-(false
.@AllArgsConstructor(suppressConstructorProperties = true)
ist veraltet. Definieren Sielombok.anyConstructor.suppressConstructorProperties=true
( https://projectlombok.org/features/configuration ) und ändern Sie die Lombok-Annotation von POJO von@Value
in@Data
+@NoArgsConstructor
+@AllArgsConstructor
funktioniert für mich.quelle
Bei mir hat es funktioniert, als ich die Lombok-Version auf 'org.projectlombok: lombok: 1.18.0' aktualisiert habe.
quelle
Aus Jan Riekes Antwort
Sie benötigen für jedes Feld eine @JsonProperty, auch wenn der Name übereinstimmt. Dies ist jedoch eine gute Vorgehensweise. Sie können damit auch Ihre Felder auf ein öffentliches Finale setzen, was ich Getter vorziehe.
@ToString @EqualsAndHashCode @Wither @AllArgsConstructor(onConstructor=@__(@JsonCreator)) public class TestFoo { @JsonProperty("xoom") public final String x; @JsonProperty("z") public final int z; }
Es sollte aber auch mit Getter (+ Setter) funktionieren.
quelle
Can not deserialize instance of java.lang.String out of START_OBJECT token
... Und das hat es behoben! Ich brauche diese haben@JsonProperty
Anmerkung für jeden Konstruktorparameter und dass zusätzlich zu der@AllArgsConstructor
ermöglicht lombok zu Instrument , das in.Sie können Jackson dazu bringen, mit fast allem zu spielen, wenn Sie das "Mixin" -Muster verwenden . Grundsätzlich gibt es Ihnen die Möglichkeit, einer vorhandenen Klasse Jackson-Anmerkungen hinzuzufügen, ohne diese Klasse tatsächlich zu ändern. Ich neige dazu, es hier eher zu empfehlen als eine Lombok-Lösung, da dies ein Problem löst, das Jackson mit einer Jackson-Funktion hat, sodass es eher langfristig funktioniert.
quelle
Ich habe alle meine Klassen wie folgt kommentiert:
@JsonAutoDetect(fieldVisibility = Visibility.ANY) @JsonInclude(JsonInclude.Include.NON_DEFAULT) @Data @Accessors(fluent = true) @NoArgsConstructor @AllArgsConstructor
Es funktionierte mindestens ein paar Jahre lang mit allen Lombok- und Jackson-Versionen.
Beispiel:
@JsonAutoDetect(fieldVisibility = Visibility.ANY) @JsonInclude(JsonInclude.Include.NON_DEFAULT) @Data @Accessors(fluent = true) @NoArgsConstructor @AllArgsConstructor public class Person { String id; String first; String last; }
Und das ist es. Lombok und Jackson spielen wie ein Zauber zusammen.
quelle
@JsonInclude(JsonInclude.Include.NON_NULL) @Data public class Person { String id; String first; String last; }
Zusätzlich zur Datenklasse sollte der ObjectMapper korrekt konfiguriert sein. In diesem Fall funktioniert es mit einer ParameterNamesModule-Konfiguration und dem Festlegen der Sichtbarkeit von Feldern und Erstellungsmethoden einwandfrei
om.registerModule(new ParameterNamesModule()); om.setVisibility(FIELD, JsonAutoDetect.Visibility.ANY); om.setVisibility(CREATOR, JsonAutoDetect.Visibility.ANY);
Dann sollte es wie erwartet funktionieren.
quelle
Ich hatte Probleme damit, Lombok dazu zu bringen, die
ConstructorProperies
Anmerkung nicht hinzuzufügen, also ging ich in die andere Richtung und hinderte Jackson daran, diese Anmerkung anzusehen.Der Schuldige ist JacksonAnnotationIntrospector.findCreatorAnnotation . Beachten:
if (_cfgConstructorPropertiesImpliesCreator && config.isEnabled(MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES)
Beachten Sie auch JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator :
public JacksonAnnotationIntrospector setConstructorPropertiesImpliesCreator(boolean b) { _cfgConstructorPropertiesImpliesCreator = b; return this; }
Also zwei Optionen, entweder setzen Sie den
MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
Wert auf false oder erstellen Sie einenJacksonAnnotationIntrospector
SatzsetConstructorPropertiesImpliesCreator
auffalse
und setzen Sie diesenAnnotationIntrospector
in denObjectMapper
via ObjectMapper.setAnnotationIntrospector .Beachten Sie ein paar Dinge, ich benutze Jackson 2.8.10 und in dieser Version
MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
existiert nicht. Ich bin nicht sicher, in welcher Version von Jackson es hinzugefügt wurde. Wenn es nicht vorhanden ist, verwenden Sie denJacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator
Mechanismus.quelle
Sie benötigen auch dieses Modul. https://github.com/FasterXML/jackson-modules-java8
Aktivieren Sie dann das Flag -parameters für Ihren Compiler.
<build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin>
quelle
Ich hatte auch einen Moment damit zu kämpfen. Wenn ich jedoch die Dokumentation hier durchschaue, kann ich feststellen, dass der Annotationsparameter onConstructor als experimentell angesehen wird und auf meiner IDE (STS 4) nicht gut unterstützt wird. Laut der Jackson-Dokumentation werden private Mitglieder standardmäßig nicht (de) serialisiert. Es gibt schnelle Möglichkeiten, dies zu beheben.
Fügen Sie die JsonAutoDetect-Annotation hinzu und stellen Sie sie entsprechend ein, um geschützte / private Mitglieder zu erkennen. Dies ist praktisch für DTOs
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) public class SomeClass
Fügen Sie eine Factory-Funktion mit der Annotation @JsonCreator hinzu. Dies funktioniert am besten, wenn Sie eine Objektvalidierung oder zusätzliche Transformationen benötigen.
public class SomeClass { // some code here @JsonCreator public static SomeClass factory(/* params here dressing them in @JsonProperty annotations*/) { return new SomeClass(); } }
Natürlich können Sie den Konstruktor auch manuell in sich selbst hinzufügen.
quelle
Ich hatte ein anderes Problem und es war mit den booleschen primitiven Typen.
private boolean isAggregate;
Als Ergebnis wurde der folgende Fehler ausgegeben
Exception: Unrecognized field "isAggregate" (class
Lambok wandelt
isAggregate
sichisAggregate()
als Getter um und macht das Eigentum internaggregate
stattdessen zu LombokisAggregate
. Die Jackson-Bibliothek mag es nicht und brauchtisAggregate
stattdessen Eigentum.Ich habe den primitiven Booleschen Wert auf den Wrapper-Booleschen Wert aktualisiert, um dieses Problem zu umgehen. Es gibt andere Optionen für Sie, wenn Sie mit
boolean
Typen arbeiten, siehe die Referenz unten.Sol:
private Boolean isAggregate;
ref: https://www.baeldung.com/lombok-getter-boolean
quelle