Skip to content

Instantly share code, notes, and snippets.

@bbeck
Last active August 29, 2015 14:00
Show Gist options
  • Save bbeck/934d787cc36c61c3e8a0 to your computer and use it in GitHub Desktop.
Save bbeck/934d787cc36c61c3e8a0 to your computer and use it in GitHub Desktop.
Jackson bug with polymorphic deserialization involving Guava optional
package com.bazaarvoice.jackson;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.MappingJsonFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.guava.GuavaModule;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
public class Bug {
static class ContainerA {
@JsonProperty private Optional<String> name = Optional.absent();
@JsonProperty private Optional<Strategy> strategy = Optional.absent();
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("name", name)
.add("strategy", strategy)
.toString();
}
}
static class ContainerB {
@JsonProperty private Optional<String> name = Optional.absent();
@JsonProperty private Strategy strategy = null;
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("name", name)
.add("strategy", strategy)
.toString();
}
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(name = "Foo", value = Foo.class),
@JsonSubTypes.Type(name = "Bar", value = Bar.class),
@JsonSubTypes.Type(name = "Baz", value = Baz.class)
})
static interface Strategy {
}
static class Foo implements Strategy {
@JsonProperty private final int foo;
@JsonCreator Foo(@JsonProperty("foo") int foo) {
this.foo = foo;
}
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("foo", foo)
.toString();
}
}
static class Bar implements Strategy {
@JsonProperty private final boolean bar;
@JsonCreator Bar(@JsonProperty("bar") boolean bar) {
this.bar = bar;
}
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("bar", bar)
.toString();
}
}
static class Baz implements Strategy {
@JsonProperty private final String baz;
@JsonCreator Baz(@JsonProperty("baz") String baz) {
this.baz = baz;
}
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("baz", baz)
.toString();
}
}
private static final ObjectMapper mapper = new MappingJsonFactory().getCodec().registerModule(new GuavaModule());
public static void main(String[] args) throws JsonProcessingException {
ImmutableMap<String, Object> foo = ImmutableMap.<String, Object>builder()
.put("name", "foo strategy")
.put("strategy", ImmutableMap.builder()
.put("type", "Foo")
.put("foo", 42)
.build())
.build();
ImmutableMap<String, Object> bar = ImmutableMap.<String, Object>builder()
.put("name", "bar strategy")
.put("strategy", ImmutableMap.builder()
.put("type", "Boo")
.put("bar", true)
.build())
.build();
ImmutableMap<String, Object> baz = ImmutableMap.<String, Object>builder()
.put("name", "baz strategy")
.put("strategy", ImmutableMap.builder()
.put("type", "Baz")
.put("baz", "hello world!")
.build())
.build();
test(foo);
test(bar);
test(baz);
}
private static void test(Map<String, ?> map) throws JsonProcessingException {
String json = mapper.writeValueAsString(map);
System.out.println("Running test case on: " + json);
System.out.println();
System.out.println("Trying ContainerA:");
try {
ContainerA obj = mapper.readValue(json, ContainerA.class);
System.out.println(obj);
} catch (Exception e) {
e.printStackTrace(System.out);
}
System.out.println();
System.out.println("Trying ContainerB:");
try {
ContainerB obj = mapper.readValue(json, ContainerB.class);
System.out.println(obj);
} catch (Exception e) {
e.printStackTrace(System.out);
}
System.out.println();
System.out.println();
System.out.println("===============================");
System.out.println();
}
}
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bazaarvoice</groupId>
<artifactId>jackson-bug</artifactId>
<version>1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Jackson Bug</name>
<description>Jackson Bug</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- <jackson.version>2.2.3</jackson.version> --> <!-- Works fine with 2.2.3 -->
<jackson.version>2.3.2</jackson.version> <!-- Doesn't work with 2.3.2 -->
</properties>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-guava</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
</project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment