Skip to content

Commit 2d80cf9

Browse files
committed
Fix issue FasterXML#731 - returning Object from Converter
1 parent df716c3 commit 2d80cf9

5 files changed

Lines changed: 119 additions & 13 deletions

File tree

src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
1313
import com.fasterxml.jackson.databind.ser.*;
1414
import com.fasterxml.jackson.databind.ser.impl.*;
15+
import com.fasterxml.jackson.databind.ser.std.DynamicSerializer;
1516
import com.fasterxml.jackson.databind.ser.std.NullSerializer;
1617
import com.fasterxml.jackson.databind.type.TypeFactory;
1718
import com.fasterxml.jackson.databind.util.ClassUtil;
@@ -829,6 +830,16 @@ public JsonSerializer<Object> getUnknownTypeSerializer(Class<?> unknownType) {
829830
public boolean isUnknownTypeSerializer(JsonSerializer<?> ser) {
830831
return (ser == _unknownTypeSerializer) || (ser == null);
831832
}
833+
834+
/**
835+
* Helper method called to see if given serializer is a dynamic serializer, that is, something
836+
* for which no regular serializer was found or constructed and it will be a try to find actual serializer in runtime.
837+
*
838+
* @since 2.5
839+
*/
840+
public boolean isDynamicSerializer(JsonSerializer<?> ser) {
841+
return ser instanceof DynamicSerializer;
842+
}
832843

833844
/*
834845
/**********************************************************
@@ -1094,8 +1105,9 @@ protected JsonSerializer<Object> _findExplicitUntypedSerializer(Class<?> runtime
10941105
* that pushes creation of "unknown type" serializer deeper down
10951106
* in BeanSerializerFactory; as a result, we need to "undo" creation
10961107
* here.
1108+
* 14-Mar-2015 If we have DynamicSerializer here it means that we actually don't have explicit serializer and will try to detect it in runtime
10971109
*/
1098-
if (isUnknownTypeSerializer(ser)) {
1110+
if (isDynamicSerializer(ser) || isUnknownTypeSerializer(ser)) {
10991111
return null;
11001112
}
11011113
return ser;

src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.fasterxml.jackson.databind.ser.impl.FilteredBeanPropertyWriter;
1414
import com.fasterxml.jackson.databind.ser.impl.ObjectIdWriter;
1515
import com.fasterxml.jackson.databind.ser.impl.PropertyBasedObjectIdGenerator;
16+
import com.fasterxml.jackson.databind.ser.std.DynamicSerializer;
1617
import com.fasterxml.jackson.databind.ser.std.MapSerializer;
1718
import com.fasterxml.jackson.databind.ser.std.StdDelegatingSerializer;
1819
import com.fasterxml.jackson.databind.type.*;
@@ -339,7 +340,7 @@ protected JsonSerializer<Object> constructBeanSerializer(SerializerProvider prov
339340
// 13-Oct-2010, tatu: quick sanity check: never try to create bean serializer for plain Object
340341
// 05-Jul-2012, tatu: ... but we should be able to just return "unknown type" serializer, right?
341342
if (beanDesc.getBeanClass() == Object.class) {
342-
return prov.getUnknownTypeSerializer(Object.class);
343+
return new DynamicSerializer(prov.getUnknownTypeSerializer(Object.class));
343344
// throw new IllegalArgumentException("Can not create bean serializer for Object.class");
344345
}
345346
final SerializationConfig config = prov.getConfig();
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package com.fasterxml.jackson.databind.ser.std;
2+
3+
import java.io.IOException;
4+
import java.lang.reflect.Type;
5+
6+
import com.fasterxml.jackson.core.JsonGenerator;
7+
import com.fasterxml.jackson.databind.JavaType;
8+
import com.fasterxml.jackson.databind.JsonMappingException;
9+
import com.fasterxml.jackson.databind.JsonNode;
10+
import com.fasterxml.jackson.databind.JsonSerializer;
11+
import com.fasterxml.jackson.databind.SerializerProvider;
12+
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
13+
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
14+
15+
/**
16+
* Use serializer of this class in case of type and serializer for this type can't detect statically
17+
* For example, if intermediate {@link com.fasterxml.jackson.databind.util.Converter} return generic Object value,
18+
* this serializer can be used to get actual serializer in runtime
19+
*/
20+
@SuppressWarnings("serial")
21+
public class DynamicSerializer
22+
extends StdSerializer<Object>
23+
{
24+
private final JsonSerializer<Object> chainedSerializer;
25+
26+
public DynamicSerializer(JsonSerializer<Object> chainedSerializer) {
27+
super(Object.class);
28+
this.chainedSerializer = chainedSerializer;
29+
}
30+
31+
@Override
32+
public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
33+
throws IOException
34+
{
35+
JsonSerializer<Object> dynamicSerializer = provider.findValueSerializer(value.getClass());
36+
if (dynamicSerializer != null && !provider.isDynamicSerializer(dynamicSerializer)) {
37+
dynamicSerializer.serialize(value, jgen, provider);
38+
} else {
39+
chainedSerializer.serialize(value, jgen, provider);
40+
}
41+
}
42+
43+
@Override
44+
public final void serializeWithType(Object value, JsonGenerator jgen, SerializerProvider provider,
45+
TypeSerializer typeSer)
46+
throws IOException
47+
{
48+
JsonSerializer<Object> dynamicSerializer = provider.findValueSerializer(value.getClass());
49+
if (dynamicSerializer != null) {
50+
dynamicSerializer.serializeWithType(value, jgen, provider, typeSer);
51+
}
52+
53+
chainedSerializer.serializeWithType(value, jgen, provider, typeSer);
54+
}
55+
56+
@Override
57+
public JsonNode getSchema(SerializerProvider provider, Type typeHint) throws JsonMappingException
58+
{
59+
return null;
60+
}
61+
62+
@Override
63+
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
64+
throws JsonMappingException
65+
{
66+
visitor.expectAnyFormat(typeHint);
67+
}
68+
}

src/test/java/com/fasterxml/jackson/databind/convert/TestBeanConversions.java

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,15 @@ static class Leaf {
6363
public Leaf() { }
6464
public Leaf(int v) { value = v; }
6565
}
66-
66+
67+
public static class DummyBean {
68+
public final int a, b;
69+
public DummyBean(int v1, int v2) {
70+
a = v1 * 2;
71+
b = v2 * 2;
72+
}
73+
}
74+
6775
// [Issue#288]
6876

6977
@JsonSerialize(converter = ConvertingBeanConverter.class)
@@ -75,14 +83,6 @@ public ConvertingBean(int v1, int v2) {
7583
}
7684
}
7785

78-
public static class DummyBean {
79-
public final int a, b;
80-
public DummyBean(int v1, int v2) {
81-
a = v1 * 2;
82-
b = v2 * 2;
83-
}
84-
}
85-
8686
static class ConvertingBeanConverter extends StdConverter<ConvertingBean, DummyBean>
8787
{
8888
@Override
@@ -91,6 +91,25 @@ public DummyBean convert(ConvertingBean cb) {
9191
}
9292
}
9393

94+
// [Issue#731]
95+
96+
@JsonSerialize(converter = UntypedConvertingBeanConverter.class)
97+
static class ConvertingBeanWithUntypedConverter {
98+
public int x, y;
99+
public ConvertingBeanWithUntypedConverter(int v1, int v2) {
100+
x = v1;
101+
y = v2;
102+
}
103+
}
104+
105+
static class UntypedConvertingBeanConverter extends StdConverter<ConvertingBeanWithUntypedConverter, Object>
106+
{
107+
@Override
108+
public Object convert(ConvertingBeanWithUntypedConverter cb) {
109+
return new DummyBean(cb.x, cb.y);
110+
}
111+
}
112+
94113
/*
95114
/**********************************************************
96115
/* Test methods
@@ -252,5 +271,12 @@ public void testConversionIssue288() throws Exception
252271
String json = MAPPER.writeValueAsString(new ConvertingBean(1, 2));
253272
// must be {"a":2,"b":4}
254273
assertEquals("{\"a\":2,\"b\":4}", json);
255-
}
274+
}
275+
276+
public void testIssue731() throws Exception
277+
{
278+
String json = MAPPER.writeValueAsString(new ConvertingBeanWithUntypedConverter(1, 2));
279+
// must be {"a":2,"b":4}
280+
assertEquals("{\"a\":2,\"b\":4}", json);
281+
}
256282
}

src/test/java/com/fasterxml/jackson/databind/ser/TestSerializerProvider.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import java.util.concurrent.atomic.AtomicReference;
44

55
import com.fasterxml.jackson.databind.*;
6-
import com.fasterxml.jackson.databind.ser.BeanSerializerFactory;
76

87
public class TestSerializerProvider
98
extends com.fasterxml.jackson.databind.BaseMapTest

0 commit comments

Comments
 (0)