aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release-notes/CREDITS7
-rw-r--r--release-notes/VERSION2
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/JavaType.java13
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java3
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java4
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/std/StdDelegatingSerializer.java54
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/std/StdSerializer.java4
-rw-r--r--src/test/java/com/fasterxml/jackson/databind/convert/TestConvertingSerializer.java36
8 files changed, 109 insertions, 14 deletions
diff --git a/release-notes/CREDITS b/release-notes/CREDITS
index cf8f03433..875b7ffd3 100644
--- a/release-notes/CREDITS
+++ b/release-notes/CREDITS
@@ -221,7 +221,12 @@ Dylan Scott (dylanscott@github)
issue)
(2.5.2)
+Dmitry Spikhalskiy (Spikhalskiy@github)
+ * Reported #731, suggested the way to fix it: XmlAdapter result marshaling error in
+ case of ValueType=Object
+ (2.5.3)
+
John Meyer (jpmeyer@github)
- * Reported, contributed fix for #745: EnumDeserializer.deserializerForCreator fails
+ * Reported, contributed fix for #745: EnumDeserializer.deserializerForCreator() fails
when used to deserialize a Map key
(2.5.3)
diff --git a/release-notes/VERSION b/release-notes/VERSION
index 8856d08bd..cc413c95e 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -6,6 +6,8 @@ Project: jackson-databind
2.5.3 (not yet released)
+#731: XmlAdapter result marshaling error in case of ValueType=Object
+ (reported, debugged by Dmitry S)
#742: Allow deserialization of `null` Object Id (missing already allowed)
#744: Custom deserializer with parent object update failing
(reported by migel@github)
diff --git a/src/main/java/com/fasterxml/jackson/databind/JavaType.java b/src/main/java/com/fasterxml/jackson/databind/JavaType.java
index 822130b00..07b6ba968 100644
--- a/src/main/java/com/fasterxml/jackson/databind/JavaType.java
+++ b/src/main/java/com/fasterxml/jackson/databind/JavaType.java
@@ -291,6 +291,17 @@ public abstract class JavaType
public boolean isMapLikeType() { return false; }
/**
+ * Convenience method, short-hand for
+ *<code>
+ * getRawClass() == Object.class
+ *</code>
+ * and used to figure if we basically have "untyped" type object.
+ *
+ * @since 2.5
+ */
+ public final boolean isJavaLangObject() { return _class == Object.class; }
+
+ /**
* Accessor for checking whether handlers for dealing with values of
* this type should use static typing (as opposed to dynamic typing).
* Note that while value of 'true' does mean that static typing is to
@@ -299,7 +310,7 @@ public abstract class JavaType
* @since 2.2
*/
public final boolean useStaticType() { return _asStatic; }
-
+
/*
/**********************************************************
/* Public API, type parameter access; pass-through
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java
index ec540cc6d..14e6d9345 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java
@@ -159,7 +159,8 @@ public class BeanSerializerFactory
// [#359]: explicitly check (again) for @JsonSerializer...
ser = findSerializerFromAnnotation(prov, beanDesc.getClassInfo());
}
- if (ser == null) {
+ // [databind#731]: Should skip if nominally java.lang.Object
+ if (ser == null && !delegateType.isJavaLangObject()) {
ser = _createSerializer2(prov, delegateType, beanDesc, true);
}
return new StdDelegatingSerializer(conv, delegateType, ser);
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java
index ee8735c2f..3e1164808 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java
@@ -366,7 +366,9 @@ public abstract class BeanSerializerBase
if (convDef != null) {
Converter<Object,Object> conv = provider.converterInstance(prop.getMember(), convDef);
JavaType delegateType = conv.getOutputType(provider.getTypeFactory());
- JsonSerializer<?> ser = provider.findValueSerializer(delegateType, prop);
+ // [databind#731]: Should skip if nominally java.lang.Object
+ JsonSerializer<?> ser = delegateType.isJavaLangObject() ? null
+ : provider.findValueSerializer(delegateType, prop);
return new StdDelegatingSerializer(conv, delegateType, ser);
}
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/StdDelegatingSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/StdDelegatingSerializer.java
index 0b435ead1..6c52b736e 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/StdDelegatingSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/StdDelegatingSerializer.java
@@ -115,13 +115,20 @@ public class StdDelegatingSerializer
if (delegateType == null) {
delegateType = _converter.getOutputType(provider.getTypeFactory());
}
- delSer = provider.findValueSerializer(delegateType);
+ /* 02-Apr-2015, tatu: For "dynamic case", where type is only specified as
+ * java.lang.Object (or missing generic), [databind#731]
+ */
+ if (!delegateType.isJavaLangObject()) {
+ delSer = provider.findValueSerializer(delegateType);
+ }
}
if (delSer instanceof ContextualSerializer) {
delSer = provider.handleSecondaryContextualization(delSer, property);
}
- return (delSer == _delegateSerializer) ? this
- : withDelegate(_converter, delegateType, delSer);
+ if (delSer == _delegateSerializer && delegateType == _delegateType) {
+ return this;
+ }
+ return withDelegate(_converter, delegateType, delSer);
}
/*
@@ -154,7 +161,12 @@ public class StdDelegatingSerializer
provider.defaultSerializeNull(gen);
return;
}
- _delegateSerializer.serialize(delegateValue, gen, provider);
+ // 02-Apr-2015, tatu: As per [databind#731] may need to do dynamic lookup
+ JsonSerializer<Object> ser = _delegateSerializer;
+ if (ser == null) {
+ ser = _findSerializer(delegateValue, provider);
+ }
+ ser.serialize(delegateValue, gen, provider);
}
@Override
@@ -165,14 +177,21 @@ public class StdDelegatingSerializer
* let's give it a chance?
*/
Object delegateValue = convertValue(value);
- _delegateSerializer.serializeWithType(delegateValue, gen, provider, typeSer);
+ JsonSerializer<Object> ser = _delegateSerializer;
+ if (ser == null) {
+ ser = _findSerializer(value, provider);
+ }
+ ser.serializeWithType(delegateValue, gen, provider, typeSer);
}
@Override
- @Deprecated // since 1.5
+ @Deprecated // since 2.5
public boolean isEmpty(Object value)
{
Object delegateValue = convertValue(value);
+ if (_delegateSerializer == null) { // best we can do for now, too costly to look up
+ return (value == null);
+ }
return _delegateSerializer.isEmpty(delegateValue);
}
@@ -180,6 +199,9 @@ public class StdDelegatingSerializer
public boolean isEmpty(SerializerProvider prov, Object value)
{
Object delegateValue = convertValue(value);
+ if (_delegateSerializer == null) { // best we can do for now, too costly to look up
+ return (value == null);
+ }
return _delegateSerializer.isEmpty(prov, delegateValue);
}
@@ -216,7 +238,10 @@ public class StdDelegatingSerializer
/* 03-Sep-2012, tatu: Not sure if this can be made to really work
* properly... but for now, try this:
*/
- _delegateSerializer.acceptJsonFormatVisitor(visitor, typeHint);
+ // 02-Apr-2015, tatu: For dynamic case, very little we can do
+ if (_delegateSerializer != null) {
+ _delegateSerializer.acceptJsonFormatVisitor(visitor, typeHint);
+ }
}
/*
@@ -239,4 +264,19 @@ public class StdDelegatingSerializer
protected Object convertValue(Object value) {
return _converter.convert(value);
}
+
+ /**
+ * Helper method used for locating serializer to use in dynamic use case, where
+ * actual type value gets converted to is not specified beyond basic
+ * {@link java.lang.Object}, and where serializer needs to be located dynamically
+ * based on actual value type.
+ *
+ * @since 2.6
+ */
+ protected JsonSerializer<Object> _findSerializer(Object value, SerializerProvider serializers)
+ throws JsonMappingException
+ {
+ // NOTE: will NOT call contextualization
+ return serializers.findValueSerializer(value.getClass());
+ }
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/StdSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/StdSerializer.java
index 31bbe0870..6089e6be2 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/StdSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/StdSerializer.java
@@ -250,7 +250,6 @@ public abstract class StdSerializer<T>
* when applying contextual content converter; this is not ideal way,
* but should work for most cases.
*/
-
final AnnotationIntrospector intr = provider.getAnnotationIntrospector();
if (intr != null && prop != null) {
AnnotatedMember m = prop.getMember();
@@ -259,7 +258,8 @@ public abstract class StdSerializer<T>
if (convDef != null) {
Converter<Object,Object> conv = provider.converterInstance(prop.getMember(), convDef);
JavaType delegateType = conv.getOutputType(provider.getTypeFactory());
- if (existingSerializer == null) {
+ // [databind#731]: Should skip if nominally java.lang.Object
+ if (existingSerializer == null && !delegateType.hasRawClass(Object.class)) {
existingSerializer = provider.findValueSerializer(delegateType);
}
return new StdDelegatingSerializer(conv, delegateType, existingSerializer);
diff --git a/src/test/java/com/fasterxml/jackson/databind/convert/TestConvertingSerializer.java b/src/test/java/com/fasterxml/jackson/databind/convert/TestConvertingSerializer.java
index e9e467dde..6104782c6 100644
--- a/src/test/java/com/fasterxml/jackson/databind/convert/TestConvertingSerializer.java
+++ b/src/test/java/com/fasterxml/jackson/databind/convert/TestConvertingSerializer.java
@@ -122,7 +122,33 @@ public class TestConvertingSerializer
jsonGenerator.writeString("Target");
}
}
-
+
+ // [Issue#731]
+ public static class DummyBean {
+ public final int a, b;
+ public DummyBean(int v1, int v2) {
+ a = v1 * 2;
+ b = v2 * 2;
+ }
+ }
+
+ @JsonSerialize(converter = UntypedConvertingBeanConverter.class)
+ static class ConvertingBeanWithUntypedConverter {
+ public int x, y;
+ public ConvertingBeanWithUntypedConverter(int v1, int v2) {
+ x = v1;
+ y = v2;
+ }
+ }
+
+ static class UntypedConvertingBeanConverter extends StdConverter<ConvertingBeanWithUntypedConverter, Object>
+ {
+ @Override
+ public Object convert(ConvertingBeanWithUntypedConverter cb) {
+ return new DummyBean(cb.x, cb.y);
+ }
+ }
+
/*
/**********************************************************
/* Test methods
@@ -168,4 +194,12 @@ public class TestConvertingSerializer
String json = objectWriter().writeValueAsString(new Bean359());
assertEquals("{\"stuff\":[\"Target\"]}", json);
}
+
+ // [databind#731]: Problems converting from java.lang.Object ("unknown")
+ public void testIssue731() throws Exception
+ {
+ String json = objectWriter().writeValueAsString(new ConvertingBeanWithUntypedConverter(1, 2));
+ // must be {"a":2,"b":4}
+ assertEquals("{\"a\":2,\"b\":4}", json);
+ }
}