1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.yaml.snakeyaml.constructor;
17
18 import java.lang.reflect.Array;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.EnumMap;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.LinkedHashMap;
25 import java.util.LinkedHashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30 import org.yaml.snakeyaml.composer.Composer;
31 import org.yaml.snakeyaml.composer.ComposerException;
32 import org.yaml.snakeyaml.error.YAMLException;
33 import org.yaml.snakeyaml.introspector.PropertyUtils;
34 import org.yaml.snakeyaml.nodes.MappingNode;
35 import org.yaml.snakeyaml.nodes.Node;
36 import org.yaml.snakeyaml.nodes.NodeId;
37 import org.yaml.snakeyaml.nodes.NodeTuple;
38 import org.yaml.snakeyaml.nodes.ScalarNode;
39 import org.yaml.snakeyaml.nodes.SequenceNode;
40 import org.yaml.snakeyaml.nodes.Tag;
41
42 public abstract class BaseConstructor {
43
44
45
46
47 protected final Map<NodeId, Construct> yamlClassConstructors = new EnumMap<NodeId, Construct>(
48 NodeId.class);
49
50
51
52
53
54
55
56 protected final Map<Tag, Construct> yamlConstructors = new HashMap<Tag, Construct>();
57
58
59
60
61 protected final Map<String, Construct> yamlMultiConstructors = new HashMap<String, Construct>();
62
63 private Composer composer;
64 private final Map<Node, Object> constructedObjects;
65 private final Set<Node> recursiveObjects;
66 private final ArrayList<RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>> maps2fill;
67 private final ArrayList<RecursiveTuple<Set<Object>, Object>> sets2fill;
68
69 protected Tag rootTag;
70 private PropertyUtils propertyUtils;
71 private boolean explicitPropertyUtils;
72
73 public BaseConstructor() {
74 constructedObjects = new HashMap<Node, Object>();
75 recursiveObjects = new HashSet<Node>();
76 maps2fill = new ArrayList<RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>>();
77 sets2fill = new ArrayList<RecursiveTuple<Set<Object>, Object>>();
78 rootTag = null;
79 explicitPropertyUtils = false;
80 }
81
82 public void setComposer(Composer composer) {
83 this.composer = composer;
84 }
85
86
87
88
89
90
91 public boolean checkData() {
92
93 return composer.checkNode();
94 }
95
96
97
98
99
100
101 public Object getData() {
102
103 composer.checkNode();
104 Node node = composer.getNode();
105 if (rootTag != null) {
106 node.setTag(rootTag);
107 }
108 return constructDocument(node);
109 }
110
111
112
113
114
115
116
117
118 public Object getSingleData(Class<?> type) {
119
120 Node node = composer.getSingleNode();
121 if (node != null) {
122 if (Object.class != type) {
123 node.setTag(new Tag(type));
124 } else if (rootTag != null) {
125 node.setTag(rootTag);
126 }
127 return constructDocument(node);
128 }
129 return null;
130 }
131
132
133
134
135
136
137
138
139
140 private Object constructDocument(Node node) {
141 Object data = constructObject(node);
142 fillRecursive();
143 constructedObjects.clear();
144 recursiveObjects.clear();
145 return data;
146 }
147
148 private void fillRecursive() {
149 if (!maps2fill.isEmpty()) {
150 for (RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>> entry : maps2fill) {
151 RecursiveTuple<Object, Object> key_value = entry._2();
152 entry._1().put(key_value._1(), key_value._2());
153 }
154 maps2fill.clear();
155 }
156 if (!sets2fill.isEmpty()) {
157 for (RecursiveTuple<Set<Object>, Object> value : sets2fill) {
158 value._1().add(value._2());
159 }
160 sets2fill.clear();
161 }
162 }
163
164
165
166
167
168
169
170
171
172 protected Object constructObject(Node node) {
173 if (constructedObjects.containsKey(node)) {
174 return constructedObjects.get(node);
175 }
176 if (recursiveObjects.contains(node)) {
177 throw new ConstructorException(null, null, "found unconstructable recursive node",
178 node.getStartMark());
179 }
180 recursiveObjects.add(node);
181 Construct constructor = getConstructor(node);
182 Object data = constructor.construct(node);
183 constructedObjects.put(node, data);
184 recursiveObjects.remove(node);
185 if (node.isTwoStepsConstruction()) {
186 constructor.construct2ndStep(node, data);
187 }
188 return data;
189 }
190
191
192
193
194
195
196
197
198
199
200 protected Construct getConstructor(Node node) {
201 if (node.useClassConstructor()) {
202 return yamlClassConstructors.get(node.getNodeId());
203 } else {
204 Construct constructor = yamlConstructors.get(node.getTag());
205 if (constructor == null) {
206 for (String prefix : yamlMultiConstructors.keySet()) {
207 if (node.getTag().startsWith(prefix)) {
208 return yamlMultiConstructors.get(prefix);
209 }
210 }
211 return yamlConstructors.get(null);
212 }
213 return constructor;
214 }
215 }
216
217 protected Object constructScalar(ScalarNode node) {
218 return node.getValue();
219 }
220
221 protected List<Object> createDefaultList(int initSize) {
222 return new ArrayList<Object>(initSize);
223 }
224
225 protected Set<Object> createDefaultSet(int initSize) {
226 return new LinkedHashSet<Object>(initSize);
227 }
228
229 @SuppressWarnings("unchecked")
230 protected <T> T[] createArray(Class<T> type, int size) {
231 return (T[]) Array.newInstance(type.getComponentType(), size);
232 }
233
234 @SuppressWarnings("unchecked")
235 protected List<? extends Object> constructSequence(SequenceNode node) {
236 List<Object> result;
237 if (List.class.isAssignableFrom(node.getType()) && !node.getType().isInterface()) {
238
239 try {
240 result = (List<Object>) node.getType().newInstance();
241 } catch (Exception e) {
242 throw new YAMLException(e);
243 }
244 } else {
245 result = createDefaultList(node.getValue().size());
246 }
247 constructSequenceStep2(node, result);
248 return result;
249
250 }
251
252 @SuppressWarnings("unchecked")
253 protected Set<? extends Object> constructSet(SequenceNode node) {
254 Set<Object> result;
255 if (!node.getType().isInterface()) {
256
257 try {
258 result = (Set<Object>) node.getType().newInstance();
259 } catch (Exception e) {
260 throw new YAMLException(e);
261 }
262 } else {
263 result = createDefaultSet(node.getValue().size());
264 }
265 constructSequenceStep2(node, result);
266 return result;
267
268 }
269
270 protected Object constructArray(SequenceNode node) {
271 return constructArrayStep2(node, createArray(node.getType(), node.getValue().size()));
272 }
273
274 protected void constructSequenceStep2(SequenceNode node, Collection<Object> collection) {
275 for (Node child : node.getValue()) {
276 collection.add(constructObject(child));
277 }
278 }
279
280 protected Object constructArrayStep2(SequenceNode node, Object array) {
281 int index = 0;
282 for (Node child : node.getValue()) {
283 Array.set(array, index++, constructObject(child));
284 }
285 return array;
286 }
287
288 protected Map<Object, Object> createDefaultMap() {
289
290 return new LinkedHashMap<Object, Object>();
291 }
292
293 protected Set<Object> createDefaultSet() {
294
295 return new LinkedHashSet<Object>();
296 }
297
298 protected Set<Object> constructSet(MappingNode node) {
299 Set<Object> set = createDefaultSet();
300 constructSet2ndStep(node, set);
301 return set;
302 }
303
304 protected Map<Object, Object> constructMapping(MappingNode node) {
305 Map<Object, Object> mapping = createDefaultMap();
306 constructMapping2ndStep(node, mapping);
307 return mapping;
308 }
309
310 protected void constructMapping2ndStep(MappingNode node, Map<Object, Object> mapping) {
311 List<NodeTuple> nodeValue = (List<NodeTuple>) node.getValue();
312 for (NodeTuple tuple : nodeValue) {
313 Node keyNode = tuple.getKeyNode();
314 Node valueNode = tuple.getValueNode();
315 Object key = constructObject(keyNode);
316 if (key != null) {
317 try {
318 key.hashCode();
319 } catch (Exception e) {
320 throw new ConstructorException("while constructing a mapping",
321 node.getStartMark(), "found unacceptable key " + key, tuple
322 .getKeyNode().getStartMark(), e);
323 }
324 }
325 Object value = constructObject(valueNode);
326 if (keyNode.isTwoStepsConstruction()) {
327
328
329
330
331
332
333 maps2fill.add(0,
334 new RecursiveTuple<Map<Object, Object>, RecursiveTuple<Object, Object>>(
335 mapping, new RecursiveTuple<Object, Object>(key, value)));
336 } else {
337 mapping.put(key, value);
338 }
339 }
340 }
341
342 protected void constructSet2ndStep(MappingNode node, Set<Object> set) {
343 List<NodeTuple> nodeValue = (List<NodeTuple>) node.getValue();
344 for (NodeTuple tuple : nodeValue) {
345 Node keyNode = tuple.getKeyNode();
346 Object key = constructObject(keyNode);
347 if (key != null) {
348 try {
349 key.hashCode();
350 } catch (Exception e) {
351 throw new ConstructorException("while constructing a Set", node.getStartMark(),
352 "found unacceptable key " + key, tuple.getKeyNode().getStartMark(), e);
353 }
354 }
355 if (keyNode.isTwoStepsConstruction()) {
356
357
358
359
360
361
362 sets2fill.add(0, new RecursiveTuple<Set<Object>, Object>(set, key));
363 } else {
364 set.add(key);
365 }
366 }
367 }
368
369
370
371
372
373
374
375
376
377
378
379
380
381 public void setPropertyUtils(PropertyUtils propertyUtils) {
382 this.propertyUtils = propertyUtils;
383 explicitPropertyUtils = true;
384 }
385
386 public final PropertyUtils getPropertyUtils() {
387 if (propertyUtils == null) {
388 propertyUtils = new PropertyUtils();
389 }
390 return propertyUtils;
391 }
392
393 private static class RecursiveTuple<T, K> {
394 private final T _1;
395 private final K _2;
396
397 public RecursiveTuple(T _1, K _2) {
398 this._1 = _1;
399 this._2 = _2;
400 }
401
402 public K _2() {
403 return _2;
404 }
405
406 public T _1() {
407 return _1;
408 }
409 }
410
411 public final boolean isExplicitPropertyUtils() {
412 return explicitPropertyUtils;
413 }
414 }