-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
I have a use case (described also in this Stackoverflow question: http://stackoverflow.com/questions/30264115/how-to-use-jackson-deserializer-converter-correctly) where I would like to implement custom parsing for string values into types based on a legacy parser. I implemented a converter extending StdConverter
that takes a string and runs my legacy parser to parse it in my desired type. I then tried to use @JsonDeserialize
with converter
argument.
This works when my field is a concrete class. But if my field is declared to be of an abstract type, even if the converter correctly returns a concrete instance, I get an exception.
More specifically, in the test case below, I would expect both testNonAbstractTypeDeserialization
and testAbstractTypeDeserialization
to pass, because they use very similar converters. But in practice (Jackson 2.5.0) testNonAbstractTypeDeserialization
passes, and testAbstractTypeDeserialization
fails with the following exception:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of JacksonTest$AbstractCustomType, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
at [Source: {"customField": "customString"}; line: 1, column: 2]
The JUnit test case is below
import java.io.IOException;
import org.junit.Test;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.databind.util.Converter;
import com.fasterxml.jackson.databind.util.StdConverter;
import static org.junit.Assert.*;
public class JacksonTest {
public static abstract class AbstractCustomType {
private final String value;
public AbstractCustomType(String v) {
this.value = v;
}
}
public static class ConcreteCustomType extends AbstractCustomType {
public ConcreteCustomType(String v) {
super(v);
}
}
public static class AbstractCustomTypeDeserializationConverter extends StdConverter<String, AbstractCustomType>{
@Override
public AbstractCustomType convert(String arg) {
return new ConcreteCustomType(arg);
}
}
public static class AbstractCustomTypeUser {
@JsonProperty
@JsonDeserialize(converter = AbstractCustomTypeDeserializationConverter.class)
private final AbstractCustomType customField;
@JsonCreator AbstractCustomTypeUser(@JsonProperty("customField") AbstractCustomType customField) {
this.customField = customField;
}
}
public static class NonAbstractCustomType {
private final String value;
public NonAbstractCustomType(String v) {
this.value = v;
}
}
public static class NonAbstractCustomTypeDeserializationConverter extends StdConverter<String, NonAbstractCustomType>{
@Override
public NonAbstractCustomType convert(String arg) {
return new NonAbstractCustomType(arg);
}
}
public static class NonAbstractCustomTypeUser {
@JsonProperty
@JsonDeserialize(converter = NonAbstractCustomTypeDeserializationConverter.class)
private final NonAbstractCustomType customField;
@JsonCreator NonAbstractCustomTypeUser(@JsonProperty("customField") NonAbstractCustomType customField) {
this.customField = customField;
}
}
private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
@Test
public void testAbstractTypeDeserialization() throws IOException {
String test="{\"customField\": \"customString\"}";
AbstractCustomTypeUser cu = JSON_MAPPER.readValue(test, AbstractCustomTypeUser.class);
assertNotNull(cu);
}
@Test
public void testNonAbstractDeserialization() throws IOException {
String test="{\"customField\": \"customString\"}";
NonAbstractCustomTypeUser cu = JSON_MAPPER.readValue(test, NonAbstractCustomTypeUser.class);
assertNotNull(cu);
}
}