blob: 088860e4b333311ccd2eab4a57b77afec9790622 [file] [log] [blame]
Tatu Salorantaa63c2032011-12-24 00:26:53 -08001package com.fasterxml.jackson.databind.module;
2
3import java.util.*;
4
Tatu Salorantafce83262018-05-01 17:02:13 -07005import com.fasterxml.jackson.annotation.JsonCreator;
6import com.fasterxml.jackson.annotation.JsonProperty;
Tatu Salorantaa63c2032011-12-24 00:26:53 -08007import com.fasterxml.jackson.core.Version;
8import com.fasterxml.jackson.databind.BaseMapTest;
9import com.fasterxml.jackson.databind.ObjectMapper;
10import com.fasterxml.jackson.databind.module.SimpleModule;
11
12public class TestAbstractTypes extends BaseMapTest
13{
Tatu Salorantaa63c2032011-12-24 00:26:53 -080014 static class MyString implements CharSequence
15 {
16 protected String value;
17
18 public MyString(String s) { value = s; }
19
Tatu Saloranta9439a312013-03-02 13:13:09 -080020 @Override
Tatu Salorantaa63c2032011-12-24 00:26:53 -080021 public char charAt(int index) {
22 return value.charAt(index);
23 }
24
Tatu Saloranta9439a312013-03-02 13:13:09 -080025 @Override
Tatu Salorantaa63c2032011-12-24 00:26:53 -080026 public int length() {
27 return value.length();
28 }
29
Tatu Saloranta9439a312013-03-02 13:13:09 -080030 @Override
Tatu Salorantaa63c2032011-12-24 00:26:53 -080031 public CharSequence subSequence(int arg0, int arg1) { return this; }
32 }
Tatu Saloranta20748cc2016-07-18 20:56:08 -070033
Tatu Salorantaa589ee42017-09-18 19:36:40 -070034 public interface Abstract {
35 public int getValue();
36 }
37
38 public static class AbstractImpl implements Abstract {
39 @Override
40 public int getValue() { return 3; }
41 }
42
Tatu Salorantafce83262018-05-01 17:02:13 -070043 // [databind#2019]: mappings from multiple modules
44 public interface Datatype1 {
45 String getValue();
46 }
47
48 public interface Datatype2 {
49 String getValue();
50 }
51
52 static class SimpleDatatype1 implements Datatype1 {
53
54 private final String value;
55
56 @JsonCreator
57 public SimpleDatatype1(@JsonProperty("value") String value) {
58 this.value = value;
59 }
60
61 @Override
62 public String getValue() {
63 return value;
64 }
65 }
66
67 static class SimpleDatatype2 implements Datatype2 {
68 private final String value;
69
70 @JsonCreator
71 public SimpleDatatype2(@JsonProperty("value") String value) {
72 this.value = value;
73 }
74
75 @Override
76 public String getValue() {
77 return value;
78 }
79 }
Tatu Salorantadd7258a2018-08-28 21:40:00 -070080
Tatu Salorantaa63c2032011-12-24 00:26:53 -080081 /*
Tatu Salorantafce83262018-05-01 17:02:13 -070082 /**********************************************************************
Tatu Saloranta20748cc2016-07-18 20:56:08 -070083 /* Test methods
Tatu Salorantafce83262018-05-01 17:02:13 -070084 /**********************************************************************
Tatu Salorantaa63c2032011-12-24 00:26:53 -080085 */
86
87 public void testCollectionDefaulting() throws Exception
88 {
89 ObjectMapper mapper = new ObjectMapper();
90 SimpleModule mod = new SimpleModule("test", Version.unknownVersion());
91 // let's ensure we get hierarchic mapping
92 mod.addAbstractTypeMapping(Collection.class, List.class);
93 mod.addAbstractTypeMapping(List.class, LinkedList.class);
94 mapper.registerModule(mod);
95 Collection<?> result = mapper.readValue("[]", Collection.class);
96 assertEquals(LinkedList.class, result.getClass());
97 }
98
Cowtowncoderbff35ba2015-02-11 15:38:14 -080099 public void testMapDefaultingBasic() throws Exception
Tatu Salorantaa63c2032011-12-24 00:26:53 -0800100 {
101 ObjectMapper mapper = new ObjectMapper();
102 SimpleModule mod = new SimpleModule("test", Version.unknownVersion());
103 // default is HashMap, so:
104 mod.addAbstractTypeMapping(Map.class, TreeMap.class);
105 mapper.registerModule(mod);
106 Map<?,?> result = mapper.readValue("{}", Map.class);
107 assertEquals(TreeMap.class, result.getClass());
108 }
Cowtowncoderbff35ba2015-02-11 15:38:14 -0800109
Cowtowncoderbff35ba2015-02-11 15:38:14 -0800110 // [databind#700]
Cowtowncoder7fee92e2015-02-11 16:15:08 -0800111 public void testDefaultingRecursive() throws Exception
Cowtowncoderbff35ba2015-02-11 15:38:14 -0800112 {
113 ObjectMapper mapper = new ObjectMapper();
114 SimpleModule mod = new SimpleModule("test", Version.unknownVersion());
Cowtowncoder7fee92e2015-02-11 16:15:08 -0800115
116 // defaults: LinkedHashMap, ArrayList
Cowtowncoderbff35ba2015-02-11 15:38:14 -0800117 mod.addAbstractTypeMapping(Map.class, TreeMap.class);
Cowtowncoder7fee92e2015-02-11 16:15:08 -0800118 mod.addAbstractTypeMapping(List.class, LinkedList.class);
119
Cowtowncoderbff35ba2015-02-11 15:38:14 -0800120 mapper.registerModule(mod);
Cowtowncoder7fee92e2015-02-11 16:15:08 -0800121 Object result;
122
123 result = mapper.readValue("[ {} ]", Object.class);
124 assertEquals(LinkedList.class, result.getClass());
Cowtowncoderbff35ba2015-02-11 15:38:14 -0800125 Object v = ((List<?>) result).get(0);
126 assertNotNull(v);
127 assertEquals(TreeMap.class, v.getClass());
Cowtowncoder7fee92e2015-02-11 16:15:08 -0800128
129 result = mapper.readValue("{ \"x\": [ 3 ] }", Object.class);
130 assertEquals(TreeMap.class, result.getClass());
131 Map<?,?> map = (Map<?,?>) result;
132 assertEquals(1, map.size());
133 v = map.get("x");
134 assertNotNull(v);
135 assertEquals(LinkedList.class, v.getClass());
136 assertEquals(1, ((List<?>) v).size());
Cowtowncoderbff35ba2015-02-11 15:38:14 -0800137 }
Cowtowncoderbff35ba2015-02-11 15:38:14 -0800138
Tatu Salorantaa63c2032011-12-24 00:26:53 -0800139 public void testInterfaceDefaulting() throws Exception
140 {
141 ObjectMapper mapper = new ObjectMapper();
142 SimpleModule mod = new SimpleModule("test", Version.unknownVersion());
143 // let's ensure we get hierarchic mapping
144 mod.addAbstractTypeMapping(CharSequence.class, MyString.class);
145 mapper.registerModule(mod);
146 Object result = mapper.readValue(quote("abc"), CharSequence.class);
147 assertEquals(MyString.class, result.getClass());
148 assertEquals("abc", ((MyString) result).value);
Tatu Salorantaa589ee42017-09-18 19:36:40 -0700149
150 // and ditto for POJOs
151 mod = new SimpleModule();
152 mod.addAbstractTypeMapping(Abstract.class, AbstractImpl.class);
153 mapper = new ObjectMapper()
154 .registerModule(mod);
155 Abstract a = mapper.readValue("{}", Abstract.class);
156 assertNotNull(a);
Tatu Salorantaa63c2032011-12-24 00:26:53 -0800157 }
Tatu Salorantafce83262018-05-01 17:02:13 -0700158
159 // [databind#2019]: mappings from multiple modules
Tatu Salorantadd7258a2018-08-28 21:40:00 -0700160 public void testAbstractMappingsFromTwoModules() throws Exception
Tatu Salorantafce83262018-05-01 17:02:13 -0700161 {
Tatu Salorantac7ddf692019-08-23 14:02:52 -0700162 ObjectMapper mapper = newJsonMapper();
Tatu Salorantafce83262018-05-01 17:02:13 -0700163 SimpleModule module1 = new SimpleModule("module1");
164 module1.addAbstractTypeMapping(Datatype1.class, SimpleDatatype1.class);
165
166 SimpleModule module2 = new SimpleModule("module2");
167 module2.addAbstractTypeMapping(Datatype2.class, SimpleDatatype2.class);
168 mapper.registerModules(module1, module2);
169
170 final String JSON_EXAMPLE = "{\"value\": \"aaa\"}";
171 Datatype1 value1 = mapper.readValue(JSON_EXAMPLE, Datatype1.class);
172 assertNotNull(value1);
173
174 Datatype2 value2 = mapper.readValue(JSON_EXAMPLE, Datatype2.class);
175 assertNotNull(value2);
176 }
Tatu Salorantaa63c2032011-12-24 00:26:53 -0800177}