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

Commit b5aa0c3

Browse files
committed
Fix #42 for 2.3.4 as well
1 parent dd80f92 commit b5aa0c3

File tree

3 files changed

+148
-5
lines changed

3 files changed

+148
-5
lines changed

release-notes/VERSION

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
Project: jackson-datatype-guava
2-
Version: 2.3.3 (10-Apr-2014)
2+
Version: 2.3.4 (xx-xxx-2014)
33

4-
#37: `Optional` not correctly deserialized from JSON null, if inside a Collection
5-
(reported by JYang-Addepar@github)
6-
#41: `Multimap` serializer does not honor @JsonInclude(JsonInclude.Include.NON_EMPTY)
7-
(reported by Olve S-H)
4+
#42: Polymorphic deserialization involving Guava Optional<T> is broken.
5+
(reported by bbeck@github)
86

97
------------------------------------------------------------------------
108
=== History: ===
119
------------------------------------------------------------------------
1210

11+
2.3.3 (10-Apr-2014)
12+
13+
#37: `Optional` not correctly deserialized from JSON null, if inside a Collection
14+
(reported by JYang-Addepar@github)
15+
#41: `Multimap` serializer does not honor @JsonInclude(JsonInclude.Include.NON_EMPTY)
16+
(reported by Olve S-H)
17+
1318
2.3.2 (01-Mar-2014)
1419

1520
#36: Improve Range deserializer to work with older Guava versions (10-)

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
package com.fasterxml.jackson.datatype.guava.deser;
22

33
import java.io.IOException;
4+
import java.util.Collection;
45

56
import com.fasterxml.jackson.core.JsonParser;
67
import com.fasterxml.jackson.core.JsonProcessingException;
78
import com.fasterxml.jackson.core.JsonToken;
9+
import com.fasterxml.jackson.databind.BeanDescription;
810
import com.fasterxml.jackson.databind.BeanProperty;
11+
import com.fasterxml.jackson.databind.DeserializationConfig;
912
import com.fasterxml.jackson.databind.DeserializationContext;
1013
import com.fasterxml.jackson.databind.JavaType;
1114
import com.fasterxml.jackson.databind.JsonDeserializer;
1215
import com.fasterxml.jackson.databind.JsonMappingException;
1316
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
1417
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
18+
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
19+
import com.fasterxml.jackson.databind.jsontype.NamedType;
1520
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
21+
import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
1622
import com.google.common.base.Optional;
1723

1824
public class GuavaOptionalDeserializer
@@ -77,6 +83,9 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
7783
if (deser == null) {
7884
deser = ctxt.findContextualValueDeserializer(_referenceType, property);
7985
}
86+
if (typeDeser == null) {
87+
typeDeser = _findTypeDeserializer(ctxt.getConfig(), _referenceType);
88+
}
8089
if (typeDeser != null) {
8190
typeDeser = typeDeser.forProperty(property);
8291
}
@@ -85,6 +94,29 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
8594
}
8695
return withResolved(typeDeser, deser);
8796
}
97+
98+
/**
99+
* Method that is temporarily copied here, until 2.4 is released (at which point
100+
* jackson-databind has it available via DeserializationConfig)
101+
*/
102+
private TypeDeserializer _findTypeDeserializer(DeserializationConfig cfg, JavaType baseType)
103+
throws JsonMappingException
104+
{
105+
BeanDescription bean = cfg.introspectClassAnnotations(baseType.getRawClass());
106+
AnnotatedClass ac = bean.getClassInfo();
107+
TypeResolverBuilder<?> b = cfg.getAnnotationIntrospector().findTypeResolver(cfg, ac, baseType);
108+
109+
Collection<NamedType> subtypes = null;
110+
if (b == null) {
111+
b = cfg.getDefaultTyper(baseType);
112+
if (b == null) {
113+
return null;
114+
}
115+
} else {
116+
subtypes = cfg.getSubtypeResolver().collectAndResolveSubtypes(ac, cfg, cfg.getAnnotationIntrospector());
117+
}
118+
return b.buildTypeDeserializer(cfg, baseType, subtypes);
119+
}
88120

89121
@Override
90122
public Optional<?> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
Lines changed: 106 additions & 0 deletions
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)