1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.reflection.wrapper;
17
18 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertNull;
22 import static org.junit.jupiter.api.Assertions.assertTrue;
23 import static org.junit.jupiter.api.Assertions.fail;
24
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.LinkedHashMap;
28 import java.util.List;
29 import java.util.Map;
30
31 import org.apache.ibatis.reflection.DefaultReflectorFactory;
32 import org.apache.ibatis.reflection.MetaObject;
33 import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
34 import org.apache.ibatis.reflection.factory.ObjectFactory;
35 import org.apache.ibatis.reflection.property.PropertyTokenizer;
36 import org.junit.jupiter.api.Test;
37 import org.junit.jupiter.params.ParameterizedTest;
38 import org.junit.jupiter.params.provider.CsvSource;
39
40 class MapWrapperTest {
41
42 @Test
43 void assertBasicOperations() {
44 Map<String, Object> map = new LinkedHashMap<>();
45 map.put("a", "100");
46 map.put("b", null);
47 map.put("my_name", Integer.valueOf(200));
48 MetaObject metaObj = MetaObject.forObject(map, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(),
49 new DefaultReflectorFactory());
50 assertFalse(metaObj.isCollection());
51 assertTrue(metaObj.hasGetter("a"));
52 assertTrue(metaObj.hasSetter("a"));
53 assertTrue(metaObj.hasGetter("b.anykey"));
54 assertEquals("a", metaObj.findProperty("a", false));
55 assertEquals("b", metaObj.findProperty("b", false));
56 assertEquals("my_name", metaObj.findProperty("my_name", false));
57 assertEquals("my_name", metaObj.findProperty("my_name", true));
58 assertArrayEquals(new String[] { "a", "b", "my_name" }, metaObj.getGetterNames());
59 assertArrayEquals(new String[] { "a", "b", "my_name" }, metaObj.getSetterNames());
60 assertEquals(String.class, metaObj.getGetterType("a"));
61 assertEquals(Object.class, metaObj.getGetterType("b"));
62 assertEquals(Integer.class, metaObj.getGetterType("my_name"));
63 assertEquals(String.class, metaObj.getSetterType("a"));
64 assertEquals(Object.class, metaObj.getSetterType("b"));
65 assertEquals(Integer.class, metaObj.getSetterType("my_name"));
66 assertEquals("100", metaObj.getValue("a"));
67 assertNull(metaObj.getValue("b"));
68 assertEquals(Integer.valueOf(200), metaObj.getValue("my_name"));
69 try {
70 metaObj.add("x");
71 fail();
72 } catch (UnsupportedOperationException e) {
73
74 }
75 try {
76 metaObj.addAll(Arrays.asList("x", "y"));
77 fail();
78 } catch (UnsupportedOperationException e) {
79
80 }
81 metaObj.setValue("a", Long.valueOf(900L));
82 assertEquals(Long.valueOf(900L), map.get("a"));
83 }
84
85 @Test
86 void assertNonExistentKey() {
87 Map<String, Object> map = new HashMap<>();
88 map.put("a", "100");
89 MetaObject metaObj = MetaObject.forObject(map, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(),
90 new DefaultReflectorFactory());
91 assertEquals("anykey", metaObj.findProperty("anykey", false));
92 assertFalse(metaObj.hasGetter("anykey"));
93 assertFalse(metaObj.hasGetter("child.anykey"));
94 assertEquals(Object.class, metaObj.getGetterType("anykey"));
95 assertEquals(Object.class, metaObj.getGetterType("child.anykey"));
96 assertTrue(metaObj.hasSetter("anykey"));
97 assertTrue(metaObj.hasSetter("child.anykey"));
98 assertEquals(Object.class, metaObj.getSetterType("anykey"));
99 assertEquals(Object.class, metaObj.getSetterType("child.anykey"));
100 assertNull(metaObj.getValue("anykey"));
101
102 metaObj.setValue("anykey", Integer.valueOf(200));
103 metaObj.setValue("child.anykey", Integer.valueOf(300));
104 assertEquals(3, map.size());
105 assertEquals(Integer.valueOf(200), map.get("anykey"));
106 @SuppressWarnings("unchecked")
107 Map<String, Object> childMap = (Map<String, Object>) map.get("child");
108 assertEquals(Integer.valueOf(300), childMap.get("anykey"));
109 }
110
111 @Test
112 void assertChildBean() {
113 Map<String, Object> map = new HashMap<>();
114 TestBean bean = new TestBean();
115 bean.setPropA("aaa");
116 map.put("bean", bean);
117 MetaObject metaObj = MetaObject.forObject(map, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(),
118 new DefaultReflectorFactory());
119 assertTrue(metaObj.hasGetter("bean.propA"));
120 assertEquals(String.class, metaObj.getGetterType("bean.propA"));
121 assertEquals(String.class, metaObj.getSetterType("bean.propA"));
122 assertEquals("aaa", metaObj.getValue("bean.propA"));
123
124 assertNull(metaObj.getValue("bean.propB"));
125 metaObj.setValue("bean.propB", "bbb");
126 assertEquals("bbb", bean.getPropB());
127
128 metaObj.setValue("bean.propA", "ccc");
129 assertEquals("ccc", bean.getPropA());
130 }
131
132 static class TestBean {
133 private String propA;
134 private String propB;
135
136 public String getPropA() {
137 return propA;
138 }
139
140 public void setPropA(String propA) {
141 this.propA = propA;
142 }
143
144 public String getPropB() {
145 return propB;
146 }
147
148 public void setPropB(String propB) {
149 this.propB = propB;
150 }
151 }
152
153 @Test
154 void accessIndexedList() {
155 Map<String, Object> map = new HashMap<>();
156 List<String> list = Arrays.asList("a", "b", "c");
157 map.put("list", list);
158 MetaObject metaObj = MetaObject.forObject(map, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(),
159 new DefaultReflectorFactory());
160 assertEquals("b", metaObj.getValue("list[1]"));
161
162 metaObj.setValue("list[2]", "x");
163 assertEquals("x", list.get(2));
164
165 try {
166 metaObj.setValue("list[3]", "y");
167 fail();
168 } catch (IndexOutOfBoundsException e) {
169
170 }
171
172 assertTrue(metaObj.hasGetter("list[1]"));
173 assertTrue(metaObj.hasSetter("list[1]"));
174
175
176 }
177
178 @Test
179 void accessIndexedMap() {
180 Map<String, Object> map = new HashMap<>();
181 Map<String, String> submap = new HashMap<>();
182 submap.put("a", "100");
183 submap.put("b", "200");
184 submap.put("c", "300");
185 map.put("submap", submap);
186 MetaObject metaObj = MetaObject.forObject(map, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(),
187 new DefaultReflectorFactory());
188 assertEquals("200", metaObj.getValue("submap[b]"));
189
190 metaObj.setValue("submap[c]", "999");
191 assertEquals("999", submap.get("c"));
192
193 metaObj.setValue("submap[d]", "400");
194 assertEquals(4, submap.size());
195 assertEquals("400", submap.get("d"));
196
197 assertTrue(metaObj.hasGetter("submap[b]"));
198 assertTrue(metaObj.hasGetter("submap[anykey]"));
199 assertTrue(metaObj.hasSetter("submap[d]"));
200 assertTrue(metaObj.hasSetter("submap[anykey]"));
201 }
202
203 @ParameterizedTest
204 @CsvSource({ "abc[def]", "abc.def", "abc.def.ghi", "abc[d.ef].ghi" })
205 void customMapWrapper(String key) {
206 Map<String, Object> map = new HashMap<>();
207 MetaObject metaObj = MetaObject.forObject(map, new DefaultObjectFactory(), new FlatMapWrapperFactory(),
208 new DefaultReflectorFactory());
209 metaObj.setValue(key, "1");
210 assertEquals("1", map.get(key));
211 assertEquals("1", metaObj.getValue(key));
212 }
213
214 static class FlatMapWrapperFactory implements ObjectWrapperFactory {
215 @Override
216 public boolean hasWrapperFor(Object object) {
217 return object instanceof Map;
218 }
219
220 @SuppressWarnings("unchecked")
221 @Override
222 public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
223 return new FlatMapWrapper(metaObject, (Map<String, Object>) object, metaObject.getObjectFactory());
224 }
225 }
226
227 static class FlatMapWrapper extends MapWrapper {
228 public FlatMapWrapper(MetaObject metaObject, Map<String, Object> map, ObjectFactory objectFactory) {
229 super(metaObject, map);
230 }
231
232 @Override
233 public Object get(PropertyTokenizer prop) {
234 String key;
235 if (prop.getChildren() == null) {
236 key = prop.getIndexedName();
237 } else {
238 key = prop.getIndexedName() + "." + prop.getChildren();
239 }
240 return map.get(key);
241 }
242
243 @Override
244 public void set(PropertyTokenizer prop, Object value) {
245 String key;
246 if (prop.getChildren() == null) {
247 key = prop.getIndexedName();
248 } else {
249 key = prop.getIndexedName() + "." + prop.getChildren();
250 }
251 map.put(key, value);
252 }
253 }
254
255 }