问题
I am trying to write a custom deserializer in order to trim down a big set of data I receive from somewhere else. I return a List of custom objects from the deserializer.
My question is, how do I do that, if this is my custom deserializer :
public class MyCustomDeserializer extends JsonDeserializer<List<CustomClass>> { ... }
I certainly can't do this :
final SimpleModule module = new SimpleModule();
module.addDeserializer(List<CustomClass>.class, new MyCustomDeserializer());
Will something like this work ?
final List<CustomClass> response = Arrays.asList(objectMapper.readValue(stringBean, CustomClass[].class));
If this indeed works, I find it a bit confusing and "dangerous" ? Isn't the deserialization done inside the asList method invocation ? So it basically maps a List to an array[] ?
I learned about TypeReference so I can probably use that like so :
objectMapper.readValue(stringBean, new TypeReference<List<CustomClass>>(){});
but I heard it is slower.
I also don't want to create a container for the list, and return that in the deserialization because that means it will be wrapped in another json object, and I simply want my endpoint to produce something like :
[{object1}, {object2}]
// instead of
{"Output" : [{object1}, {object2}]}
EDIT:
It seems that I have misinterpreted how jackson is using my deserializer in both cases :
final List<CustomClass> response = Arrays.asList(objectMapper.readValue(stringBean, CustomClass[].class));
// or
objectMapper.readValue(stringBean, new TypeReference<List<CustomClass>>(){});
It looks like the deserializer is called twice, once for each object in the array. I thought that the entire array would be considered as a whole. To clear the confusion, here is what I mean:
The json I receive and try to deserialize looks like so :
[
{
"Data" : {
"id" : "someId",
"otherThing" : "someOtherThing"
},
"Message" : "OK"
},
{
"Data" : null,
"Message" : "Object not found for id blabla"
}
]
and so I though this is what I would have inside my deserializer, but as I said before it seems that i actually get each "entry" from that array and call it multiple times.
回答1:
First of all, If you registered your custom deserializer using annotation on the bean CustomClass
then the deserializer should handle one instance of CustomClass
and not a collection and thus should be defined:
public class MyCustomDeserializer extends JsonDeserializer<CustomClass> {
@Override
public CustomClass deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException
{
...
}
}
and now you can use Jackson's type factory to pass the mapper the required type information
JavaType customClassCollection = objectMapper.getTypeFactory().constructCollectionType(List.class, CustomClass.class);
List<CustomClass> beanList = (List<CustomClass>)objectMapper.readValue(stringBean, customClassCollection);
回答2:
I worked it out by adding a custom deserializer to an attribute in my model class and using JsonDeserialize annotation's contentUsing()
method, like so:
@JsonDeserialize(contentUsing = MyCustomDeserializer.class)
private List<CustomClass> customClassObjList;
where MyCustomDeserializer class is a custom Jackson JSON deserializer defined as:
public class MyCustomDeserializer extends JsonDeserializer<CustomClass> {
@Override
public CustomClass deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
...
}
}
来源:https://stackoverflow.com/questions/34176607/custom-deserialization-of-list-using-jackson