Skip to content
This repository was archived by the owner on Jan 20, 2025. It is now read-only.

Commit a5d16ab

Browse files
committed
Fix #42 for master (2.4.0)
1 parent 7b99e58 commit a5d16ab

File tree

3 files changed

+132
-16
lines changed

3 files changed

+132
-16
lines changed

src/main/java/com/fasterxml/jackson/datatype/guava/GuavaDeserializers.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.fasterxml.jackson.databind.type.CollectionType;
77
import com.fasterxml.jackson.databind.type.MapLikeType;
88
import com.fasterxml.jackson.databind.type.MapType;
9+
import com.fasterxml.jackson.databind.type.TypeFactory;
910
import com.fasterxml.jackson.datatype.guava.deser.*;
1011
import com.fasterxml.jackson.datatype.guava.deser.multimap.list.ArrayListMultimapDeserializer;
1112
import com.fasterxml.jackson.datatype.guava.deser.multimap.list.LinkedListMultimapDeserializer;
@@ -210,12 +211,19 @@ public JsonDeserializer<?> findMapLikeDeserializer(MapLikeType type,
210211

211212
@Override
212213
public JsonDeserializer<?> findBeanDeserializer(final JavaType type, DeserializationConfig config,
213-
BeanDescription beanDesc) throws JsonMappingException {
214+
BeanDescription beanDesc) throws JsonMappingException
215+
{
214216
Class<?> raw = type.getRawClass();
215217
if (Optional.class.isAssignableFrom(raw)){
218+
JavaType[] types = config.getTypeFactory().findTypeParameters(type, Optional.class);
219+
JavaType refType = (types == null) ? TypeFactory.unknownType() : types[0];
216220
JsonDeserializer<?> valueDeser = type.getValueHandler();
217221
TypeDeserializer typeDeser = type.getTypeHandler();
218-
return new GuavaOptionalDeserializer(type, typeDeser, valueDeser);
222+
// [Issue#42]: Polymorphic types need type deserializer
223+
if (typeDeser == null) {
224+
typeDeser = config.findTypeDeserializer(refType);
225+
}
226+
return new GuavaOptionalDeserializer(type, refType, typeDeser, valueDeser);
219227
}
220228
if (Range.class.isAssignableFrom(raw)) {
221229
return new RangeDeserializer(type);

src/main/java/com/fasterxml/jackson/datatype/guava/deser/GuavaOptionalDeserializer.java

+16-14
Original file line numberDiff line numberDiff line change
@@ -21,39 +21,38 @@ public class GuavaOptionalDeserializer
2121
{
2222
private static final long serialVersionUID = 1L;
2323

24+
protected final JavaType _fullType;
25+
2426
protected final JavaType _referenceType;
2527

2628
protected final JsonDeserializer<?> _valueDeserializer;
2729

2830
protected final TypeDeserializer _valueTypeDeserializer;
2931

30-
@Deprecated // since 2.3,
31-
public GuavaOptionalDeserializer(JavaType valueType) {
32-
this(valueType, null, null);
33-
}
34-
35-
public GuavaOptionalDeserializer(JavaType valueType,
32+
public GuavaOptionalDeserializer(JavaType fullType, JavaType refType,
3633
TypeDeserializer typeDeser, JsonDeserializer<?> valueDeser)
3734
{
38-
super(valueType);
39-
_referenceType = valueType.containedType(0);
35+
super(fullType);
36+
_fullType = fullType;
37+
_referenceType = refType;
4038
_valueTypeDeserializer = typeDeser;
4139
_valueDeserializer = valueDeser;
4240
}
4341

4442
@Override
45-
public Optional<?> getNullValue() {
46-
return Optional.absent();
47-
}
43+
public JavaType getValueType() { return _fullType; }
44+
45+
@Override
46+
public Optional<?> getNullValue() { return Optional.absent(); }
4847

4948
/**
5049
* Overridable fluent factory method used for creating contextual
5150
* instances.
5251
*/
53-
public GuavaOptionalDeserializer withResolved(
52+
protected GuavaOptionalDeserializer withResolved(
5453
TypeDeserializer typeDeser, JsonDeserializer<?> valueDeser)
5554
{
56-
return new GuavaOptionalDeserializer(_referenceType,
55+
return new GuavaOptionalDeserializer(_fullType, _referenceType,
5756
typeDeser, valueDeser);
5857
}
5958

@@ -74,8 +73,11 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
7473
{
7574
JsonDeserializer<?> deser = _valueDeserializer;
7675
TypeDeserializer typeDeser = _valueTypeDeserializer;
76+
7777
if (deser == null) {
7878
deser = ctxt.findContextualValueDeserializer(_referenceType, property);
79+
} else { // otherwise directly assigned, probably not contextual yet:
80+
deser = ctxt.handleSecondaryContextualization(deser, property);
7981
}
8082
if (typeDeser != null) {
8183
typeDeser = typeDeser.forProperty(property);
@@ -88,7 +90,7 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
8890

8991
@Override
9092
public Optional<?> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
91-
JsonProcessingException
93+
JsonProcessingException
9294
{
9395
Object refd;
9496

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package com.fasterxml.jackson.datatype.guava;
2+
3+
import java.util.Map;
4+
5+
import com.fasterxml.jackson.annotation.*;
6+
import com.fasterxml.jackson.databind.*;
7+
8+
import com.google.common.base.Optional;
9+
import com.google.common.collect.ImmutableMap;
10+
11+
public class TestOptionalWithPolymorphic extends BaseTest
12+
{
13+
static class ContainerA {
14+
@JsonProperty private Optional<String> name = Optional.absent();
15+
@JsonProperty private Optional<Strategy> strategy = Optional.absent();
16+
}
17+
18+
static class ContainerB {
19+
@JsonProperty private Optional<String> name = Optional.absent();
20+
@JsonProperty private Strategy strategy = null;
21+
}
22+
23+
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
24+
@JsonSubTypes({
25+
@JsonSubTypes.Type(name = "Foo", value = Foo.class),
26+
@JsonSubTypes.Type(name = "Bar", value = Bar.class),
27+
@JsonSubTypes.Type(name = "Baz", value = Baz.class)
28+
})
29+
interface Strategy {
30+
}
31+
32+
static class Foo implements Strategy {
33+
@JsonProperty private final int foo;
34+
@JsonCreator Foo(@JsonProperty("foo") int foo) {
35+
this.foo = foo;
36+
}
37+
}
38+
39+
static class Bar implements Strategy {
40+
@JsonProperty private final boolean bar;
41+
@JsonCreator Bar(@JsonProperty("bar") boolean bar) {
42+
this.bar = bar;
43+
}
44+
}
45+
46+
static class Baz implements Strategy {
47+
@JsonProperty private final String baz;
48+
@JsonCreator Baz(@JsonProperty("baz") String baz) {
49+
this.baz = baz;
50+
}
51+
}
52+
53+
/*
54+
/**********************************************************************
55+
/* Test methods
56+
/**********************************************************************
57+
*/
58+
59+
final ObjectMapper MAPPER = mapperWithModule();
60+
61+
public void testOptionalMapsFoo() throws Exception {
62+
63+
ImmutableMap<String, Object> foo = ImmutableMap.<String, Object>builder()
64+
.put("name", "foo strategy")
65+
.put("strategy", ImmutableMap.builder()
66+
.put("type", "Foo")
67+
.put("foo", 42)
68+
.build())
69+
.build();
70+
_test(MAPPER, foo);
71+
}
72+
73+
public void testOptionalMapsBar() throws Exception {
74+
75+
ImmutableMap<String, Object> bar = ImmutableMap.<String, Object>builder()
76+
.put("name", "bar strategy")
77+
.put("strategy", ImmutableMap.builder()
78+
.put("type", "Bar")
79+
.put("bar", true)
80+
.build())
81+
.build();
82+
_test(MAPPER, bar);
83+
}
84+
85+
public void testOptionalMapsBaz() throws Exception {
86+
ImmutableMap<String, Object> baz = ImmutableMap.<String, Object>builder()
87+
.put("name", "baz strategy")
88+
.put("strategy", ImmutableMap.builder()
89+
.put("type", "Baz")
90+
.put("baz", "hello world!")
91+
.build())
92+
.build();
93+
_test(MAPPER, baz);
94+
}
95+
96+
private void _test(ObjectMapper m, Map<String, ?> map) throws Exception
97+
{
98+
String json = m.writeValueAsString(map);
99+
100+
ContainerA objA = m.readValue(json, ContainerA.class);
101+
assertNotNull(objA);
102+
103+
ContainerB objB = m.readValue(json, ContainerB.class);
104+
assertNotNull(objB);
105+
}
106+
}

0 commit comments

Comments
 (0)