aboutsummaryrefslogtreecommitdiff
path: root/src/test/java/com/fasterxml/jackson/databind/jsontype
diff options
context:
space:
mode:
authorJoe Koshakow <koshy44@gmail.com>2019-10-25 00:14:05 -0400
committerTatu Saloranta <tsaloranta@gmail.com>2019-11-05 21:49:01 -0800
commit3ac186c506f4180e22ac4e75b7cfd5bc5e6c6c2c (patch)
tree5413f3e04539643ee059470cb85aa96a837415aa /src/test/java/com/fasterxml/jackson/databind/jsontype
parent6042bcfb0714429aa11ef87db27b7c5ef19589ea (diff)
downloadjackson-databind-3ac186c506f4180e22ac4e75b7cfd5bc5e6c6c2c.tar.gz
Allow registering the same subtype multiple times
Before this commit NamedType hashes only on it's class and not on the name. This only allowed you to register a class once using ObjectMapper.registerSubtypes(NamedType... types). This commit now uses name field to hash NamedTypes. This successfully allows you to deserialize objects of the same type but different name. Serializing objects of the same type but different name (for example fields of a POJO) still has some issues. 1. SerializerProvider caches Serializers based on class and doesn't take name into account. 2. TypeIdResolver has no method to resolve an id that takes name into account. Therefore when resolving an id we only have the value and type. 3. TypeNameIdResolver stores type and id information as a Map<String, String> that maps type to id, ignoring name Fixes #2515
Diffstat (limited to 'src/test/java/com/fasterxml/jackson/databind/jsontype')
-rw-r--r--src/test/java/com/fasterxml/jackson/databind/jsontype/TestSubtypes.java71
1 files changed, 63 insertions, 8 deletions
diff --git a/src/test/java/com/fasterxml/jackson/databind/jsontype/TestSubtypes.java b/src/test/java/com/fasterxml/jackson/databind/jsontype/TestSubtypes.java
index 0ffd4564c..c6fa2bb35 100644
--- a/src/test/java/com/fasterxml/jackson/databind/jsontype/TestSubtypes.java
+++ b/src/test/java/com/fasterxml/jackson/databind/jsontype/TestSubtypes.java
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.Version;
import java.util.*;
+import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
@@ -38,7 +39,7 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest
// "Empty" bean
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME)
static abstract class BaseBean { }
-
+
static class EmptyBean extends BaseBean { }
static class EmptyNonFinal { }
@@ -49,7 +50,7 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest
{
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME)
public SuperType value;
-
+
public PropertyBean() { this(null); }
public PropertyBean(SuperType v) { value = v; }
}
@@ -70,6 +71,28 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest
public int a;
}
+ static class Sub extends SuperTypeWithoutDefault {
+ public int a;
+
+ public Sub(){}
+ public Sub(int a) {
+ this.a = a;
+ }
+ }
+
+ static class POJOWrapper {
+ @JsonProperty
+ Sub sub1;
+ @JsonProperty
+ Sub sub2;
+
+ public POJOWrapper(){}
+ public POJOWrapper(Sub sub1, Sub sub2) {
+ this.sub1 = sub1;
+ this.sub2 = sub2;
+ }
+ }
+
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.PROPERTY, property="type")
@JsonSubTypes({ @JsonSubTypes.Type(ImplX.class),
@JsonSubTypes.Type(ImplY.class) })
@@ -118,7 +141,7 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest
public Issue1125Wrapper() { }
public Issue1125Wrapper(Base1125 v) { value = v; }
}
-
+
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, defaultImpl=Default1125.class)
@JsonSubTypes({ @JsonSubTypes.Type(Interm1125.class) })
static class Base1125 {
@@ -204,7 +227,7 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest
result = mapper.readValue(json, PropertyBean.class);
assertSame(SubC.class, result.value.getClass());
}
-
+
public void testSerialization() throws Exception
{
// serialization can detect type name ok without anything extra:
@@ -217,7 +240,17 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest
assertEquals("{\"@type\":\"typeB\",\"b\":1}", mapper.writeValueAsString(bean));
// and default name ought to be simple class name; with context
- assertEquals("{\"@type\":\"TestSubtypes$SubD\",\"d\":0}", mapper.writeValueAsString(new SubD()));
+ assertEquals("{\"@type\":\"TestSubtypes$SubD\",\"d\":0}", mapper.writeValueAsString(new SubD()));
+ }
+
+ public void testSerializationWithDuplicateRegisteredSubtypes() throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.registerSubtypes(new NamedType(Sub.class, "sub1"));
+ mapper.registerSubtypes(new NamedType(Sub.class, "sub2"));
+
+ // the first registered type name is used for serialization
+ Sub sub = new Sub(15);
+ assertEquals("{\"#type\":\"sub1\",\"a\":15}", mapper.writeValueAsString(sub));
}
public void testDeserializationNonNamed() throws Exception
@@ -247,6 +280,28 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest
assertEquals(-4, ((SubD) bean).d);
}
+ public void testDeserializationWithDuplicateRegisteredSubtypes()
+ throws Exception {
+ ObjectMapper mapper = new ObjectMapper();
+
+ // We can register the same class with different names
+ mapper.registerSubtypes(new NamedType(Sub.class, "sub1"));
+ mapper.registerSubtypes(new NamedType(Sub.class, "sub2"));
+
+ // fields of a POJO will be deserialized correctly according to their field name
+ POJOWrapper pojoWrapper = mapper.readValue("{\"sub1\":{\"#type\":\"sub1\",\"a\":10},\"sub2\":{\"#type\":\"sub2\",\"a\":50}}", POJOWrapper.class);
+ assertEquals(10, pojoWrapper.sub1.a);
+ assertEquals(50, pojoWrapper.sub2.a);
+
+ // Instances of the same object can be deserialized with multiple names
+ SuperTypeWithoutDefault sub1 = mapper.readValue("{\"#type\":\"sub1\", \"a\":20}", SuperTypeWithoutDefault.class);
+ assertSame(Sub.class, sub1.getClass());
+ assertEquals(20, ((Sub) sub1).a);
+ SuperTypeWithoutDefault sub2 = mapper.readValue("{\"#type\":\"sub2\", \"a\":30}", SuperTypeWithoutDefault.class);
+ assertSame(Sub.class, sub2.getClass());
+ assertEquals(30, ((Sub) sub2).a);
+ }
+
// Trying to reproduce [JACKSON-366]
public void testEmptyBean() throws Exception
{
@@ -295,7 +350,7 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest
public void testDefaultImplViaModule() throws Exception
{
final String JSON = "{\"a\":123}";
-
+
// first: without registration etc, epic fail:
try {
MAPPER.readValue(JSON, SuperTypeWithoutDefault.class);
@@ -317,7 +372,7 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest
bean = mapper.readValue("{\"#type\":\"foobar\"}", SuperTypeWithoutDefault.class);
assertEquals(DefaultImpl505.class, bean.getClass());
assertEquals(0, ((DefaultImpl505) bean).a);
-
+
}
public void testErrorMessage() throws Exception {
@@ -361,7 +416,7 @@ public class TestSubtypes extends com.fasterxml.jackson.databind.BaseMapTest
public void testIssue1125NonDefault() throws Exception
{
String json = MAPPER.writeValueAsString(new Issue1125Wrapper(new Impl1125(1, 2, 3)));
-
+
Issue1125Wrapper result = MAPPER.readValue(json, Issue1125Wrapper.class);
assertNotNull(result.value);
assertEquals(Impl1125.class, result.value.getClass());