From d4f3f2278efafe5edad621dbfa58f21f197bee3d Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Wed, 22 Jun 2016 15:15:25 -0700 Subject: [PATCH] Fix #13 --- paranamer/pom.xml | 2 +- .../ParanamerAnnotationIntrospector.java | 52 ++++++-------- ...anamerOnJacksonAnnotationIntrospector.java | 47 ++++++------- .../paranamer/SerializableParanamer.java | 67 +++++++++++++++++++ .../jackson/module/paranamer/SimpleTest.java | 3 +- .../paranamer/TestJDKSerializability.java | 62 +++++++++++++++++ release-notes/VERSION | 4 ++ 7 files changed, 178 insertions(+), 59 deletions(-) create mode 100644 paranamer/src/main/java/com/fasterxml/jackson/module/paranamer/SerializableParanamer.java create mode 100644 paranamer/src/test/java/com/fasterxml/jackson/module/paranamer/TestJDKSerializability.java diff --git a/paranamer/pom.xml b/paranamer/pom.xml index cdc42914..0548d927 100644 --- a/paranamer/pom.xml +++ b/paranamer/pom.xml @@ -75,7 +75,7 @@ to introspect names of constructor (and factory method) parameters. - + org.apache.maven.plugins maven-shade-plugin ${version.plugin.shade} diff --git a/paranamer/src/main/java/com/fasterxml/jackson/module/paranamer/ParanamerAnnotationIntrospector.java b/paranamer/src/main/java/com/fasterxml/jackson/module/paranamer/ParanamerAnnotationIntrospector.java index 6d993589..2cc228f6 100644 --- a/paranamer/src/main/java/com/fasterxml/jackson/module/paranamer/ParanamerAnnotationIntrospector.java +++ b/paranamer/src/main/java/com/fasterxml/jackson/module/paranamer/ParanamerAnnotationIntrospector.java @@ -1,8 +1,5 @@ package com.fasterxml.jackson.module.paranamer; -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.AnnotatedElement; - import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.introspect.Annotated; import com.fasterxml.jackson.databind.introspect.AnnotatedMember; @@ -21,16 +18,27 @@ public class ParanamerAnnotationIntrospector { private static final long serialVersionUID = 1; - protected final Paranamer _paranamer; + /** + * Wrapper used to encapsulate actual Paranamer call, to allow serialization + * of this introspector + */ + protected final SerializableParanamer _paranamer; public ParanamerAnnotationIntrospector() { - this(new CachingParanamer(new BytecodeReadingParanamer())); + this(new SerializableParanamer()); } - public ParanamerAnnotationIntrospector(Paranamer pn) { + /** + * @since 2.7.6 + */ + public ParanamerAnnotationIntrospector(SerializableParanamer pn) { _paranamer = pn; } + public ParanamerAnnotationIntrospector(Paranamer pn) { + this(new SerializableParanamer(pn)); + } + @Override public PropertyName findNameForDeserialization(Annotated a) { @@ -39,10 +47,13 @@ public PropertyName findNameForDeserialization(Annotated a) * in {@link #findParameterSourceName(AnnotatedParameter)}. */ /* - if (a instanceof AnnotatedParameter) { - String rawName = _findParaName((AnnotatedParameter) a); - if (rawName != null) { - return new PropertyName(rawName); + PropertyName name = super.findNameForDeserialization(a); + if (name == null) { + if (a instanceof AnnotatedParameter) { + String rawName _paranamer.findParameterName((AnnotatedParameter) a); + if (rawName != null) { + return new PropertyName(rawName); + } } } */ @@ -53,26 +64,7 @@ public PropertyName findNameForDeserialization(Annotated a) @Override public String findImplicitPropertyName(AnnotatedMember param) { if (param instanceof AnnotatedParameter) { - return _findParaName((AnnotatedParameter) param); - } - return null; - } - - /* - /********************************************************** - /* Internal methods - /********************************************************** - */ - - protected String _findParaName(AnnotatedParameter param) - { - int index = param.getIndex(); - AnnotatedElement ctor = param.getOwner().getAnnotated(); - String[] names = _paranamer.lookupParameterNames((AccessibleObject) ctor, false); - if (names != null) { - if (index < names.length) { - return names[index]; - } + return _paranamer.findParameterName((AnnotatedParameter) param); } return null; } diff --git a/paranamer/src/main/java/com/fasterxml/jackson/module/paranamer/ParanamerOnJacksonAnnotationIntrospector.java b/paranamer/src/main/java/com/fasterxml/jackson/module/paranamer/ParanamerOnJacksonAnnotationIntrospector.java index bb0e5f01..3a298f76 100644 --- a/paranamer/src/main/java/com/fasterxml/jackson/module/paranamer/ParanamerOnJacksonAnnotationIntrospector.java +++ b/paranamer/src/main/java/com/fasterxml/jackson/module/paranamer/ParanamerOnJacksonAnnotationIntrospector.java @@ -1,9 +1,5 @@ package com.fasterxml.jackson.module.paranamer; -import java.lang.reflect.*; - -import com.thoughtworks.paranamer.BytecodeReadingParanamer; -import com.thoughtworks.paranamer.CachingParanamer; import com.thoughtworks.paranamer.Paranamer; import com.fasterxml.jackson.databind.AnnotationIntrospector; import com.fasterxml.jackson.databind.PropertyName; @@ -21,16 +17,31 @@ public class ParanamerOnJacksonAnnotationIntrospector { private static final long serialVersionUID = 1; - protected final Paranamer _paranamer; + /** + * Wrapper used to encapsulate actual Paranamer call, to allow serialization + * of this introspector + */ + protected final SerializableParanamer _paranamer; public ParanamerOnJacksonAnnotationIntrospector() { - this(new CachingParanamer(new BytecodeReadingParanamer())); + this(new SerializableParanamer()); } - public ParanamerOnJacksonAnnotationIntrospector(Paranamer pn) { + /** + * @since 2.7.6 + */ + public ParanamerOnJacksonAnnotationIntrospector(SerializableParanamer pn) { _paranamer = pn; } + /** + * @deprecated since 2.7.6 + */ + @Deprecated + public ParanamerOnJacksonAnnotationIntrospector(Paranamer pn) { + this(new SerializableParanamer(pn)); + } + @Override public PropertyName findNameForDeserialization(Annotated a) { @@ -42,7 +53,7 @@ public PropertyName findNameForDeserialization(Annotated a) PropertyName name = super.findNameForDeserialization(a); if (name == null) { if (a instanceof AnnotatedParameter) { - String rawName = _findParaName((AnnotatedParameter) a); + String rawName _paranamer.findParameterName((AnnotatedParameter) a); if (rawName != null) { return new PropertyName(rawName); } @@ -52,28 +63,10 @@ public PropertyName findNameForDeserialization(Annotated a) return null; } - // since 2.4 @Override public String findImplicitPropertyName(AnnotatedMember param) { if (param instanceof AnnotatedParameter) { - return _findParaName((AnnotatedParameter) param); - } - return null; - } - - /* - /********************************************************** - /* Internal methods - /********************************************************** - */ - - protected String _findParaName(AnnotatedParameter param) - { - int index = param.getIndex(); - AnnotatedElement ctor = param.getOwner().getAnnotated(); - String[] names = _paranamer.lookupParameterNames((AccessibleObject) ctor); - if (names != null && index < names.length) { - return names[index]; + return _paranamer.findParameterName((AnnotatedParameter) param); } return null; } diff --git a/paranamer/src/main/java/com/fasterxml/jackson/module/paranamer/SerializableParanamer.java b/paranamer/src/main/java/com/fasterxml/jackson/module/paranamer/SerializableParanamer.java new file mode 100644 index 00000000..a706f23f --- /dev/null +++ b/paranamer/src/main/java/com/fasterxml/jackson/module/paranamer/SerializableParanamer.java @@ -0,0 +1,67 @@ +package com.fasterxml.jackson.module.paranamer; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.AnnotatedElement; + +import com.fasterxml.jackson.databind.introspect.AnnotatedParameter; +import com.thoughtworks.paranamer.BytecodeReadingParanamer; +import com.thoughtworks.paranamer.CachingParanamer; +import com.thoughtworks.paranamer.Paranamer; + +/** + * Simple wrapper used to hide the fact that paranamer accessor itself if not JDK serializable + * in a way to keep actual ObjectMapper / ObjectReader serializable. + */ +public class SerializableParanamer + implements java.io.Serializable +{ + private static final long serialVersionUID = 1L; + + protected transient Paranamer _paranamer; + + public SerializableParanamer() { + this(null); + } + + public SerializableParanamer(Paranamer paranamer) { + if (paranamer == null) { + paranamer = defaultParanamer(); + } + _paranamer = paranamer; + } + + /** + * Overridable method in case someone really wants to sub-class this implementation. + */ + protected Paranamer defaultParanamer() { + return new CachingParanamer(new BytecodeReadingParanamer()); + } + + /* + /********************************************************** + /* Public API + /********************************************************** + */ + + public String findParameterName(AnnotatedParameter param) + { + int index = param.getIndex(); + AnnotatedElement ctor = param.getOwner().getAnnotated(); + String[] names = _paranamer.lookupParameterNames((AccessibleObject) ctor, false); + if (names != null && index < names.length) { + return names[index]; + } + return null; + } + + /* + /********************************************************** + /* JDK serialization handling + /********************************************************** + */ + + Object readResolve() { + _paranamer = defaultParanamer(); + return this; + } +} diff --git a/paranamer/src/test/java/com/fasterxml/jackson/module/paranamer/SimpleTest.java b/paranamer/src/test/java/com/fasterxml/jackson/module/paranamer/SimpleTest.java index 45116f93..b43599f7 100644 --- a/paranamer/src/test/java/com/fasterxml/jackson/module/paranamer/SimpleTest.java +++ b/paranamer/src/test/java/com/fasterxml/jackson/module/paranamer/SimpleTest.java @@ -50,7 +50,8 @@ public void testSimple() throws Exception assertEquals(40, bean.age); } - // As per [Issue#3] + // Let's test handling of case where parameter names are not found; for example when + // trying to access things for JDK types public void testWrapper() throws Exception { ObjectMapper mapper = new ObjectMapper().registerModule(new ParanamerModule()); diff --git a/paranamer/src/test/java/com/fasterxml/jackson/module/paranamer/TestJDKSerializability.java b/paranamer/src/test/java/com/fasterxml/jackson/module/paranamer/TestJDKSerializability.java new file mode 100644 index 00000000..9c3a4688 --- /dev/null +++ b/paranamer/src/test/java/com/fasterxml/jackson/module/paranamer/TestJDKSerializability.java @@ -0,0 +1,62 @@ +package com.fasterxml.jackson.module.paranamer; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class TestJDKSerializability extends ParanamerTestBase +{ + static class Point { + public int x, y; + } + + public void testMapper() throws Exception + { + ObjectMapper mapper = new ObjectMapper().registerModule(new ParanamerModule()); + // first: serialize as is + byte[] ser = jdkSerialize(mapper); + ObjectMapper m2 = jdkDeserialize(ser); + + // then use lightly, repeat + byte[] rawPoint = m2.writeValueAsBytes(new Point()); + Point result = m2.readValue(rawPoint, Point.class); + assertNotNull(result); + + ser = jdkSerialize(m2); + ObjectMapper m3 = jdkDeserialize(ser); + assertNotNull(m3); + } + + /* + /********************************************************** + /* Helper methods + /********************************************************** + */ + + protected byte[] jdkSerialize(Object o) throws IOException + { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(1000); + ObjectOutputStream obOut = new ObjectOutputStream(bytes); + obOut.writeObject(o); + obOut.close(); + return bytes.toByteArray(); + } + + @SuppressWarnings("unchecked") + protected T jdkDeserialize(byte[] raw) throws IOException + { + ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(raw)); + try { + return (T) objIn.readObject(); + } catch (ClassNotFoundException e) { + fail("Missing class: "+e.getMessage()); + return null; + } finally { + objIn.close(); + } + } +} diff --git a/release-notes/VERSION b/release-notes/VERSION index c9a88b1b..e39e8807 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -8,6 +8,10 @@ Modules: === Releases === ------------------------------------------------------------------------ +2.7.6 (not yet released) + +#13: (paranamer) Make `ParanamerAnnotationIntrospector` serializable + 2.7.5 (11-Jun-2016) No changes since 2.7.4