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