1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.beanutils2;
19
20 import java.lang.reflect.Array;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Objects;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 public class BasicDynaBean implements DynaBean {
41
42 private static final Short SHORT_ZERO = Short.valueOf((short) 0);
43
44 private static final Long LONG_ZERO = Long.valueOf(0);
45
46 private static final Integer INTEGER_ZERO = Integer.valueOf(0);
47
48 private static final Float FLOAT_ZERO = Float.valueOf((float) 0.0);
49
50 private static final Double DOUBLE_ZERO = Double.valueOf(0.0);
51
52 private static final Character CHARACTER_ZERO = Character.valueOf((char) 0);
53
54 private static final Byte BYTE_ZERO = Byte.valueOf((byte) 0);
55
56 private static final long serialVersionUID = 1L;
57
58
59
60
61 protected DynaClass dynaClass;
62
63
64
65
66 protected HashMap<String, Object> values = new HashMap<>();
67
68
69 private transient Map<String, Object> mapDecorator;
70
71
72
73
74
75
76 public BasicDynaBean(final DynaClass dynaClass) {
77 this.dynaClass = dynaClass;
78 }
79
80
81
82
83
84
85
86
87
88 @Override
89 public boolean contains(final String name, final String key) {
90 final Object value = values.get(name);
91 requireMappedValue(name, key, value);
92 if (value instanceof Map) {
93 return ((Map<?, ?>) value).containsKey(key);
94 }
95 throw new IllegalArgumentException("Non-mapped property for '" + name + "(" + key + ")'");
96 }
97
98
99
100
101
102
103
104
105 @Override
106 public Object get(final String name) {
107
108 final Object value = values.get(name);
109 if (value != null) {
110 return value;
111 }
112
113 final Class<?> type = getDynaProperty(name).getType();
114 if (!type.isPrimitive()) {
115 return value;
116 }
117
118 if (type == Boolean.TYPE) {
119 return Boolean.FALSE;
120 }
121 if (type == Byte.TYPE) {
122 return BYTE_ZERO;
123 }
124 if (type == Character.TYPE) {
125 return CHARACTER_ZERO;
126 }
127 if (type == Double.TYPE) {
128 return DOUBLE_ZERO;
129 }
130 if (type == Float.TYPE) {
131 return FLOAT_ZERO;
132 }
133 if (type == Integer.TYPE) {
134 return INTEGER_ZERO;
135 }
136 if (type == Long.TYPE) {
137 return LONG_ZERO;
138 }
139 if (type == Short.TYPE) {
140 return SHORT_ZERO;
141 }
142 return null;
143 }
144
145
146
147
148
149
150
151
152
153
154
155
156 @Override
157 public Object get(final String name, final int index) {
158 final Object value = values.get(name);
159 Objects.requireNonNull(value, "No indexed value for '" + name + "[" + index + "]'");
160 if (value.getClass().isArray()) {
161 return Array.get(value, index);
162 }
163 if (value instanceof List) {
164 return ((List<?>) value).get(index);
165 }
166 throw new IllegalArgumentException("Non-indexed property for '" + name + "[" + index + "]'");
167 }
168
169
170
171
172
173
174
175
176
177
178 @Override
179 public Object get(final String name, final String key) {
180 final Object value = values.get(name);
181 requireMappedValue(name, key, value);
182 if (value instanceof Map) {
183 return ((Map<?, ?>) value).get(key);
184 }
185 throw new IllegalArgumentException("Non-mapped property for '" + name + "(" + key + ")'");
186
187 }
188
189
190
191
192
193
194 @Override
195 public DynaClass getDynaClass() {
196 return this.dynaClass;
197 }
198
199
200
201
202
203
204
205
206 protected DynaProperty getDynaProperty(final String name) {
207 final DynaProperty descriptor = getDynaClass().getDynaProperty(name);
208 if (descriptor == null) {
209 throw new IllegalArgumentException("Invalid property name '" + name + "'");
210 }
211 return descriptor;
212
213 }
214
215
216
217
218
219
220
221
222
223
224
225
226
227 public Map<String, Object> getMap() {
228
229 if (mapDecorator == null) {
230 mapDecorator = new DynaBeanPropertyMapDecorator(this);
231 }
232 return mapDecorator;
233
234 }
235
236
237
238
239
240
241
242
243 protected boolean isAssignable(final Class<?> dest, final Class<?> source) {
244
245 return dest.isAssignableFrom(source) ||
246 dest == Boolean.TYPE && source == Boolean.class ||
247 dest == Byte.TYPE && source == Byte.class ||
248 dest == Character.TYPE && source == Character.class ||
249 dest == Double.TYPE && source == Double.class ||
250 dest == Float.TYPE && source == Float.class ||
251 dest == Integer.TYPE && source == Integer.class ||
252 dest == Long.TYPE && source == Long.class ||
253 dest == Short.TYPE && source == Short.class;
254
255 }
256
257
258
259
260
261
262
263
264 @Override
265 public void remove(final String name, final String key) {
266 final Object value = values.get(name);
267 requireMappedValue(name, key, value);
268 if (!(value instanceof Map)) {
269 throw new IllegalArgumentException("Non-mapped property for '" + name + "(" + key + ")'");
270 }
271 ((Map<?, ?>) value).remove(key);
272 }
273
274 private void requireMappedValue(final String name, final String key, final Object value) {
275 Objects.requireNonNull(value, () -> "No mapped value for '" + name + "(" + key + ")'");
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289 @Override
290 public void set(final String name, final int index, final Object value) {
291 final Object prop = values.get(name);
292 Objects.requireNonNull(prop, "No indexed value for '" + name + "[" + index + "]'");
293 if (prop.getClass().isArray()) {
294 Array.set(prop, index, value);
295 } else if (prop instanceof List) {
296 try {
297 @SuppressWarnings("unchecked")
298
299
300 final List<Object> list = (List<Object>) prop;
301 list.set(index, value);
302 } catch (final ClassCastException e) {
303 throw new ConversionException(e.getMessage());
304 }
305 } else {
306 throw new IllegalArgumentException("Non-indexed property for '" + name + "[" + index + "]'");
307 }
308 }
309
310
311
312
313
314
315
316
317
318
319 @Override
320 public void set(final String name, final Object value) {
321 final DynaProperty descriptor = getDynaProperty(name);
322 if (value == null) {
323 if (descriptor.getType().isPrimitive()) {
324 throw new NullPointerException("Primitive value for '" + name + "'");
325 }
326 } else if (!isAssignable(descriptor.getType(), value.getClass())) {
327 throw ConversionException.format("Cannot assign value of type '%s' to property '%s' of type '%s'", value.getClass().getName(), name,
328 descriptor.getType().getName());
329 }
330 values.put(name, value);
331 }
332
333
334
335
336
337
338
339
340
341
342
343 @SuppressWarnings("unchecked")
344 @Override
345 public void set(final String name, final String key, final Object value) {
346 final Object prop = values.get(name);
347 requireMappedValue(name, key, prop);
348 if (!(prop instanceof Map)) {
349 throw new IllegalArgumentException("Non-mapped property for '" + name + "(" + key + ")'");
350 }
351
352
353 ((Map<String, Object>) prop).put(key, value);
354 }
355
356 }