Suppose I have the following Java class:
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Demo {
public int x;
public int y;
public List<Pair<Integer, Integer>> the_list;
}
I would like to populate it from e.g. the following json format:
{ "x" : 1,
"y" : 2,
"the_list" : [[1,2],[3,4]]}
using a fasterxml
ObjectMapper mapper = new ObjectMapper();
I can probably get there invoking mapper.readTree(json) and fill in everything I need. The problem is that the actual class I have (not the Demo) contains a lot of parameters and I would like to benefit from the databind capabilities.
Trying a plain:
mapper.readValue(json, Demo.class)
gives the following error:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of
org.apache.commons.lang3.tuple.Pair, problem: abstract types either need to be mapped to
concrete types, have custom deserializer, or be instantiated with additional type
information
Is there a way to mix custom parsing with databind? I looked through the annotations but did not find anything that suited the purpose (I could not get mixins to work with generics, a custom setter for the_list was not invoked probably because it's a list, a JsonCreator is not an option as I did not write the Pair class ...).
You should write a custom serializer/deserializer for the Pair class.
Here is an example:
public class JacksonPair {
static final String JSON = "{ \"x\" : 1, \n" +
" \"y\" : 2, \n" +
" \"the_list\" : [[1,2],[3,4]]}";
static class Demo {
public int x;
public int y;
public List<Pair<Integer, Integer>> the_list;
@Override
public String toString() {
return "Demo{" +
"x=" + x +
", y=" + y +
", the_list=" + the_list +
'}';
}
}
static class PairSerializer extends JsonSerializer<Pair> {
@Override
public void serialize(
Pair pair,
JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartArray(2);
jsonGenerator.writeObject(pair.getLeft());
jsonGenerator.writeObject(pair.getRight());
jsonGenerator.writeEndArray();
}
}
static class PairDeserializer extends JsonDeserializer<Pair> {
@Override
public Pair deserialize(
JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException {
final Object[] array = jsonParser.readValueAs(Object[].class);
return Pair.of(array[0], array[1]);
}
}
public static void main(String[] args) throws IOException {
final SimpleModule module = new SimpleModule();
module.addSerializer(Pair.class, new PairSerializer());
module.addDeserializer(Pair.class, new PairDeserializer());
final ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
final Demo demo = objectMapper.readValue(JSON, Demo.class);
System.out.println("toString: " + demo);
System.out.println("Input: " + JSON);
System.out.println("Output: " + objectMapper.writeValueAsString(demo));
}
}
Output:
toString: Demo{x=1, y=2, the_list=[(1,2), (3,4)]}
Input: { "x" : 1,
"y" : 2,
"the_list" : [[1,2],[3,4]]}
Output: {"x":1,"y":2,"the_list":[[1,2],[3,4]]}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With