113 votes

Impossible de construire une instance de - Jackson

J'utilise Jackson et j'ai des problèmes. Lorsque j'essaie de désérialiser un objet, j'obtiens l'erreur suivante :

com.fasterxml.jackson.databind.JsonMappingException: 
    Can not construct instance of net.MyAbstractClass, 
    problem: abstract types either need to be mapped to concrete types, 
        have custom deserializer, or be instantiated with additional type information

J'ai des problèmes dans l'attribut :

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT, property = "@id")
@JsonSubTypes({ @JsonSubTypes.Type(value = MyAbstractClass.class, name = "MyAbstractClass") })
@ManyToOne
private MyAbstractClass object;

Quelqu'un peut-il m'aider ?

74voto

jlabedo Points 1028

Vous ne pouvez pas instancier une classe abstraite, Jackson non plus. Vous devez donner à Jackson des informations sur la manière d'instancier MaClasseAbstraite avec un type concret.

Voir cette réponse sur stackoverflow : Bibliothèque Jackson JSON : comment instancier une classe contenant des champs abstraits ?

Et peut-être aussi voir Désérialisation polymorphe de Jackson

30voto

Gabriel Andrade Points 398

J'ai eu ce problème en utilisant la méthode de lombok. @Data y @Builder annotations seules, que j'ai remplacées par :

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder

Et ça a résolu mon problème.

20voto

Asif Points 167

Vous devez utiliser une classe concrète et non une classe abstraite lors de la désérialisation. Si la classe abstraite a plusieurs implémentations, alors, dans ce cas, vous pouvez l'utiliser comme ci-dessous-

  @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes({ 
      @Type(value = Bike.class, name = "bike"), 
      @Type(value = Auto.class, name = "auto"), 
      @Type(value = Car.class, name = "car")
    })
    public abstract class Vehicle {
        // fields, constructors, getters, setters
    }

6voto

StaxMan Points 34626

Votre @JsonSubTypes n'a pas de sens : elle doit lister les (sous-)classes d'implémentation, PAS la classe elle-même (ce qui serait inutile). Vous devez donc modifier cette entrée pour lister les sous-classes qu'il y a ; ou utiliser un autre mécanisme pour enregistrer les sous-classes ( SimpleModule a quelque chose comme addAbstractTypeMapping ).

5voto

ACV Points 5246

Dans votre exemple concret, le problème est que vous n'utilisez pas cette construction correctement :

@JsonSubTypes({ @JsonSubTypes.Type(value = MyAbstractClass.class, name = "MyAbstractClass") })

@JsonSubTypes.Type doit contenir les sous-types réels non abstraits de votre classe abstraite.

Par conséquent, si vous avez :

abstract class Parent et les sous-classes concrètes

Ch1 extends Parent y Ch2 extends Parent

Votre annotation devrait alors ressembler à ceci :

@JsonSubTypes({ 
          @JsonSubTypes.Type(value = Ch1.class, name = "ch1"),
          @JsonSubTypes.Type(value = Ch2.class, name = "ch2")
})

Aquí name doit correspondre à la valeur de votre "discriminateur" :

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, 
include = JsonTypeInfo.As.WRAPPER_OBJECT, 
property = "type")

dans le property ici, il est égal à type . Donc type sera la clé et la valeur que vous avez définie dans le champ name sera la valeur.

Par conséquent, lorsque la chaîne json arrive si elle a cette forme :

{
 "type": "ch1",
 "other":"fields"
}

Jackson le convertira automatiquement en un Ch1 classe.

Si vous envoyez ça :

{
 "type": "ch2",
 "other":"fields"
}

Vous obtiendrez un Ch2 instance.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X