web-dev-qa-db-fra.com

ObjectMapper ne peut pas désérialiser sans constructeur par défaut après la mise à niveau vers Spring Boot 2

J'ai les DTO suivants:

@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 est une annotation de Lombok qui génère un constructeur. Ce qui signifie que cette classe n'a pas de constructeur no-arg.

J'ai utilisé Spring Boot 1.4.3.RELEASE et le bean ObjectMapper était capable de désérialiser un tel objet depuis json.

Après la mise à niveau vers Spring Boot 2.0.0.M7, je reçois l'exception suivante:

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)

La version de Jackson utilisée dans Spring Boot 1.4.3 est 2.8.10 et pour Spring Boot 2.0.0.M7 est 2.9.2.

J'ai essayé de Google ce problème mais n'ai trouvé que des solutions avec @JsonCreator ou @JsonProperty.

Alors, pourquoi cela fonctionne-t-il avec Spring Boot 1.4.3 et échoue-t-il avec Spring Boot 2? Est-il possible de configurer Bean pour qu'il se comporte de la même manière que l'ancienne version?

15
solomkinmv

En raison des modifications importantes apportées à la version 1.16.20 de Lombok, vous devez définir la propriété suivante dans votre fichier lombok.config (si vous ne l'avez pas, vous pouvez le créer à la racine du projet):

lombok.anyConstructor.addConstructorProperties=true

Ceci est décrit dans le journal des modifications de Lombok: https://projectlombok.org/changelog .

Après cela, la @Value devrait être à nouveau acceptée par Jackson.

Vous pouvez être intéressé par le problème lié à GitHub ici: https://github.com/rzwitserloot/lombok/issues/1563

23
Tobias

Une autre façon de résoudre ce problème. Utilisez le module Jackson noms de paramètres , inclus par défaut dans Spring Boot 2. Après cela, Jackson peut désérialiser des objets. Mais cela ne fonctionne que si vous avez plus d'une propriété dans object. Dans le cas d'une propriété unique, le message d'erreur suivant s'affiche:

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)

Pour les raisons suivantes:

Les annotations de marqueur peuvent être utilisées pour définir les constructeurs et les méthodes de fabrique comme méthodes à utiliser pour instancier de nouvelles instances de la classe associée.

REMARQUE: lorsque vous annotez des méthodes de création (constructeurs, méthodes d'usine), la méthode doit être:

  • Méthode constructeur/fabrique à un seul argument sans l'annotation JsonProperty pour l'argument: si tel est le cas, il s'agit du "créateur du délégué", auquel cas Jackson associe d'abord JSON au type de l'argument, puis appelle creator. Ceci est souvent utilisé avec JsonValue (utilisé pour la sérialisation).
  • Méthode constructeur/fabrique dans laquelle chaque argument est annoté avec JsonProperty ou JacksonInject, pour indiquer le nom de la propriété à laquelle se lier

Notez également que toutes les annotations JsonProperty doivent spécifier le nom réel (NON une chaîne vide pour "défaut"), sauf si vous utilisez l'un des modules d'extension capables de détecter le nom du paramètre; Cela parce que les versions JDK par défaut antérieures à 8 n'ont pas été en mesure de stocker et/ou d'extraire les noms de paramètres à partir de bytecode. Mais avec JDK 8 (ou à l'aide de bibliothèques auxiliaires telles que Paranamer ou d'autres langages JVM tels que Scala ou Kotlin), la spécification du nom est facultative. 

Pour résoudre ce problème avec Lombok, j’ai utilisé la solution suivante:

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

J'ai mis à jour la version de lombok vers: 'org.projectlombok: lombok: 1.18.0' et cela a fonctionné pour moi.

0
fascynacja