diff --git a/release-notes/VERSION b/release-notes/VERSION index 3be57f8372..9c9c1576b3 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -13,6 +13,8 @@ Project: jackson-databind (reported by carrino@github) #1191: Non-matching quotes used in error message for date parsing #1194: Incorrect signature for generic type via `JavaType.getGenericSignature +#1195: `JsonMappingException` not Serializable due to 2.7 reference to source (parser) + (reported by mjustin@github) #1198: Problem with `@JsonTypeInfo.As.EXTERNAL_PROPERTY`, `defaultImpl`, missing type id, NPE - Improve handling of custom content (de)serializers for `AtomicReference` diff --git a/src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java b/src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java index 4ff6c02c57..b6731a3394 100644 --- a/src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java +++ b/src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java @@ -89,6 +89,12 @@ public Reference(Object from, int index) { _index = index; } + private Reference(Reference src, Object newFrom) { + _from = newFrom; + _fieldName = src._fieldName; + _index = src._index; + } + public void setFrom(Object o) { _from = o; } public void setFieldName(String n) { _fieldName = n; } public void setIndex(int ix) { _index = ix; } @@ -124,7 +130,24 @@ public Reference(Object from, int index) { sb.append(']'); return sb.toString(); } - } + + /** + * May need some cleaning here, given that `from` may or may not be serializable. + * + * since 2.7.4 + */ + Object writeReplace() { + // as per [databind#1195], reference may cause trouble, if non-serializable + // instance. What to replace it with is trickier; Class is most natural, but + // would recipient have that available? Assume this is the case, for now, because + // + if ((_from != null) && !(_from instanceof Serializable)) { + Object from = _from.getClass(); + return new Reference(this, from); + } + return this; + } +} /* /********************************************************** @@ -141,10 +164,12 @@ public Reference(Object from, int index) { /** * Underlying processor ({@link JsonParser} or {@link JsonGenerator}), * if known. + *

+ * NOTE: typically not serializable hence transient * * @since 2.7 */ - protected Closeable _processor; + protected transient Closeable _processor; /* /********************************************************** diff --git a/src/test/java/com/fasterxml/jackson/databind/TestJDKSerialization.java b/src/test/java/com/fasterxml/jackson/databind/TestJDKSerialization.java index f84ec0a494..dd5c4fe675 100644 --- a/src/test/java/com/fasterxml/jackson/databind/TestJDKSerialization.java +++ b/src/test/java/com/fasterxml/jackson/databind/TestJDKSerialization.java @@ -194,5 +194,4 @@ protected T jdkDeserialize(byte[] raw) throws IOException objIn.close(); } } - } diff --git a/src/test/java/com/fasterxml/jackson/databind/interop/ExceptionSerializableTest1195.java b/src/test/java/com/fasterxml/jackson/databind/interop/ExceptionSerializableTest1195.java new file mode 100644 index 0000000000..102874d8a7 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/interop/ExceptionSerializableTest1195.java @@ -0,0 +1,45 @@ +package com.fasterxml.jackson.databind.interop; + +import java.io.*; + +import com.fasterxml.jackson.databind.*; + +public class ExceptionSerializableTest1195 extends BaseMapTest +{ + abstract static class ClassToRead { + public int x; + } + + static class ContainerClassToRead { + public ClassToRead classToRead; + } + + public void testExceptionSerializability() throws Exception + { + final ObjectMapper mapper = new ObjectMapper(); + try { + mapper.readValue("{\"type\": \"B\"}", ClassToRead.class); + fail("Should not have passed"); + } catch (JsonMappingException e) { + ObjectOutputStream stream = new ObjectOutputStream(new ByteArrayOutputStream()); + try { + stream.writeObject(e); + stream.close(); + } catch (Exception e2) { + fail("Failed to serialize "+e.getClass().getName()+": "+e2); + } + } + try { + mapper.readValue("{\"classToRead\": {\"type\": \"B\"}}", ContainerClassToRead.class); + fail("Should not have passed"); + } catch (JsonMappingException e) { + ObjectOutputStream stream = new ObjectOutputStream(new ByteArrayOutputStream()); + try { + stream.writeObject(e); + stream.close(); + } catch (Exception e2) { + fail("Failed to serialize "+e.getClass().getName()+": "+e2); + } + } + } +}