web-dev-qa-db-fra.com

Lombok 1.18.0 et Jackson 2.9.6 ne fonctionnent pas ensemble

La désérialisation échoue après la mise à jour.

J'ai mis à jour mon micro-service de Spring 1.5.10.RELEASE à Spring 2.0.3.RELEASE ainsi que la variable lombok de 1.16.14 à 1.18.0 et jackson-datatype-jsr310 de 2.9.4 à 2.9.6.

La chaîne JSON -

{"heading":"Validation failed","detail":"field must not be null"}

La classe -

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorDetail {

   private final String heading;
   private final String detail;
   private String type;
}

Appel de méthode -

ErrorDetail errorDetail = asObject(jsonString, ErrorDetail.class);

La méthode utilisée pour désérialiser -

import com.fasterxml.jackson.databind.ObjectMapper;
// more imports and class defination.

private static <T> T asObject(final String str, Class<T> clazz) {
    try {
        return new ObjectMapper().readValue(str, clazz);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

Erreur - 

Java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.foo.bar.ErrorDetail` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"heading":"Validation failed","detail":"field must not be null"}"; line: 1, column: 2]
4
JHS

Lombok a cessé de générer @ConstructorProperties sur les constructeurs avec la version 1.16.20 (voir changelog ), car cela risquerait de casser les applications Java 9+ utilisant des modules. Cette annotation contient les noms des paramètres du constructeur (ils sont supprimés lors de la compilation de la classe. Il s'agit donc d'une solution de contournement permettant de récupérer les noms de paramètres à l'exécution). L'annotation n'étant plus générée par défaut, Jackson ne peut pas mapper les noms de champs sur les paramètres du constructeur.

Solution 1: Utilisez un @NoArgsConstructor et un @Setter, mais vous perdrez l'immuabilité (si c'est important pour vous).

Mise à jour: Seulement @NoArgsConstructor et @Getter (sans @Setter) peuvent également fonctionner (car INFER_PROPERTY_MUTATORS=true ). De cette manière, vous pouvez garder la classe immuable, du moins à partir de code normal (non réfléchissant).

Solution 2: Configurez lombok pour générer à nouveau les annotations, à l'aide d'un fichier lombok.config contenant la ligne lombok.anyConstructor.addConstructorProperties = true. (Si vous utilisez des modules, assurez-vous que Java.desktop se trouve sur le chemin de votre module.)

Solution 3: Utilisez la prise en charge du générateur de Jackson en combinaison avec le @Builder de lombok, comme décrit par ici .

12
Jan Rieke

Vous voulez désérialiser une classe qui a un champ final. vous devez donc déclarer un constructeur qui contient le champ final à désérialiser.

@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorDetail {

private final String heading;
private final String detail;
private String type;

@JsonCreator
public ErrorDetail(@JsonProperty("heading") String heading, @JsonProperty("detail") String detail) {
    this.heading = heading;
    this.detail = detail;
}
}

et lorsque la désérialisation avec mappeur doit/ MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS définir cette propriété false .

private static <T> T asObject(final String str, Class<T> clazz) {
    try {
        return new ObjectMapper().configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS,false).readValue(str, clazz);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
1
sajib

Utiliser l'annotation @Data est à mon avis une mauvaise approche . S'il vous plaît changez @Data en @Getting, @Setter, @EqualsAndHashcode et ainsi de suite ..

et écrivez ici s'il vous plaît, si cela vous aidera.

mettre à jour

Je suggère que @Data crée @RequiredArgsConstructor et que ce soit constructeur avec les champs finaux, et sans private String type;

0
lord_hokage