Eksperymentuję z połączeniem Jacksona i Lomboka. To są moje zajęcia:
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);
}
}
Oto pliki JAR, które dodam do klasy:
Lombok: https://projectlombok.org/downloads/lombok.jar (wersja 1.16.10)
Adnotacje Jacksona: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.8.2/jackson-annotations-2.8.2.jar
Rdzeń Jacksona: http://repo1.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.8.2/jackson-core-2.8.2.jar
Jackson databind: 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
Kompiluję go z Netbeans (nie sądzę, że jest to naprawdę istotne, ale i tak zgłaszam to, aby było idealnie i wiernie odtwarzalne). Pięć powyższych plików JAR jest przechowywanych w folderze o nazwie „ lib
” wewnątrz folderu projektu (wraz z „ src
”, „ nbproject
”, „ test
” i „ build
”). Dodałem je do Netbeans za pomocą przycisku „ Dodaj JAR / Folder ” we właściwościach projektu i są one wymienione w dokładnej kolejności jak na powyższej liście. Projekt jest standardowym projektem typu „aplikacja Java”.
Ponadto projekt Netbeans jest skonfigurowany tak, aby „ NIE kompilować przy zapisywaniu ”, „ generować informacje o debugowaniu ”, „ raportować przestarzałe interfejsy API ”, „ śledzić zależności java ”, „ przetwarzać adnotacje aktywowane ” i „ przetwarzać adnotacje aktywowane w edytorze ”. W Netbeans nie jest jawnie konfigurowany żaden procesor ani opcja przetwarzania adnotacji. Ponadto -Xlint:all
opcja wiersza polecenia „ ” jest przekazywana w wierszu poleceń kompilatora, a kompilator działa na zewnętrznej maszynie wirtualnej.
Wersja mojego javaca to 1.8.0_72, a moja wersja java to 1.8.0_72-b15. Mój Netbeans to 8.1.
Mój projekt dobrze się kompiluje. Jednak w jej wykonaniu zgłasza wyjątek. Wyjątkiem nie wydaje się być coś, co wygląda na łatwe lub oczywiste do naprawienia. Oto wynik, w tym ślad stosu:
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
Próbowałem już losowo grzebać w adnotacjach @Value
i @AllArgsConstructor
, ale nie mogłem tego ulepszyć.
Wyszukałem w Google wyjątek i znalazłem stary raport o błędzie w serwisie Jackson i kolejny, który jest otwarty, ale wydaje się być powiązany z czymś innym . Jednak to nadal nie mówi nic o tym, czym jest ten błąd ani jak go naprawić. Poza tym nie mogłem znaleźć niczego użytecznego, szukając tego gdzie indziej.
Ponieważ to, co próbuję zrobić, to bardzo podstawowe użycie zarówno lomboka, jak i jacksona, wydaje się dziwne, że nie mogłem znaleźć żadnych bardziej przydatnych informacji o tym, jak obejść ten problem. Może coś przegapiłem?
Oprócz powiedzenia „ nie używaj lomboka ” lub „ nie używaj jackson ”, czy ktoś ma jakiś pomysł, jak to rozwiązać?
Immutable + Lombok + Jackson można osiągnąć w następujący sposób:
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); } }
źródło
AllArgsConstructor
już częścią@Value
adnotacji?@NoArgsConstructor
nadpisuje konstruktor, który jest generowany przez@Value
adnotację, więc musisz dodać dodatkowy@AllArgsConstructor
Wypróbowałem kilka z powyższych i wszystkie były temperamentne. To, co naprawdę zadziałało, to odpowiedź, którą tutaj znalazłem .
w katalogu głównym projektu dodaj plik lombok.config (jeśli jeszcze tego nie zrobiłeś)
i wklej to
lombok.anyConstructor.addConstructorProperties=true
Następnie możesz zdefiniować swoje pojos w następujący sposób:
@Data @AllArgsConstructor public class MyPojo { @JsonProperty("Description") private String description; @JsonProperty("ErrorCode") private String errorCode; }
źródło
Miałem dokładnie ten sam problem, „rozwiązałem” go poprzez dodanie
suppressConstructorProperties = true
parametru (na przykładzie):@Value @Wither @AllArgsConstructor(suppressConstructorProperties = true) public class TestFoo { @JsonProperty("xoom") private String x; private int z; }
Jackson najwyraźniej nie lubi
java.beans.ConstructorProperties
adnotacji dodanej do konstruktorów.suppressConstructorProperties = true
Parametr mówi Lombok nie je dodać (robi domyślnie).źródło
suppressConstructorProperties
jest teraz przestarzała :-(false
.@AllArgsConstructor(suppressConstructorProperties = true)
jest przestarzałe. Zdefiniujlombok.anyConstructor.suppressConstructorProperties=true
( https://projectlombok.org/features/configuration ) i zmień adnotację lombok POJO z@Value
na@Data
+@NoArgsConstructor
+@AllArgsConstructor
działa dla mnie.źródło
U mnie zadziałało, gdy zaktualizowałem wersję lombok do: „org.projectlombok: lombok: 1.18.0”
źródło
Z odpowiedzi Jana Rieke
Będziesz potrzebować @JsonProperty na każdym polu, nawet jeśli nazwa pasuje, ale i tak jest to dobra praktyka. Możesz także ustawić swoje pola jako publiczne ostateczne, używając tego, co wolę od metod pobierających.
@ToString @EqualsAndHashCode @Wither @AllArgsConstructor(onConstructor=@__(@JsonCreator)) public class TestFoo { @JsonProperty("xoom") public final String x; @JsonProperty("z") public final int z; }
Powinien jednak działać również z pobierającymi (+ ustawiającymi).
źródło
Can not deserialize instance of java.lang.String out of START_OBJECT token
... I to naprawiło! Muszę mieć tę@JsonProperty
adnotację dla każdego parametru konstruktora, a ten dodatek do@AllArgsConstructor
pozwala lombokowi na instrumentowanie.Możesz zmusić Jacksona do grania niemal wszystkim, jeśli użyjesz jego schematu „mieszania” . Zasadniczo umożliwia dodawanie adnotacji Jacksona do istniejącej klasy bez faktycznego modyfikowania tej klasy. Skłaniam się ku poleceniu go tutaj, a nie rozwiązania Lombok, ponieważ rozwiązuje to problem Jacksona z funkcją Jacksona, więc jest bardziej prawdopodobne, że będzie działać długoterminowo.
źródło
Wszystkie moje zajęcia mają następującą adnotację:
@JsonAutoDetect(fieldVisibility = Visibility.ANY) @JsonInclude(JsonInclude.Include.NON_DEFAULT) @Data @Accessors(fluent = true) @NoArgsConstructor @AllArgsConstructor
Działał ze wszystkimi wersjami Lomboka i Jacksona przynajmniej przez kilka lat.
Przykład:
@JsonAutoDetect(fieldVisibility = Visibility.ANY) @JsonInclude(JsonInclude.Include.NON_DEFAULT) @Data @Accessors(fluent = true) @NoArgsConstructor @AllArgsConstructor public class Person { String id; String first; String last; }
I to wszystko. Lombok i Jackson grają razem jak urok.
źródło
@JsonInclude(JsonInclude.Include.NON_NULL) @Data public class Person { String id; String first; String last; }
Oprócz klasy danych należy poprawnie skonfigurować ObjectMapper. W tym przypadku działa dobrze z konfiguracją ParameterNamesModule i ustawieniem widoczności pól i metod twórcy
om.registerModule(new ParameterNamesModule()); om.setVisibility(FIELD, JsonAutoDetect.Visibility.ANY); om.setVisibility(CREATOR, JsonAutoDetect.Visibility.ANY);
Wtedy powinno działać zgodnie z oczekiwaniami.
źródło
Miałem problemy z tym, że Lombok nie dodawał
ConstructorProperies
adnotacji, więc poszedłem w drugą stronę i uniemożliwiłem Jacksonowi przeglądanie tej adnotacji.Winowajcą jest JacksonAnnotationIntrospector.findCreatorAnnotation . Ogłoszenie:
if (_cfgConstructorPropertiesImpliesCreator && config.isEnabled(MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES)
Zwróć także uwagę na JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator :
public JacksonAnnotationIntrospector setConstructorPropertiesImpliesCreator(boolean b) { _cfgConstructorPropertiesImpliesCreator = b; return this; }
Więc dwie opcje, albo ustawić
MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
na false lub utworzyćJacksonAnnotationIntrospector
zestawsetConstructorPropertiesImpliesCreator
dofalse
i ustawić tenAnnotationIntrospector
Into theObjectMapper
poprzez ObjectMapper.setAnnotationIntrospector .Zauważ kilka rzeczy, używam Jacksona 2.8.10 iw tej wersji
MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
nie istnieje. Nie jestem pewien, w której wersji Jacksona został dodany. Jeśli więc go tam nie ma, użyjJacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator
mechanizmu.źródło
Musisz też mieć ten moduł. https://github.com/FasterXML/jackson-modules-java8
następnie włącz flagę -parameters dla swojego kompilatora.
<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>
źródło
Z tym też przez chwilę walczyłem. Ale przeglądając dokumentację tutaj , widzę, że parametr adnotacji onConstructor jest uważany za eksperymentalny i nie jest dobrze obsługiwany w moim IDE (STS 4). Zgodnie z dokumentacją Jacksona prywatni członkowie nie są domyślnie (de) serializowani. Istnieją szybkie sposoby rozwiązania tego problemu.
Dodaj adnotację JsonAutoDetect i ustaw ją odpowiednio, aby wykrywać chronione / prywatne elementy członkowskie. Jest to wygodne dla DTO
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) public class SomeClass
Dodaj funkcję fabryczną z adnotacją @JsonCreator, działa to najlepiej, jeśli potrzebujesz walidacji obiektu lub dodatkowych przekształceń.
public class SomeClass { // some code here @JsonCreator public static SomeClass factory(/* params here dressing them in @JsonProperty annotations*/) { return new SomeClass(); } }
Oczywiście możesz również ręcznie dodać konstruktora w sobie.
źródło
Miałem inny problem i dotyczyło to prymitywnych typów logicznych.
private boolean isAggregate;
W rezultacie generował następujący błąd
Exception: Unrecognized field "isAggregate" (class
Nawróceni Lambok
isAggregate
doisAggregate()
jako przebojowa dokonywania właściwość wewnętrznie Lombok jakaggregate
zamiastisAggregate
. Bibliotece Jacksona się to nie podoba iisAggregate
zamiast tego potrzebuje własności.Zaktualizowałem prymitywną wartość logiczną do Wrapper Boolean, aby obejść ten problem. Jeśli masz do czynienia z
boolean
typami, istnieją inne opcje , patrz odniesienie poniżej.Sol:
private Boolean isAggregate;
ref: https://www.baeldung.com/lombok-getter-boolean
źródło