web-dev-qa-db-fra.com

Jackson - La propriété @JsonTypeInfo est mappée comme nulle?

Je fais face à ce problème. Disons que j'ai cette réponse:

{  
    "id":"decaa828741611e58bcffeff819cdc9f",
    "statement":"question statement",
    "exercise_type":"QUESTION"
}

Ensuite, basé sur type_exercice attribut, je veux instancier différentes instances d'objets (sous-classes de ExerciseResponseDTO), donc je crée ce mélange dans:

@JsonTypeInfo(  
    use = JsonTypeInfo.Id.NAME,  
    include = JsonTypeInfo.As.PROPERTY,  
    property = "exercise_type")  
@JsonSubTypes({  
    @Type(value = ExerciseChoiceResponseDTO.class, name = "CHOICE"),  
    @Type(value = ExerciseQuestionResponseDTO.class, name = "QUESTION")})  
public abstract class ExerciseMixIn  
{}  

public abstract class ExerciseResponseDTO {

    private String id;
    private String statement;
    @JsonProperty(value = "exercise_type") private String exerciseType;

    // Getters and setters 
}

public class ExerciseQuestionResponseDTO
    extends ExerciseResponseDTO {}

public class ExerciseChoiceResponseDTO
    extends ExerciseResponseDTO {}

Donc je crée mon ObjectMapper comme suit

ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(ExerciseResponseDTO.class, ExerciseMixIn.class);

Mon test:

ExerciseResponseDTO exercise = mapper.readValue(serviceResponse, ExerciseResponseDTO.class)
Assert.assertTrue(exercise.getClass() == ExerciseQuestionResponseDTO.class); // OK
Assert.assertEquals("decaa828741611e58bcffeff819cdc9f" exercise.getId()); // OK
Assert.assertEquals("question statement", exercise.getStatement()); // OK
Assert.assertEquals("QUESTION", exercise.getExerciseType()); // FAIL. Expected: "QUESTION", actual: null 

Le problème est que, pour une raison quelconque, l'attribut exerc_type utilisé comme propriété sur @JsonTypeInfo est mappé comme null. Une idée comment je peux résoudre ce problème?

40
jscherman

Enfin, j'ai trouvé la solution dans le API Doc

Remarque sur la visibilité de l'identifiant de type: par défaut, la désérialisation (à utiliser lors de la lecture de JSON) de l'identifiant de type est entièrement gérée par Jackson et n'est pas transmise aux désérialiseurs. Cependant, si vous le souhaitez, il est possible de définir la propriété visible = true, auquel cas la propriété sera transmise telle quelle aux désérialiseurs (et définie via setter ou field) lors de la désérialisation.

La solution consistait donc simplement à ajouter l'attribut ' visible ' comme suit

@JsonTypeInfo(  
    use = JsonTypeInfo.Id.NAME,  
    include = JsonTypeInfo.As.PROPERTY,  
    property = "exercise_type",
    visible = true)  
@JsonSubTypes({  
    @Type(value = ExerciseChoiceResponseDTO.class, name = "CHOICE"),  
    @Type(value = ExerciseQuestionResponseDTO.class, name = "QUESTION")})  
public abstract class ExerciseMixIn  
{}  

J'espère que ceci aide quelqu'un d'autre.

77
jscherman

Selon @ réponse jscherman en définissant, 'visible' true dans JsonTypeInfo aidera à accéder à exerced_type en tant que champ.

Si vous utilisez également la même classe pour sérialiser, le JSON résultant affichera exercice_type deux fois. Il est donc préférable de mettre également à jour l'inclusion vers JsonTypeInfo.As.EXISTING_PROPERTY

Et cela vaut également la peine de regarder toutes les autres options pour inclure.

3
Shashank