Jackson - @JsonTypeInfo property is being mapped as null?

jscherman picture jscherman · Nov 9, 2015 · Viewed 30.3k times · Source

I have this response:

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

Then, based on exercise_type attribute, I want to instantiate different objects instances (subclasses of ExerciseResponseDTO), so I create 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 {}

So I create my ObjectMapper as follows

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

My 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 

The problem is that, for some reason, the exercise_type attribute being used as property on @JsonTypeInfo is being mapped as null. Any idea how i can solve this?

Answer

jscherman picture jscherman · Nov 9, 2015

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

Hope this helps someone else.