javajacksonjson-deserialization

Jackson - @JsonTypeInfo property is being mapped as null?


Say I have the following JSON:

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

then, based on the exercise_type field, I want to instantiate different objects instances (subclasses of ExerciseResponseDTO). In order to do that, I tried creating this mix in:

@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 {}

and then the mapper ObjectMapper as follows

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

but for some reason, this test fails:

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

seems like there's an issue specifically with the exercise_type attribute that's not being mapped for some reason, since all the other fields are being mapped just fine. Any idea what could it be causing this?


Solution

  • Finally, I've found the solution in the API Doc

    Note on visibility of type identifier: by default, deserialization (use during reading of JSON) of type identifier is completely handled by Jackson, and is not passed to deserializers. However, if so desired, it is possible to define property visible = true in which case property will be passed as-is to deserializers (and set via setter or field) on deserialization.

    So the solution was simply adding the 'visible' attribute as follows

    @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  
    {}