Fixed [JACKSON-377], ThrowableDeserializer not correctly handling @JsonCreator or @JsonAnySetter
diff --git a/release-notes/CREDITS b/release-notes/CREDITS index 4ae05ab..592e477 100644 --- a/release-notes/CREDITS +++ b/release-notes/CREDITS
@@ -400,6 +400,9 @@ * Suggested [JACKSON-308] Configurable date formatting support for XMLGregorianCalendar, XMLGregorianCalendar now uses same Date/Calendar serialization as other date types. [1.6.0] - - + +Kirill Stokoz: + * Reported [JACKSON-377] ThrowableDeserializer was not properly using information from + @JsonCreator or @JsonAnySetter + [1.6.1] \ No newline at end of file
diff --git a/release-notes/VERSION b/release-notes/VERSION index d263ff1..fa0bd76 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION
@@ -10,7 +10,10 @@ * [JACKSON-372] handle missing primitive type values for @JsonCreator gracefully (with defaults) * [JACKSON-376] writing binary data as object field value with Smile failed - (report by Shay B) + (reported by Shay B) + * [JACKSON-377] ThrowableDeserializer was not properly using information from + @JsonCreator or @JsonAnySetter + (reported by Kirill S) * all fixes from 1.5.x up to 1.5.7 ------------------------------------------------------------------------
diff --git a/src/mapper/java/org/codehaus/jackson/map/deser/ThrowableDeserializer.java b/src/mapper/java/org/codehaus/jackson/map/deser/ThrowableDeserializer.java index e27d0ca..507866e 100644 --- a/src/mapper/java/org/codehaus/jackson/map/deser/ThrowableDeserializer.java +++ b/src/mapper/java/org/codehaus/jackson/map/deser/ThrowableDeserializer.java
@@ -13,12 +13,12 @@ public class ThrowableDeserializer extends BeanDeserializer { - final static String PROP_NAME_MESSAGE = "message"; + protected final static String PROP_NAME_MESSAGE = "message"; /* - /////////////////////////////////////////////////////// - // Construction - /////////////////////////////////////////////////////// + /********************************************************** + /* Construction + /********************************************************** */ public ThrowableDeserializer(JavaType type) @@ -27,15 +27,32 @@ } /* - /////////////////////////////////////////////////////// - // Overridden methods - /////////////////////////////////////////////////////// + /********************************************************** + /* Overridden methods + /********************************************************** */ @Override public Object deserializeFromObject(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { + // 30-Sep-2010, tatu: Need to allow use of @JsonCreator, so: + if (_propertyBasedCreator != null) { // proper @JsonCreator + return _deserializeUsingPropertyBased(jp, ctxt); + } + if (_delegatingCreator != null) { // delegate based one (single-arg, no property name) + return _delegatingCreator.deserialize(jp, ctxt); + } + if (_beanType.isAbstract()) { // for good measure, check this too + throw JsonMappingException.from(jp, "Can not instantiate abstract type "+_beanType + +" (need to add/enable type information?)"); + } + // and finally, verify we do have single-String arg constructor (if no @JsonCreator) + if (_stringCreator == null) { + throw new JsonMappingException("Can not deserialize Throwable of type "+_beanType + +" without having either single-String-arg constructor; or explicit @JsonCreator"); + } + Object throwable = null; Object[] pending = null; int pendingIx = 0; @@ -73,6 +90,17 @@ } continue; } + /* As per [JACKSON-313], things marked as ignorable should not be + * passed to any setter + */ + if (_ignorableProps != null && _ignorableProps.contains(propName)) { + jp.skipChildren(); + continue; + } + if (_anySetter != null) { + _anySetter.deserializeAndSet(jp, ctxt, throwable, propName); + continue; + } // Unknown: let's call handler method handleUnknownProperty(jp, ctxt, throwable, propName); }
diff --git a/src/test/org/codehaus/jackson/map/deser/TestExceptionDeserialization.java b/src/test/org/codehaus/jackson/map/deser/TestExceptionDeserialization.java index 4b69433..527c4a2 100644 --- a/src/test/org/codehaus/jackson/map/deser/TestExceptionDeserialization.java +++ b/src/test/org/codehaus/jackson/map/deser/TestExceptionDeserialization.java
@@ -3,7 +3,11 @@ import org.codehaus.jackson.map.BaseMapTest; import java.io.IOException; +import java.util.*; +import org.codehaus.jackson.annotate.JsonAnySetter; +import org.codehaus.jackson.annotate.JsonCreator; +import org.codehaus.jackson.annotate.JsonProperty; import org.codehaus.jackson.map.*; /** @@ -12,8 +16,39 @@ public class TestExceptionDeserialization extends BaseMapTest { - public void testIOException() - throws IOException + @SuppressWarnings("serial") + static class MyException extends Exception + { + protected int value; + + protected String myMessage; + protected HashMap<String,Object> stuff = new HashMap<String, Object>(); + + @JsonCreator + MyException(@JsonProperty("message") String msg, @JsonProperty("value") int v) + { + super(msg); + myMessage = msg; + value = v; + } + + public int getValue() { return value; } + + public String getFoo() { return "bar"; } + + @JsonAnySetter public void setter(String key, Object value) + { + stuff.put(key, value); + } + } + + /* + /********************************************************** + /* Tests + /********************************************************** + */ + + public void testIOException() throws IOException { ObjectMapper mapper = new ObjectMapper(); IOException ioe = new IOException("TEST"); @@ -24,4 +59,18 @@ assertEquals(ioe.getMessage(), result.getMessage()); } + + // As per [JACKSON-377] + public void testWithCreator() throws IOException + { + final String MSG = "the message"; + ObjectMapper mapper = new ObjectMapper(); + String json = mapper.writeValueAsString(new MyException(MSG, 3)); + + MyException result = mapper.readValue(json, MyException.class); + assertEquals(MSG, result.getMessage()); + assertEquals(3, result.value); + assertEquals(1, result.stuff.size()); + assertEquals(result.getFoo(), result.stuff.get("foo")); + } }