Jackson - @JsonTypeInfo property is being mapped as null?
JavaJacksonJson DeserializationJava Problem Overview
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?
Java Solutions
Solution 1 - Java
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.
Solution 2 - Java
As per @jscherman answer by setting, 'visible' true in JsonTypeInfo will help in accessing exercise_type as a field.
If you use the same class to serialize also then resulting JSON will have exercise_type appear twice. So it's better to also update include to JsonTypeInfo.As.EXISTING_PROPERTY
And it's also worth looking at all other options for include.