web-dev-qa-db-de.com

Ohne den Standardkonstruktor kann ObjectMapper nach dem Upgrade auf Spring Boot 2 nicht deserialisiert werden

Ich habe folgende DTOs:

@Value
public class PracticeResults {
    @NotNull
    Map<Long, Boolean> wordAnswers;
}

@Value
public class ProfileMetaDto {

    @NotEmpty
    String name;
    @Email
    String email;
    @Size(min = 5)
    String password;
}

@Value ist eine Lombok-Annotation, die einen Konstruktor generiert. Das bedeutet, dass diese Klasse keinen Konstruktor ohne Argumente hat.

Ich habe Spring Boot 1.4.3.RELEASE verwendet und ObjectMapper Bean konnte ein solches Objekt von json deserialisieren.

Nach dem Upgrade auf Spring Boot 2.0.0.M7 erhalte ich folgende Ausnahme:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of PracticeResults (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

Die in Spring Boot 1.4.3 verwendete Jackson-Version ist 2.8.10 und für Spring Boot 2.0.0.M7 ist 2.9.2.

Ich habe versucht, dieses Problem zu googeln, aber nur Lösungen mit @JsonCreator oder @JsonProperty gefunden.

Warum funktioniert es mit Spring Boot 1.4.3 und schlägt mit Spring Boot 2 fehl? Ist es möglich, das Bean so zu konfigurieren, dass es sich genauso verhält wie die ältere Version?

15
solomkinmv

Aufgrund von Änderungen in Lombok Version 1.16.20 müssen Sie die folgende Eigenschaft in Ihrer lombok.config-Datei festlegen (wenn Sie diese Datei nicht haben, können Sie sie im Projektstammverzeichnis erstellen):

lombok.anyConstructor.addConstructorProperties=true

Dies ist im Lombok-Änderungsprotokoll beschrieben: https://projectlombok.org/changelog .

Danach sollte der @Value wieder von Jackson akzeptiert werden.

Sie können daran interessiert sein, die diesbezügliche GitHub-Ausgabe zu verfolgen: https://github.com/rzwitserloot/lombok/issues/1563

23
Tobias

Eine weitere Möglichkeit, dieses Problem zu lösen. Verwenden Sie das Jackson Parameternamensmodul , das standardmäßig in Spring Boot 2 enthalten ist. Danach kann Jackson Objekte deserialisieren. Es funktioniert jedoch nur, wenn Sie mehr als 1 Eigenschaft in object haben. Bei einer einzelnen Eigenschaft erhalte ich folgende Fehlermeldung:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `SomeClassName` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

Wegen der folgenden:

Markierungsanmerkung, mit der Konstruktoren und Factory-Methoden definiert werden können, um neue Instanzen der zugeordneten Klasse zu instanziieren.

HINWEIS: Wenn Sie Erstellermethoden (Konstruktoren, Factory-Methoden) kommentieren, muss die Methode entweder Folgendes sein:

  • Konstruktor-/Factory-Methode mit einem Argument ohne JsonProperty-Anmerkung für das Argument: Wenn dies der Fall ist, handelt es sich um einen sogenannten "Delegate Creator". In diesem Fall bindet Jackson JSON zuerst an den Typ des Arguments und ruft dann Creator auf. Dies wird häufig in Verbindung mit JsonValue (zur Serialisierung) verwendet.
  • Konstruktor/Factory-Methode, bei der jedes -Argument entweder mit JsonProperty oder JacksonInject versehen wird, um den Namen der Eigenschaft anzugeben, an die die Bindung erfolgen soll

Beachten Sie außerdem, dass alle JsonProperty-Anmerkungen den tatsächlichen Namen angeben müssen (NICHT leere Zeichenfolge für "Standard"), es sei denn, Sie verwenden Erweiterungsmodule, die den Parameternamen erkennen können. Dies ist darauf zurückzuführen, dass JDK-Standardversionen vor 8 nicht in der Lage waren, Parameternamen aus dem Bytecode zu speichern bzw. abzurufen. Bei JDK 8 (oder bei der Verwendung von Hilfsbibliotheken wie Paranamer oder anderen JVM-Sprachen wie Scala oder Kotlin) ist die Angabe des Namens jedoch optional. 

Um diesen Fall mit Lombok zu behandeln, habe ich folgende Problemumgehung verwendet:

@Value
@AllArgsConstructor(onConstructor = @__(@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)))
class SomeClassName {...}
1
solomkinmv

Ich habe die Lombok-Version auf 'org.projectlombok: lombok: 1.18.0' aktualisiert und es hat für mich funktioniert.

0
fascynacja