parse versus mapping exception in custom deserializers

471 views
Skip to first unread message

Daniel Lipofsky

unread,
Feb 17, 2015, 2:11:16 PM2/17/15
to jackso...@googlegroups.com
I'm converting an enum to/from and int using a custom serializer/deserializer.
I've been throwing a JsonParseException if deserialization fail.
Somewhere between 2.2.1 and 2.5.0 the Jackson libraries started
wrapping my JsonParseException with a JsonMappingException.  The most
immediate problem is that causes my unit tests to fail.  I could fix
the tests, but I am wondering why Jackson is doing this, and I am also
wonder the logical difference between a parse and a mapping exception
and whether or not I should be throwing a mapping exception instead?

@JsonSerialize(using = com.foo.FooType.FooTypeSerializer.class)
@JsonDeserialize(using = com.foo.FooType.FooTypeDeserializer.class)
public enum FooType {
    NONE
(0, "None"),
    RELATIVE
(1, "Relative"),
    ABSOLUTE
(2, "Absolute"),
    STANDARD_DEVIATION
(3, "Std Dev");


   
public static final FooType getByCode(final int i) {
       
// ... returns null if not found ...
   
}


   
private final int code;
   
private final String display;


   
FooType(final int code, final String display) {
       
this.code = code;
       
this.display = display;
   
}


   
public int getCode() {
       
return code;
   
}


   
static class FooTypeSerializer extends JsonSerializer<FooType> {
       
@Override
       
public void serialize(
               
final FooType value,
               
final JsonGenerator generator,
               
final SerializerProvider provider) throws IOException, JsonGenerationException {
            generator
.writeNumber(value.getCode());
       
}
   
}


   
static class FooTypeDeserializer extends JsonDeserializer<FooType> {
       
@Override
       
public FooType deserialize(final JsonParser jp, final DeserializationContext ctxt)
               
throws IOException, JsonParseException {
           
final int c = jp.getIntValue();
           
final FooType type = getByCode(c);
           
if (type == null) {
               
throw new JsonParseException("Could not convert " + c + " to FooType", jp.getCurrentLocation());
           
}
           
return type;
       
}
   
}
}



Caused by: com.fasterxml.jackson.databind.JsonMappingException: Could not convert 4 to FooType
 at
[Source: {"id":9,"sShockType":0,"sShock":0.0,"volShockType":4,"volShock":0.0}; line: 1, column: 53] (through reference chain: com.foo.Foo["volShockType"])
 at com
.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:210)
 at com
.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:177)
 at com
.fasterxml.jackson.databind.deser.impl.BeanPropertyMap.wrapAndThrow(BeanPropertyMap.java:439)
 at com
.fasterxml.jackson.databind.deser.impl.BeanPropertyMap._findDeserializeAndSet2(BeanPropertyMap.java:315)
 at com
.fasterxml.jackson.databind.deser.impl.BeanPropertyMap.findDeserializeAndSet(BeanPropertyMap.java:291)
 at com
.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:248)
 at com
.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:136)
 at com
.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3560)
 at com
.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2576)
 at com
.foo.FooTest.testReadErrorBadVolatilityType(FooTest.java:82)
 
...
Caused by: com.fasterxml.jackson.core.JsonParseException: Could not convert 4 to FooType
 at
[Source: {"id":9,"sShockType":0,"sShock":0.0,"volShockType":4,"volShock":0.0}; line: 1, column: 53]
 at com
.foo.FooType$FooTypeDeserializer.deserialize(FooType.java:114)
 at com
.foo.FooType$FooTypeDeserializer.deserialize(FooType.java:1)
 at com
.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:523)
 at com
.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:95)
 at com
.fasterxml.jackson.databind.deser.impl.BeanPropertyMap._findDeserializeAndSet2(BeanPropertyMap.java:313)
 
... 16 more

Thanks,
Dan

Tatu Saloranta

unread,
Feb 17, 2015, 4:28:57 PM2/17/15
to jackso...@googlegroups.com
I was about to answer that this sounds like a bug, before remembering actual reason why this is done: to add location information (where the problem occurred) regarding logical location within POJO, which is useful in troubleshooting. JsonParseException (and JsonGenerationException) are more low-level things from streaming parser/generator, and thus can only report physical input/output location.
JsonMappingException would not be wrapped, since location information can be augmented easily in cases where it has not yet been added.

In your case I do think that JsonMappingException is a better type to use; JsonParseException would refer to problem with decoding JSON (missing comma, wrong closing marker, duplicate key), but in this case JSON itself is well-formed, and problem is with mapping/binding.

Apologies for the change here. But it was made to give more useful information regarding problem; and there are no plans to change this behavior.

-+ Tatu +-


--
You received this message because you are subscribed to the Google Groups "jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user...@googlegroups.com.
To post to this group, send email to jackso...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Daniel Lipofsky

unread,
Feb 17, 2015, 5:27:57 PM2/17/15
to jackso...@googlegroups.com
No problem, I can change! I just wasn't sure what I should even be using. Your response clarifies it for me. Thanks,
Dan

Tatu Saloranta

unread,
Feb 17, 2015, 8:03:06 PM2/17/15
to jackso...@googlegroups.com
No problem -- and it is a good question, hopefully answer is useful to others as well.

-+ Tatu +-

Reply all
Reply to author
Forward
0 new messages