Java – deserialization error handling
My question is simple: I have the following simple classes:
public class Foo {
private int id = -1;
public void setId(int _id){ this.id = _id; }
public int getId(){ return this.id; }
}
I'm trying to handle the following JSON:
{
"id": "blah"
}
Obviously, there is a problem ("blah" cannot be resolved to int)
Before, Jackson threw something like org codehaus. jackson. map. Things like jsonmappingexception: you can't construct Java from string value 'blah' Instance of lang. integer: not a valid integer value
I agree with this, but I think somewhere it is allowed to ignore this type of mapping error I tried to register with a deserializationproblemhandler (see here), but it seems to apply only to unknown attributes rather than deserialization problems
Do you have any clues about this problem?
Solution
I successfully solved my problem. Thank you Tatu from Jackson ml
I had to use a custom non blocking deserializer for each primitive type processed in Jackson Factories like this:
public class JacksonNonBlockingObjectMapperFactory {
/**
* Deserializer that won't block if value parsing doesn't match with target type
* @param <T> Handled type
*/
private static class NonBlockingDeserializer<T> extends JsonDeserializer<T> {
private StdDeserializer<T> delegate;
public NonBlockingDeserializer(StdDeserializer<T> _delegate){
this.delegate = _delegate;
}
@Override
public T deserialize(JsonParser jp,DeserializationContext ctxt) throws IOException,JsonProcessingException {
try {
return delegate.deserialize(jp,ctxt);
}catch (JsonMappingException e){
// If a JSON Mapping occurs,simply returning null instead of blocking things
return null;
}
}
}
private List<StdDeserializer> jsonDeserializers = new ArrayList<StdDeserializer>();
public ObjectMapper createObjectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule customJacksonModule = new SimpleModule("customJacksonModule",new Version(1,null));
for(StdDeserializer jsonDeserializer : jsonDeserializers){
// Wrapping given deserializers with NonBlockingDeserializer
customJacksonModule.addDeserializer(jsonDeserializer.getValueClass(),new NonBlockingDeserializer(jsonDeserializer));
}
objectMapper.registerModule(customJacksonModule);
return objectMapper;
}
public JacksonNonBlockingObjectMapperFactory setJsonDeserializers(List<StdDeserializer> _jsonDeserializers){
this.jsonDeserializers = _jsonDeserializers;
return this;
}
}
Then call it this way (pass only those you want to block as a deserializer):
JacksonNonBlockingObjectMapperFactory factory = new JacksonNonBlockingObjectMapperFactory();
factory.setJsonDeserializers(Arrays.asList(new StdDeserializer[]{
// StdDeserializer,here,comes from Jackson (org.codehaus.jackson.map.deser.StdDeserializer)
new StdDeserializer.ShortDeserializer(Short.class,null),new StdDeserializer.IntegerDeserializer(Integer.class,new StdDeserializer.CharacterDeserializer(Character.class,new StdDeserializer.LongDeserializer(Long.class,new StdDeserializer.FloatDeserializer(Float.class,new StdDeserializer.DoubleDeserializer(Double.class,new StdDeserializer.NumberDeserializer(),new StdDeserializer.BigDecimalDeserializer(),new StdDeserializer.BigIntegerDeserializer(),new StdDeserializer.CalendarDeserializer()
}));
ObjectMapper om = factory.createObjectMapper();
