jscherman jscherman - 11 days ago 5
Java Question

Jackson - @JsonTypeInfo property is being mapped as null?

I am dealing with this problem. Let's say 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 {}


Ok, then 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, that exercise_type attribute that i am using as property on
@JsonTypeInfo
is being mapped as null. I've seen this possibly related question but i don't have generics in my case so it didn't fix my problem.

Any idea how i can solve this?

Answer

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.

Comments