11adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov/**
211a89b445f3bde56bf07e6a0d04f0b0256dcb215Andrey Somov * Copyright (c) 2008, http://www.snakeyaml.org
31adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov *
41adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * Licensed under the Apache License, Version 2.0 (the "License");
51adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * you may not use this file except in compliance with the License.
61adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * You may obtain a copy of the License at
71adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov *
81adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov *     http://www.apache.org/licenses/LICENSE-2.0
91adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov *
101adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * Unless required by applicable law or agreed to in writing, software
111adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * distributed under the License is distributed on an "AS IS" BASIS,
121adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * See the License for the specific language governing permissions and
141adf3a94fce500e0bda933e4b495a004d5789bd7Andrey Somov * limitations under the License.
159629be70863521bead138c295351f3dec926ab1Andrey Somov */
169629be70863521bead138c295351f3dec926ab1Andrey Somovpackage org.yaml.snakeyaml.constructor;
179629be70863521bead138c295351f3dec926ab1Andrey Somov
189629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.beans.IntrospectionException;
19583bd9a0e9fedbe9dffb6bee8183b06be204b15eAndrey Somovimport java.math.BigDecimal;
209629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.math.BigInteger;
21c084ec7a5d61af0edce644cd1ec400a8df838f4cAndrey Somovimport java.util.ArrayList;
22b4779f9a8e0eaf921e4838fc9c68b8e9c0be963cAndrey Somovimport java.util.Calendar;
2325b326160d3a4ec112768f32ae44250e4897eceaAndrey Somovimport java.util.Collection;
249629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.util.Date;
259629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.util.HashMap;
269629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.util.List;
279629be70863521bead138c295351f3dec926ab1Andrey Somovimport java.util.Map;
28cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somovimport java.util.Properties;
29377e2ff253ffd47c072a2cd057d3aa0fa8f27616Andrey Somovimport java.util.Set;
30cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somovimport java.util.SortedMap;
31f88e848a4d49bd347840dce4b43573aec8fe74e3Andrey Somovimport java.util.SortedSet;
32cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somovimport java.util.TreeMap;
33f88e848a4d49bd347840dce4b43573aec8fe74e3Andrey Somovimport java.util.TreeSet;
34ebe7279d7a16518cd05078e24ce240af52c8597eAndrey Somovimport java.util.UUID;
359629be70863521bead138c295351f3dec926ab1Andrey Somov
369629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.TypeDescription;
379629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.error.YAMLException;
389629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.introspector.Property;
399629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.nodes.MappingNode;
409629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.nodes.Node;
41ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somovimport org.yaml.snakeyaml.nodes.NodeId;
429da9b5c833e9e30ec0991f8fc4181d29384ed939Andrey Somovimport org.yaml.snakeyaml.nodes.NodeTuple;
439629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.nodes.ScalarNode;
449629be70863521bead138c295351f3dec926ab1Andrey Somovimport org.yaml.snakeyaml.nodes.SequenceNode;
4587ff57908e8ccf62ef984bb067a61b815a9a1074Andrey Somovimport org.yaml.snakeyaml.nodes.Tag;
469629be70863521bead138c295351f3dec926ab1Andrey Somov
479629be70863521bead138c295351f3dec926ab1Andrey Somov/**
48205e9cd24e59a3f9005213cb68899b9ba95a06d2Andrey Somov * Construct a custom Java instance.
499629be70863521bead138c295351f3dec926ab1Andrey Somov */
509629be70863521bead138c295351f3dec926ab1Andrey Somovpublic class Constructor extends SafeConstructor {
511fa9989515d2c8fc77d5c7b363d735efd7e443cfAndrey Somov    private final Map<Tag, Class<? extends Object>> typeTags;
52ddeae0b94884e98a832f12e1586c76d37e2e74f4Andrey Somov    protected final Map<Class<? extends Object>, TypeDescription> typeDefinitions;
539629be70863521bead138c295351f3dec926ab1Andrey Somov
549629be70863521bead138c295351f3dec926ab1Andrey Somov    public Constructor() {
559629be70863521bead138c295351f3dec926ab1Andrey Somov        this(Object.class);
569629be70863521bead138c295351f3dec926ab1Andrey Somov    }
579629be70863521bead138c295351f3dec926ab1Andrey Somov
58ae99b743010c3330b8bf850cdd56fdbcd8b67a82Andrey Somov    /**
59ae99b743010c3330b8bf850cdd56fdbcd8b67a82Andrey Somov     * Create Constructor for the specified class as the root.
60ae99b743010c3330b8bf850cdd56fdbcd8b67a82Andrey Somov     *
61ae99b743010c3330b8bf850cdd56fdbcd8b67a82Andrey Somov     * @param theRoot
62ae99b743010c3330b8bf850cdd56fdbcd8b67a82Andrey Somov     *            - the class (usually JavaBean) to be constructed
63ae99b743010c3330b8bf850cdd56fdbcd8b67a82Andrey Somov     */
649629be70863521bead138c295351f3dec926ab1Andrey Somov    public Constructor(Class<? extends Object> theRoot) {
65701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov        this(new TypeDescription(checkRoot(theRoot)));
66701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov    }
67701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov
68701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov    /**
69701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov     * Ugly Java way to check the argument in the constructor
70701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov     */
71701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov    private static Class<? extends Object> checkRoot(Class<? extends Object> theRoot) {
72701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov        if (theRoot == null) {
73701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov            throw new NullPointerException("Root class must be provided.");
74701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov        } else
75701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov            return theRoot;
76701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov    }
77701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov
78701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov    public Constructor(TypeDescription theRoot) {
799629be70863521bead138c295351f3dec926ab1Andrey Somov        if (theRoot == null) {
809629be70863521bead138c295351f3dec926ab1Andrey Somov            throw new NullPointerException("Root type must be provided.");
819629be70863521bead138c295351f3dec926ab1Andrey Somov        }
82b2ec508da00f4ce0ca420aff9e99ab6b68d7457eAndrey Somov        this.yamlConstructors.put(null, new ConstructYamlObject());
83701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov        if (!Object.class.equals(theRoot.getType())) {
84701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov            rootTag = new Tag(theRoot.getType());
85979636c0ebbe94a0d6e3a06218e2368bb44b2802Andrey Somov        }
861fa9989515d2c8fc77d5c7b363d735efd7e443cfAndrey Somov        typeTags = new HashMap<Tag, Class<? extends Object>>();
879629be70863521bead138c295351f3dec926ab1Andrey Somov        typeDefinitions = new HashMap<Class<? extends Object>, TypeDescription>();
88cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov        yamlClassConstructors.put(NodeId.scalar, new ConstructScalar());
89cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov        yamlClassConstructors.put(NodeId.mapping, new ConstructMapping());
90cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov        yamlClassConstructors.put(NodeId.sequence, new ConstructSequence());
91701d55e6c01ee5f4276a0ebcc4d78904619b8595Andrey Somov        addTypeDescription(theRoot);
929629be70863521bead138c295351f3dec926ab1Andrey Somov    }
939629be70863521bead138c295351f3dec926ab1Andrey Somov
949629be70863521bead138c295351f3dec926ab1Andrey Somov    /**
959629be70863521bead138c295351f3dec926ab1Andrey Somov     * Create Constructor for a class which does not have to be in the classpath
969629be70863521bead138c295351f3dec926ab1Andrey Somov     * or for a definition from a Spring ApplicationContext.
979629be70863521bead138c295351f3dec926ab1Andrey Somov     *
989629be70863521bead138c295351f3dec926ab1Andrey Somov     * @param theRoot
99ae99b743010c3330b8bf850cdd56fdbcd8b67a82Andrey Somov     *            fully qualified class name of the root class (usually
100ae99b743010c3330b8bf850cdd56fdbcd8b67a82Andrey Somov     *            JavaBean)
1019629be70863521bead138c295351f3dec926ab1Andrey Somov     * @throws ClassNotFoundException
1029629be70863521bead138c295351f3dec926ab1Andrey Somov     */
1039629be70863521bead138c295351f3dec926ab1Andrey Somov    public Constructor(String theRoot) throws ClassNotFoundException {
1049629be70863521bead138c295351f3dec926ab1Andrey Somov        this(Class.forName(check(theRoot)));
1059629be70863521bead138c295351f3dec926ab1Andrey Somov    }
1069629be70863521bead138c295351f3dec926ab1Andrey Somov
1079629be70863521bead138c295351f3dec926ab1Andrey Somov    private static final String check(String s) {
1089629be70863521bead138c295351f3dec926ab1Andrey Somov        if (s == null) {
1099629be70863521bead138c295351f3dec926ab1Andrey Somov            throw new NullPointerException("Root type must be provided.");
1109629be70863521bead138c295351f3dec926ab1Andrey Somov        }
1119629be70863521bead138c295351f3dec926ab1Andrey Somov        if (s.trim().length() == 0) {
1129629be70863521bead138c295351f3dec926ab1Andrey Somov            throw new YAMLException("Root type must be provided.");
1139629be70863521bead138c295351f3dec926ab1Andrey Somov        }
1149629be70863521bead138c295351f3dec926ab1Andrey Somov        return s;
1159629be70863521bead138c295351f3dec926ab1Andrey Somov    }
1169629be70863521bead138c295351f3dec926ab1Andrey Somov
1179629be70863521bead138c295351f3dec926ab1Andrey Somov    /**
1189629be70863521bead138c295351f3dec926ab1Andrey Somov     * Make YAML aware how to parse a custom Class. If there is no root Class
1199629be70863521bead138c295351f3dec926ab1Andrey Somov     * assigned in constructor then the 'root' property of this definition is
1209629be70863521bead138c295351f3dec926ab1Andrey Somov     * respected.
1219629be70863521bead138c295351f3dec926ab1Andrey Somov     *
1229629be70863521bead138c295351f3dec926ab1Andrey Somov     * @param definition
1239629be70863521bead138c295351f3dec926ab1Andrey Somov     *            to be added to the Constructor
1249629be70863521bead138c295351f3dec926ab1Andrey Somov     * @return the previous value associated with <tt>definition</tt>, or
1259629be70863521bead138c295351f3dec926ab1Andrey Somov     *         <tt>null</tt> if there was no mapping for <tt>definition</tt>.
1269629be70863521bead138c295351f3dec926ab1Andrey Somov     */
1279629be70863521bead138c295351f3dec926ab1Andrey Somov    public TypeDescription addTypeDescription(TypeDescription definition) {
1289629be70863521bead138c295351f3dec926ab1Andrey Somov        if (definition == null) {
1299629be70863521bead138c295351f3dec926ab1Andrey Somov            throw new NullPointerException("TypeDescription is required.");
1309629be70863521bead138c295351f3dec926ab1Andrey Somov        }
1311fa9989515d2c8fc77d5c7b363d735efd7e443cfAndrey Somov        Tag tag = definition.getTag();
1329629be70863521bead138c295351f3dec926ab1Andrey Somov        typeTags.put(tag, definition.getType());
1339629be70863521bead138c295351f3dec926ab1Andrey Somov        return typeDefinitions.put(definition.getType(), definition);
1349629be70863521bead138c295351f3dec926ab1Andrey Somov    }
1359629be70863521bead138c295351f3dec926ab1Andrey Somov
136cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov    /**
137cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov     * Construct mapping instance (Map, JavaBean) when the runtime class is
138903025b9188a49d214131ba4fdb2bc49a1bcc317Andrey Somov     * known.
139cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov     */
140903025b9188a49d214131ba4fdb2bc49a1bcc317Andrey Somov    protected class ConstructMapping implements Construct {
1419ab17c02ff6c2127ac57aab7a26505240ff41b07Andrey Somov
142ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov        /**
143ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov         * Construct JavaBean. If type safe collections are used please look at
144ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov         * <code>TypeDescription</code>.
145ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov         *
146ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov         * @param node
147ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov         *            node where the keys are property names (they can only be
148ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov         *            <code>String</code>s) and values are objects to be created
149ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov         * @return constructed JavaBean
150ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov         */
1519629be70863521bead138c295351f3dec926ab1Andrey Somov        public Object construct(Node node) {
152ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            MappingNode mnode = (MappingNode) node;
153cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov            if (Properties.class.isAssignableFrom(node.getType())) {
154cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov                Properties properties = new Properties();
155cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov                if (!node.isTwoStepsConstruction()) {
15672f4f1885f1ff089d9b593d159e6ec3651ba7182maslovalex                    constructMapping2ndStep(mnode, properties);
157cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov                } else {
158cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov                    throw new YAMLException("Properties must not be recursive.");
159cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov                }
160cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov                return properties;
161cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov            } else if (SortedMap.class.isAssignableFrom(node.getType())) {
162cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov                SortedMap<Object, Object> map = new TreeMap<Object, Object>();
163cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov                if (!node.isTwoStepsConstruction()) {
164cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov                    constructMapping2ndStep(mnode, map);
165cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov                }
166cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov                return map;
167cf48aa042c0255c41b3f8fec801163af06f3061eAndrey Somov            } else if (Map.class.isAssignableFrom(node.getType())) {
1689506e323ef3bd1554a138c978b8523e6831775bbAndrey Somov                if (node.isTwoStepsConstruction()) {
169ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    return createDefaultMap();
1709506e323ef3bd1554a138c978b8523e6831775bbAndrey Somov                } else {
1716a14494b7d3eb2945af24b151cbd87e6c33d1b17Andrey Somov                    return constructMapping(mnode);
1729506e323ef3bd1554a138c978b8523e6831775bbAndrey Somov                }
173f88e848a4d49bd347840dce4b43573aec8fe74e3Andrey Somov            } else if (SortedSet.class.isAssignableFrom(node.getType())) {
174f88e848a4d49bd347840dce4b43573aec8fe74e3Andrey Somov                SortedSet<Object> set = new TreeSet<Object>();
175c7b07c668a6c86ddd0890d24a89f6531bc8d17b3Andrey Somov                // XXX why this is not used ?
176c7b07c668a6c86ddd0890d24a89f6531bc8d17b3Andrey Somov                // if (!node.isTwoStepsConstruction()) {
177f532df6caa89678542a21a22a0b0a9e3638a37ccAndrey Somov                constructSet2ndStep(mnode, set);
178c7b07c668a6c86ddd0890d24a89f6531bc8d17b3Andrey Somov                // }
179f88e848a4d49bd347840dce4b43573aec8fe74e3Andrey Somov                return set;
18025b326160d3a4ec112768f32ae44250e4897eceaAndrey Somov            } else if (Collection.class.isAssignableFrom(node.getType())) {
1819506e323ef3bd1554a138c978b8523e6831775bbAndrey Somov                if (node.isTwoStepsConstruction()) {
182ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    return createDefaultSet();
1839506e323ef3bd1554a138c978b8523e6831775bbAndrey Somov                } else {
1846a14494b7d3eb2945af24b151cbd87e6c33d1b17Andrey Somov                    return constructSet(mnode);
1859506e323ef3bd1554a138c978b8523e6831775bbAndrey Somov                }
1869629be70863521bead138c295351f3dec926ab1Andrey Somov            } else {
1871db5c999dfee2026c058a4df2e85edcede7b9d86Andrey Somov                if (node.isTwoStepsConstruction()) {
188ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    return createEmptyJavaBean(mnode);
189377e2ff253ffd47c072a2cd057d3aa0fa8f27616Andrey Somov                } else {
190ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    return constructJavaBean2ndStep(mnode, createEmptyJavaBean(mnode));
191377e2ff253ffd47c072a2cd057d3aa0fa8f27616Andrey Somov                }
1929629be70863521bead138c295351f3dec926ab1Andrey Somov            }
1939629be70863521bead138c295351f3dec926ab1Andrey Somov        }
1949629be70863521bead138c295351f3dec926ab1Andrey Somov
195ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov        @SuppressWarnings("unchecked")
196ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov        public void construct2ndStep(Node node, Object object) {
197ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            if (Map.class.isAssignableFrom(node.getType())) {
198ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                constructMapping2ndStep((MappingNode) node, (Map<Object, Object>) object);
199ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            } else if (Set.class.isAssignableFrom(node.getType())) {
200ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                constructSet2ndStep((MappingNode) node, (Set<Object>) object);
201ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            } else {
202ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                constructJavaBean2ndStep((MappingNode) node, object);
203ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            }
204c6d9f4f6d5613d347e5c8f1a54ec759d50690e16Andrey Somov        }
205ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov
2068f6ec8c2337c1c83e27059d34a05295d3e93de23Andrey Somov        protected Object createEmptyJavaBean(MappingNode node) {
207ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            try {
208ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                /**
209ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                 * Using only default constructor. Everything else will be
210ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                 * initialized on 2nd step. If we do here some partial
211ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                 * initialization, how do we then track what need to be done on
212ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                 * 2nd step? I think it is better to get only object here (to
213ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                 * have it as reference for recursion) and do all other thing on
214ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                 * 2nd step.
215ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                 */
21687bde16e30ef24e63364ac981b1a598d5f971737maslovalex                java.lang.reflect.Constructor<?> c = node.getType().getDeclaredConstructor();
21787bde16e30ef24e63364ac981b1a598d5f971737maslovalex                c.setAccessible(true);
21887bde16e30ef24e63364ac981b1a598d5f971737maslovalex                return c.newInstance();
21987bde16e30ef24e63364ac981b1a598d5f971737maslovalex            } catch (Exception e) {
220ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                throw new YAMLException(e);
221ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            }
222ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov        }
223ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov
2248f6ec8c2337c1c83e27059d34a05295d3e93de23Andrey Somov        protected Object constructJavaBean2ndStep(MappingNode node, Object object) {
22572f4f1885f1ff089d9b593d159e6ec3651ba7182maslovalex            flattenMapping(node);
226ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            Class<? extends Object> beanType = node.getType();
22772f4f1885f1ff089d9b593d159e6ec3651ba7182maslovalex            List<NodeTuple> nodeValue = node.getValue();
228ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            for (NodeTuple tuple : nodeValue) {
229ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                ScalarNode keyNode;
230ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                if (tuple.getKeyNode() instanceof ScalarNode) {
231ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    // key must be scalar
232ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    keyNode = (ScalarNode) tuple.getKeyNode();
233377e2ff253ffd47c072a2cd057d3aa0fa8f27616Andrey Somov                } else {
234ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    throw new YAMLException("Keys must be scalars but found: " + tuple.getKeyNode());
235ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                }
236ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                Node valueNode = tuple.getValueNode();
237ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                // keys can only be Strings
238ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                keyNode.setType(String.class);
239ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                String key = (String) constructObject(keyNode);
240ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                try {
241ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    Property property = getProperty(beanType, key);
242ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    valueNode.setType(property.getType());
243ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    TypeDescription memberDescription = typeDefinitions.get(beanType);
244e82ce6dd9dc482001bc5bc9fb9494f53da0449e9Andrey Somov                    boolean typeDetected = false;
245ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    if (memberDescription != null) {
246ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                        switch (valueNode.getNodeId()) {
247ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                        case sequence:
248ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                            SequenceNode snode = (SequenceNode) valueNode;
249ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                            Class<? extends Object> memberType = memberDescription
250ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                                    .getListPropertyType(key);
251ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                            if (memberType != null) {
252ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                                snode.setListType(memberType);
253e82ce6dd9dc482001bc5bc9fb9494f53da0449e9Andrey Somov                                typeDetected = true;
254ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                            } else if (property.getType().isArray()) {
255ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                                snode.setListType(property.getType().getComponentType());
256e82ce6dd9dc482001bc5bc9fb9494f53da0449e9Andrey Somov                                typeDetected = true;
257ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                            }
258ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                            break;
259ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                        case mapping:
260ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                            MappingNode mnode = (MappingNode) valueNode;
261ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                            Class<? extends Object> keyType = memberDescription.getMapKeyType(key);
262ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                            if (keyType != null) {
2635e819b5115ddc5c432fac860440b48f34bac3200maslovalex                                mnode.setTypes(keyType, memberDescription.getMapValueType(key));
264e82ce6dd9dc482001bc5bc9fb9494f53da0449e9Andrey Somov                                typeDetected = true;
265ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                            }
266ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                            break;
26734f59d77fd0a29b085d4c642eb1db6b8925fc3c3Andrey Somov                        default: // scalar
268ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                        }
269ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    }
270a9de7ef39a1f086be052dfcc75ad671078c5a8a4Andrey Somov                    if (!typeDetected && valueNode.getNodeId() != NodeId.scalar) {
271e82ce6dd9dc482001bc5bc9fb9494f53da0449e9Andrey Somov                        // only if there is no explicit TypeDescription
272e85d52ba83eb6cb37dc1bf71e7c4f8c2a5d71670Andrey Somov                        Class<?>[] arguments = property.getActualTypeArguments();
27388c1e8787f0d72fdfea3a3315c4cc95d8f1c11adAndrey Somov                        if (arguments != null && arguments.length > 0) {
274a9de7ef39a1f086be052dfcc75ad671078c5a8a4Andrey Somov                            // type safe (generic) collection may contain the
275a9de7ef39a1f086be052dfcc75ad671078c5a8a4Andrey Somov                            // proper class
276a9de7ef39a1f086be052dfcc75ad671078c5a8a4Andrey Somov                            if (valueNode.getNodeId() == NodeId.sequence) {
27701f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                                Class<?> t = arguments[0];
278e82ce6dd9dc482001bc5bc9fb9494f53da0449e9Andrey Somov                                SequenceNode snode = (SequenceNode) valueNode;
279e82ce6dd9dc482001bc5bc9fb9494f53da0449e9Andrey Somov                                snode.setListType(t);
28087ff57908e8ccf62ef984bb067a61b815a9a1074Andrey Somov                            } else if (valueNode.getTag().equals(Tag.SET)) {
28101f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                                Class<?> t = arguments[0];
282e82ce6dd9dc482001bc5bc9fb9494f53da0449e9Andrey Somov                                MappingNode mnode = (MappingNode) valueNode;
2835e819b5115ddc5c432fac860440b48f34bac3200maslovalex                                mnode.setOnlyKeyType(t);
284e82ce6dd9dc482001bc5bc9fb9494f53da0449e9Andrey Somov                                mnode.setUseClassConstructor(true);
28501f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                            } else if (property.getType().isAssignableFrom(Map.class)) {
28601f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                                Class<?> ketType = arguments[0];
28701f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                                Class<?> valueType = arguments[1];
288a9de7ef39a1f086be052dfcc75ad671078c5a8a4Andrey Somov                                MappingNode mnode = (MappingNode) valueNode;
2895e819b5115ddc5c432fac860440b48f34bac3200maslovalex                                mnode.setTypes(ketType, valueType);
290a9de7ef39a1f086be052dfcc75ad671078c5a8a4Andrey Somov                                mnode.setUseClassConstructor(true);
291e85d52ba83eb6cb37dc1bf71e7c4f8c2a5d71670Andrey Somov                            } else {
292fd906b76dd780bc2271da9f597b4cf2793d630acAndrey Somov                                // the type for collection entries cannot be
293fd906b76dd780bc2271da9f597b4cf2793d630acAndrey Somov                                // detected
294e82ce6dd9dc482001bc5bc9fb9494f53da0449e9Andrey Somov                            }
295f88e848a4d49bd347840dce4b43573aec8fe74e3Andrey Somov                        }
2968caea31160c72bce4181ed38b16f850e06d29a14Andrey Somov                    }
2978c0d5ed989759b2e9c903928fd09cf3964e15d6aAndrey Somov
298ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    Object value = constructObject(valueNode);
299615d3719f75e5aad70d1598ef160123705008216Andrey Somov                    // Correct when the property expects float but double was
300615d3719f75e5aad70d1598ef160123705008216Andrey Somov                    // constructed
3018c0d5ed989759b2e9c903928fd09cf3964e15d6aAndrey Somov                    if (property.getType() == Float.TYPE || property.getType() == Float.class) {
3028c0d5ed989759b2e9c903928fd09cf3964e15d6aAndrey Somov                        if (value instanceof Double) {
3038c0d5ed989759b2e9c903928fd09cf3964e15d6aAndrey Somov                            value = ((Double) value).floatValue();
3048c0d5ed989759b2e9c903928fd09cf3964e15d6aAndrey Somov                        }
3058c0d5ed989759b2e9c903928fd09cf3964e15d6aAndrey Somov                    }
3060fca80757efbb4219edb6a0173e4f6365c8903f9Andrey Somov                    // Correct when the property a String but the value is binary
3070fca80757efbb4219edb6a0173e4f6365c8903f9Andrey Somov                    if (property.getType() == String.class && Tag.BINARY.equals(valueNode.getTag()) && value instanceof byte[]) {
3080fca80757efbb4219edb6a0173e4f6365c8903f9Andrey Somov                        value = new String((byte[])value);
3090fca80757efbb4219edb6a0173e4f6365c8903f9Andrey Somov                    }
3109b3d9d765773e00ad481ac2d5e89eab32ae68ea1Andrey Somov
311ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    property.set(object, value);
312ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                } catch (Exception e) {
31386516d77409b9a2e61c82a28d1ffaf52eaf03837Andrey Somov                    throw new ConstructorException("Cannot create property=" + key
31486516d77409b9a2e61c82a28d1ffaf52eaf03837Andrey Somov                            + " for JavaBean=" + object, node.getStartMark(), e.getMessage(),
31586516d77409b9a2e61c82a28d1ffaf52eaf03837Andrey Somov                            valueNode.getStartMark(), e);
316ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                }
317ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            }
318ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            return object;
319ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov        }
320ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov
3218f6ec8c2337c1c83e27059d34a05295d3e93de23Andrey Somov        protected Property getProperty(Class<? extends Object> type, String name)
322ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                throws IntrospectionException {
32387bde16e30ef24e63364ac981b1a598d5f971737maslovalex            return getPropertyUtils().getProperty(type, name);
324ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov        }
325ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov    }
326ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov
327cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov    /**
328cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov     * Construct an instance when the runtime class is not known but a global
329cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov     * tag with a class name is defined. It delegates the construction to the
330cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov     * appropriate constructor based on the node kind (scalar, sequence,
331903025b9188a49d214131ba4fdb2bc49a1bcc317Andrey Somov     * mapping)
332cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov     */
333903025b9188a49d214131ba4fdb2bc49a1bcc317Andrey Somov    protected class ConstructYamlObject implements Construct {
33443eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov
33543eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov        private Construct getConstructor(Node node) {
33601f469ecf699181a0799cfed097b6021db0777c4Andrey Somov            Class<?> cl = getClassForNode(node);
33743eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov            node.setType(cl);
33843eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov            // call the constructor as if the runtime class is defined
33943eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov            Construct constructor = yamlClassConstructors.get(node.getNodeId());
34043eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov            return constructor;
34143eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov        }
34243eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov
343ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov        public Object construct(Node node) {
344ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            Object result = null;
345ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            try {
34643eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov                result = getConstructor(node).construct(node);
34786516d77409b9a2e61c82a28d1ffaf52eaf03837Andrey Somov            } catch (ConstructorException e) {
34886516d77409b9a2e61c82a28d1ffaf52eaf03837Andrey Somov                throw e;
349ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            } catch (Exception e) {
350ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                throw new ConstructorException(null, null, "Can't construct a java object for "
351ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                        + node.getTag() + "; exception=" + e.getMessage(), node.getStartMark(), e);
352ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            }
353ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            return result;
354377e2ff253ffd47c072a2cd057d3aa0fa8f27616Andrey Somov        }
35543eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov
35643eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov        public void construct2ndStep(Node node, Object object) {
35743eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov            try {
35843eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov                getConstructor(node).construct2ndStep(node, object);
35943eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov            } catch (Exception e) {
36043eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov                throw new ConstructorException(null, null,
36143eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov                        "Can't construct a second step for a java object for " + node.getTag()
36243eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov                                + "; exception=" + e.getMessage(), node.getStartMark(), e);
36343eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov            }
36443eb6e5f495f9fd150d86caf033deaa47549ffa6Andrey Somov        }
3651db5c999dfee2026c058a4df2e85edcede7b9d86Andrey Somov    }
366377e2ff253ffd47c072a2cd057d3aa0fa8f27616Andrey Somov
367ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov    /**
368ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov     * Construct scalar instance when the runtime class is known. Recursive
369ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov     * structures are not supported.
370ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov     */
371ccc3b9a3ce0c926a9b13c0e4244dcce87aeaa21bAndrey Somov    protected class ConstructScalar extends AbstractConstruct {
372ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov        public Object construct(Node nnode) {
373ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            ScalarNode node = (ScalarNode) nnode;
37401f469ecf699181a0799cfed097b6021db0777c4Andrey Somov            Class<?> type = node.getType();
375ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            Object result;
376ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            if (type.isPrimitive() || type == String.class || Number.class.isAssignableFrom(type)
377ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    || type == Boolean.class || Date.class.isAssignableFrom(type)
378ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    || type == Character.class || type == BigInteger.class
37984e718ae12a709b34b5d5c2a2a9d4af2699c20cfAndrey Somov                    || type == BigDecimal.class || Enum.class.isAssignableFrom(type)
380ebe7279d7a16518cd05078e24ce240af52c8597eAndrey Somov                    || Tag.BINARY.equals(node.getTag()) || Calendar.class.isAssignableFrom(type) || type == UUID.class) {
381ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                // standard classes created directly
382ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                result = constructStandardJavaInstance(type, node);
383ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            } else {
384ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                // there must be only 1 constructor with 1 argument
385d187b365cd221bc347354518a5582f4f37b2f68cmaslovalex                java.lang.reflect.Constructor<?>[] javaConstructors = type
386d187b365cd221bc347354518a5582f4f37b2f68cmaslovalex                        .getDeclaredConstructors();
387d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                int oneArgCount = 0;
38801f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                java.lang.reflect.Constructor<?> javaConstructor = null;
38901f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                for (java.lang.reflect.Constructor<?> c : javaConstructors) {
390ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    if (c.getParameterTypes().length == 1) {
391d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                        oneArgCount++;
392ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                        javaConstructor = c;
393ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    }
394ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                }
395d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                Object argument;
396ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                if (javaConstructor == null) {
397ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    throw new YAMLException("No single argument constructor found for " + type);
398d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                } else if (oneArgCount == 1) {
399d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                    argument = constructStandardJavaInstance(
400d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                            javaConstructor.getParameterTypes()[0], node);
401ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                } else {
402d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                    // TODO it should be possible to use implicit types instead
403d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                    // of forcing String. Resolver must be available here to
404d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                    // obtain the implicit tag. Then we can set the tag and call
405ab2e864982dc460583b287da179712eaadbbf409Andrey Somov                    // callConstructor(node) to create the argument instance.
406ab2e864982dc460583b287da179712eaadbbf409Andrey Somov                    // On the other hand it may be safer to require a custom
407ab2e864982dc460583b287da179712eaadbbf409Andrey Somov                    // constructor to avoid guessing the argument class
408d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                    argument = constructScalar(node);
409ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    try {
410d187b365cd221bc347354518a5582f4f37b2f68cmaslovalex                        javaConstructor = type.getDeclaredConstructor(String.class);
411ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    } catch (Exception e) {
41229a5af489bbe2a14de867828fd12ba527fed342fAndrey Somov                        throw new YAMLException("Can't construct a java object for scalar "
41329a5af489bbe2a14de867828fd12ba527fed342fAndrey Somov                                + node.getTag() + "; No String constructor found. Exception="
41429a5af489bbe2a14de867828fd12ba527fed342fAndrey Somov                                + e.getMessage(), e);
415ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    }
416ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                }
417d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                try {
418d187b365cd221bc347354518a5582f4f37b2f68cmaslovalex                    javaConstructor.setAccessible(true);
419d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                    result = javaConstructor.newInstance(argument);
420d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                } catch (Exception e) {
421d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                    throw new ConstructorException(null, null,
422d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                            "Can't construct a java object for scalar " + node.getTag()
423d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                                    + "; exception=" + e.getMessage(), node.getStartMark(), e);
424d9d317fef9a029bc281e6d39d8906d9415dd5396Andrey Somov                }
425ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            }
426ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            return result;
427ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov        }
428ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov
429ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov        @SuppressWarnings("unchecked")
430ddeae0b94884e98a832f12e1586c76d37e2e74f4Andrey Somov        private Object constructStandardJavaInstance(@SuppressWarnings("rawtypes")
431ddeae0b94884e98a832f12e1586c76d37e2e74f4Andrey Somov        Class type, ScalarNode node) {
432ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            Object result;
4339629be70863521bead138c295351f3dec926ab1Andrey Somov            if (type == String.class) {
43487ff57908e8ccf62ef984bb067a61b815a9a1074Andrey Somov                Construct stringConstructor = yamlConstructors.get(Tag.STR);
43572f4f1885f1ff089d9b593d159e6ec3651ba7182maslovalex                result = stringConstructor.construct(node);
4369629be70863521bead138c295351f3dec926ab1Andrey Somov            } else if (type == Boolean.class || type == Boolean.TYPE) {
43787ff57908e8ccf62ef984bb067a61b815a9a1074Andrey Somov                Construct boolConstructor = yamlConstructors.get(Tag.BOOL);
43872f4f1885f1ff089d9b593d159e6ec3651ba7182maslovalex                result = boolConstructor.construct(node);
4399629be70863521bead138c295351f3dec926ab1Andrey Somov            } else if (type == Character.class || type == Character.TYPE) {
44087ff57908e8ccf62ef984bb067a61b815a9a1074Andrey Somov                Construct charConstructor = yamlConstructors.get(Tag.STR);
44172f4f1885f1ff089d9b593d159e6ec3651ba7182maslovalex                String ch = (String) charConstructor.construct(node);
442ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                if (ch.length() == 0) {
443ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    result = null;
444ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                } else if (ch.length() != 1) {
4459629be70863521bead138c295351f3dec926ab1Andrey Somov                    throw new YAMLException("Invalid node Character: '" + ch + "'; length: "
4469629be70863521bead138c295351f3dec926ab1Andrey Somov                            + ch.length());
447ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                } else {
44834f59d77fd0a29b085d4c642eb1db6b8925fc3c3Andrey Somov                    result = Character.valueOf(ch.charAt(0));
4499629be70863521bead138c295351f3dec926ab1Andrey Somov                }
450068685adad298fbfcbaa8f6606ec7aed7a678c79Andrey Somov            } else if (Date.class.isAssignableFrom(type)) {
45187ff57908e8ccf62ef984bb067a61b815a9a1074Andrey Somov                Construct dateConstructor = yamlConstructors.get(Tag.TIMESTAMP);
45272f4f1885f1ff089d9b593d159e6ec3651ba7182maslovalex                Date date = (Date) dateConstructor.construct(node);
453068685adad298fbfcbaa8f6606ec7aed7a678c79Andrey Somov                if (type == Date.class) {
454068685adad298fbfcbaa8f6606ec7aed7a678c79Andrey Somov                    result = date;
455068685adad298fbfcbaa8f6606ec7aed7a678c79Andrey Somov                } else {
456068685adad298fbfcbaa8f6606ec7aed7a678c79Andrey Somov                    try {
457068685adad298fbfcbaa8f6606ec7aed7a678c79Andrey Somov                        java.lang.reflect.Constructor<?> constr = type.getConstructor(long.class);
458068685adad298fbfcbaa8f6606ec7aed7a678c79Andrey Somov                        result = constr.newInstance(date.getTime());
459d62b0618ab6e59c72fc5670e785163357f8fdda7Andrey Somov                    } catch (RuntimeException e) {
460d62b0618ab6e59c72fc5670e785163357f8fdda7Andrey Somov                        throw e;
461068685adad298fbfcbaa8f6606ec7aed7a678c79Andrey Somov                    } catch (Exception e) {
462583bd9a0e9fedbe9dffb6bee8183b06be204b15eAndrey Somov                        throw new YAMLException("Cannot construct: '" + type + "'");
463068685adad298fbfcbaa8f6606ec7aed7a678c79Andrey Somov                    }
464068685adad298fbfcbaa8f6606ec7aed7a678c79Andrey Somov                }
4659629be70863521bead138c295351f3dec926ab1Andrey Somov            } else if (type == Float.class || type == Double.class || type == Float.TYPE
466583bd9a0e9fedbe9dffb6bee8183b06be204b15eAndrey Somov                    || type == Double.TYPE || type == BigDecimal.class) {
46784e718ae12a709b34b5d5c2a2a9d4af2699c20cfAndrey Somov                if (type == BigDecimal.class) {
46884e718ae12a709b34b5d5c2a2a9d4af2699c20cfAndrey Somov                    result = new BigDecimal(node.getValue());
46984e718ae12a709b34b5d5c2a2a9d4af2699c20cfAndrey Somov                } else {
47087ff57908e8ccf62ef984bb067a61b815a9a1074Andrey Somov                    Construct doubleConstructor = yamlConstructors.get(Tag.FLOAT);
47184e718ae12a709b34b5d5c2a2a9d4af2699c20cfAndrey Somov                    result = doubleConstructor.construct(node);
47284e718ae12a709b34b5d5c2a2a9d4af2699c20cfAndrey Somov                    if (type == Float.class || type == Float.TYPE) {
47384e718ae12a709b34b5d5c2a2a9d4af2699c20cfAndrey Somov                        result = new Float((Double) result);
47484e718ae12a709b34b5d5c2a2a9d4af2699c20cfAndrey Somov                    }
4759629be70863521bead138c295351f3dec926ab1Andrey Somov                }
476583bd9a0e9fedbe9dffb6bee8183b06be204b15eAndrey Somov            } else if (type == Byte.class || type == Short.class || type == Integer.class
477583bd9a0e9fedbe9dffb6bee8183b06be204b15eAndrey Somov                    || type == Long.class || type == BigInteger.class || type == Byte.TYPE
4789629be70863521bead138c295351f3dec926ab1Andrey Somov                    || type == Short.TYPE || type == Integer.TYPE || type == Long.TYPE) {
47987ff57908e8ccf62ef984bb067a61b815a9a1074Andrey Somov                Construct intConstructor = yamlConstructors.get(Tag.INT);
4800e5ab7057788fa02567cbdd03c33d5912cf0c389Andrey Somov                result = intConstructor.construct(node);
4819629be70863521bead138c295351f3dec926ab1Andrey Somov                if (type == Byte.class || type == Byte.TYPE) {
482d62b0618ab6e59c72fc5670e785163357f8fdda7Andrey Somov                    result = Byte.valueOf(result.toString());
4839629be70863521bead138c295351f3dec926ab1Andrey Somov                } else if (type == Short.class || type == Short.TYPE) {
484d62b0618ab6e59c72fc5670e785163357f8fdda7Andrey Somov                    result = Short.valueOf(result.toString());
4859629be70863521bead138c295351f3dec926ab1Andrey Somov                } else if (type == Integer.class || type == Integer.TYPE) {
48634f59d77fd0a29b085d4c642eb1db6b8925fc3c3Andrey Somov                    result = Integer.parseInt(result.toString());
4879629be70863521bead138c295351f3dec926ab1Andrey Somov                } else if (type == Long.class || type == Long.TYPE) {
488d62b0618ab6e59c72fc5670e785163357f8fdda7Andrey Somov                    result = Long.valueOf(result.toString());
4899629be70863521bead138c295351f3dec926ab1Andrey Somov                } else {
490583bd9a0e9fedbe9dffb6bee8183b06be204b15eAndrey Somov                    // only BigInteger left
491583bd9a0e9fedbe9dffb6bee8183b06be204b15eAndrey Somov                    result = new BigInteger(result.toString());
4929629be70863521bead138c295351f3dec926ab1Andrey Somov                }
4939629be70863521bead138c295351f3dec926ab1Andrey Somov            } else if (Enum.class.isAssignableFrom(type)) {
494ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                String enumValueName = node.getValue();
495ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                try {
496ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    result = Enum.valueOf(type, enumValueName);
497ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                } catch (Exception ex) {
498ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    throw new YAMLException("Unable to find enum value '" + enumValueName
499ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                            + "' for enum class: " + type.getName());
500ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                }
501b4779f9a8e0eaf921e4838fc9c68b8e9c0be963cAndrey Somov            } else if (Calendar.class.isAssignableFrom(type)) {
502b4779f9a8e0eaf921e4838fc9c68b8e9c0be963cAndrey Somov                ConstructYamlTimestamp contr = new ConstructYamlTimestamp();
503b4779f9a8e0eaf921e4838fc9c68b8e9c0be963cAndrey Somov                contr.construct(node);
504b4779f9a8e0eaf921e4838fc9c68b8e9c0be963cAndrey Somov                result = contr.getCalendar();
5058723ed34a3d556a43b418bb2e39bc7458386afc5Andrey Somov            } else if (Number.class.isAssignableFrom(type)) {
5068723ed34a3d556a43b418bb2e39bc7458386afc5Andrey Somov                ConstructYamlNumber contr = new ConstructYamlNumber();
5078723ed34a3d556a43b418bb2e39bc7458386afc5Andrey Somov                result = contr.construct(node);
508ebe7279d7a16518cd05078e24ce240af52c8597eAndrey Somov            }  else if (UUID.class == type) {
509ebe7279d7a16518cd05078e24ce240af52c8597eAndrey Somov                result = UUID.fromString(node.getValue());
5109629be70863521bead138c295351f3dec926ab1Andrey Somov            } else {
511d187b365cd221bc347354518a5582f4f37b2f68cmaslovalex                if (yamlConstructors.containsKey(node.getTag())) {
512d187b365cd221bc347354518a5582f4f37b2f68cmaslovalex                    result = yamlConstructors.get(node.getTag()).construct(node);
513d187b365cd221bc347354518a5582f4f37b2f68cmaslovalex                } else {
514d187b365cd221bc347354518a5582f4f37b2f68cmaslovalex                    throw new YAMLException("Unsupported class: " + type);
515d187b365cd221bc347354518a5582f4f37b2f68cmaslovalex                }
5169629be70863521bead138c295351f3dec926ab1Andrey Somov            }
517ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            return result;
518377e2ff253ffd47c072a2cd057d3aa0fa8f27616Andrey Somov        }
519377e2ff253ffd47c072a2cd057d3aa0fa8f27616Andrey Somov    }
520377e2ff253ffd47c072a2cd057d3aa0fa8f27616Andrey Somov
521cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov    /**
522cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov     * Construct sequence (List, Array, or immutable object) when the runtime
523903025b9188a49d214131ba4fdb2bc49a1bcc317Andrey Somov     * class is known.
524cc370ac444192e2693a98749996f4eeb5a03f0ebAndrey Somov     */
525903025b9188a49d214131ba4fdb2bc49a1bcc317Andrey Somov    protected class ConstructSequence implements Construct {
526ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov        @SuppressWarnings("unchecked")
527ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov        public Object construct(Node node) {
528ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            SequenceNode snode = (SequenceNode) node;
52942220bac2e8060b1eaac221cf931ecf52165047cAndrey Somov            if (Set.class.isAssignableFrom(node.getType())) {
53042220bac2e8060b1eaac221cf931ecf52165047cAndrey Somov                if (node.isTwoStepsConstruction()) {
531f532df6caa89678542a21a22a0b0a9e3638a37ccAndrey Somov                    throw new YAMLException("Set cannot be recursive.");
53242220bac2e8060b1eaac221cf931ecf52165047cAndrey Somov                } else {
53342220bac2e8060b1eaac221cf931ecf52165047cAndrey Somov                    return constructSet(snode);
53442220bac2e8060b1eaac221cf931ecf52165047cAndrey Somov                }
53542220bac2e8060b1eaac221cf931ecf52165047cAndrey Somov            } else if (Collection.class.isAssignableFrom(node.getType())) {
536ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                if (node.isTwoStepsConstruction()) {
537ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    return createDefaultList(snode.getValue().size());
538ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                } else {
539ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                    return constructSequence(snode);
5409629be70863521bead138c295351f3dec926ab1Andrey Somov                }
5414cdfade09a608d4e09cdae6531fefe33048b685bmaslovalex            } else if (node.getType().isArray()) {
5424cdfade09a608d4e09cdae6531fefe33048b685bmaslovalex                if (node.isTwoStepsConstruction()) {
5434cdfade09a608d4e09cdae6531fefe33048b685bmaslovalex                    return createArray(node.getType(), snode.getValue().size());
5444cdfade09a608d4e09cdae6531fefe33048b685bmaslovalex                } else {
5454cdfade09a608d4e09cdae6531fefe33048b685bmaslovalex                    return constructArray(snode);
5464cdfade09a608d4e09cdae6531fefe33048b685bmaslovalex                }
547ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov            } else {
548ae63c4043d331c5d538d75b9c797268d5e561f97Andrey Somov                // create immutable object
54901f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                List<java.lang.reflect.Constructor<?>> possibleConstructors = new ArrayList<java.lang.reflect.Constructor<?>>(
550c084ec7a5d61af0edce644cd1ec400a8df838f4cAndrey Somov                        snode.getValue().size());
55158dcb8e34c17d0174c4ec2e5587f570d86d6ae12maslovalex                for (java.lang.reflect.Constructor<?> constructor : node
55258dcb8e34c17d0174c4ec2e5587f570d86d6ae12maslovalex                        .getType().getDeclaredConstructors()) {
55358dcb8e34c17d0174c4ec2e5587f570d86d6ae12maslovalex                    if (snode.getValue()
55458dcb8e34c17d0174c4ec2e5587f570d86d6ae12maslovalex                            .size() == constructor.getParameterTypes().length) {
555050c422c295a0ff956f79ba91c4c5a21b255f721Andrey Somov                        possibleConstructors.add(constructor);
556050c422c295a0ff956f79ba91c4c5a21b255f721Andrey Somov                    }
557050c422c295a0ff956f79ba91c4c5a21b255f721Andrey Somov                }
5586db1cdfea180251646dc68924ed2f18339f9d984maslovalex                if (!possibleConstructors.isEmpty()) {
5596db1cdfea180251646dc68924ed2f18339f9d984maslovalex                    if (possibleConstructors.size() == 1) {
5606db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        Object[] argumentList = new Object[snode.getValue().size()];
56101f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                        java.lang.reflect.Constructor<?> c = possibleConstructors.get(0);
5626db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        int index = 0;
5636db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        for (Node argumentNode : snode.getValue()) {
56401f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                            Class<?> type = c.getParameterTypes()[index];
5656db1cdfea180251646dc68924ed2f18339f9d984maslovalex                            // set runtime classes for arguments
5666db1cdfea180251646dc68924ed2f18339f9d984maslovalex                            argumentNode.setType(type);
5676db1cdfea180251646dc68924ed2f18339f9d984maslovalex                            argumentList[index++] = constructObject(argumentNode);
5686db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        }
5696db1cdfea180251646dc68924ed2f18339f9d984maslovalex
5706db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        try {
57158dcb8e34c17d0174c4ec2e5587f570d86d6ae12maslovalex                            c.setAccessible(true);
5726db1cdfea180251646dc68924ed2f18339f9d984maslovalex                            return c.newInstance(argumentList);
5736db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        } catch (Exception e) {
5746db1cdfea180251646dc68924ed2f18339f9d984maslovalex                            throw new YAMLException(e);
5756db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        }
5766db1cdfea180251646dc68924ed2f18339f9d984maslovalex                    }
5776db1cdfea180251646dc68924ed2f18339f9d984maslovalex
5786db1cdfea180251646dc68924ed2f18339f9d984maslovalex                    // use BaseConstructor
5796db1cdfea180251646dc68924ed2f18339f9d984maslovalex                    List<Object> argumentList = (List<Object>) constructSequence(snode);
58001f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                    Class<?>[] parameterTypes = new Class[argumentList.size()];
581050c422c295a0ff956f79ba91c4c5a21b255f721Andrey Somov                    int index = 0;
5826db1cdfea180251646dc68924ed2f18339f9d984maslovalex                    for (Object parameter : argumentList) {
5836db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        parameterTypes[index] = parameter.getClass();
584050c422c295a0ff956f79ba91c4c5a21b255f721Andrey Somov                        index++;
585050c422c295a0ff956f79ba91c4c5a21b255f721Andrey Somov                    }
5866db1cdfea180251646dc68924ed2f18339f9d984maslovalex
58701f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                    for (java.lang.reflect.Constructor<?> c : possibleConstructors) {
58801f469ecf699181a0799cfed097b6021db0777c4Andrey Somov                        Class<?>[] argTypes = c.getParameterTypes();
5896db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        boolean foundConstructor = true;
5906db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        for (int i = 0; i < argTypes.length; i++) {
5916db1cdfea180251646dc68924ed2f18339f9d984maslovalex                            if (!wrapIfPrimitive(argTypes[i]).isAssignableFrom(parameterTypes[i])) {
5926db1cdfea180251646dc68924ed2f18339f9d984maslovalex                                foundConstructor = false;
5936db1cdfea180251646dc68924ed2f18339f9d984maslovalex                                break;
5946db1cdfea180251646dc68924ed2f18339f9d984maslovalex                            }
5956db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        }
5966db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        if (foundConstructor) {
5976db1cdfea180251646dc68924ed2f18339f9d984maslovalex                            try {
59858dcb8e34c17d0174c4ec2e5587f570d86d6ae12maslovalex                                c.setAccessible(true);
5996db1cdfea180251646dc68924ed2f18339f9d984maslovalex                                return c.newInstance(argumentList.toArray());
6006db1cdfea180251646dc68924ed2f18339f9d984maslovalex                            } catch (Exception e) {
6016db1cdfea180251646dc68924ed2f18339f9d984maslovalex                                throw new YAMLException(e);
6026db1cdfea180251646dc68924ed2f18339f9d984maslovalex                            }
6036db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        }
6046db1cdfea180251646dc68924ed2f18339f9d984maslovalex                    }
605583bd9a0e9fedbe9dffb6bee8183b06be204b15eAndrey Somov                }
6065aa0441307ecee16c9d80ce2b5b8aff4c23091b3Andrey Somov                throw new YAMLException("No suitable constructor with "
6076db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        + String.valueOf(snode.getValue().size()) + " arguments found for "
6086db1cdfea180251646dc68924ed2f18339f9d984maslovalex                        + node.getType());
6096db1cdfea180251646dc68924ed2f18339f9d984maslovalex
6106db1cdfea180251646dc68924ed2f18339f9d984maslovalex            }
6116db1cdfea180251646dc68924ed2f18339f9d984maslovalex        }
6126db1cdfea180251646dc68924ed2f18339f9d984maslovalex
6136db1cdfea180251646dc68924ed2f18339f9d984maslovalex        private final Class<? extends Object> wrapIfPrimitive(Class<?> clazz) {
6146db1cdfea180251646dc68924ed2f18339f9d984maslovalex            if (!clazz.isPrimitive()) {
6156db1cdfea180251646dc68924ed2f18339f9d984maslovalex                return clazz;
6166db1cdfea180251646dc68924ed2f18339f9d984maslovalex            }
6176db1cdfea180251646dc68924ed2f18339f9d984maslovalex            if (clazz == Integer.TYPE) {
6186db1cdfea180251646dc68924ed2f18339f9d984maslovalex                return Integer.class;
6196db1cdfea180251646dc68924ed2f18339f9d984maslovalex            }
6206db1cdfea180251646dc68924ed2f18339f9d984maslovalex            if (clazz == Float.TYPE) {
6216db1cdfea180251646dc68924ed2f18339f9d984maslovalex                return Float.class;
6226db1cdfea180251646dc68924ed2f18339f9d984maslovalex            }
6236db1cdfea180251646dc68924ed2f18339f9d984maslovalex            if (clazz == Double.TYPE) {
6246db1cdfea180251646dc68924ed2f18339f9d984maslovalex                return Double.class;
6256db1cdfea180251646dc68924ed2f18339f9d984maslovalex            }
6266db1cdfea180251646dc68924ed2f18339f9d984maslovalex            if (clazz == Boolean.TYPE) {
6276db1cdfea180251646dc68924ed2f18339f9d984maslovalex                return Boolean.class;
6286db1cdfea180251646dc68924ed2f18339f9d984maslovalex            }
629eb1c68f2396b6da521f4ae5778e845aade5bff1dAndrey Somov            if (clazz == Long.TYPE) {
630eb1c68f2396b6da521f4ae5778e845aade5bff1dAndrey Somov                return Long.class;
631eb1c68f2396b6da521f4ae5778e845aade5bff1dAndrey Somov            }
6326db1cdfea180251646dc68924ed2f18339f9d984maslovalex            if (clazz == Character.TYPE) {
6336db1cdfea180251646dc68924ed2f18339f9d984maslovalex                return Character.class;
6346db1cdfea180251646dc68924ed2f18339f9d984maslovalex            }
6356db1cdfea180251646dc68924ed2f18339f9d984maslovalex            if (clazz == Short.TYPE) {
6366db1cdfea180251646dc68924ed2f18339f9d984maslovalex                return Short.class;
6376db1cdfea180251646dc68924ed2f18339f9d984maslovalex            }
6386db1cdfea180251646dc68924ed2f18339f9d984maslovalex            if (clazz == Byte.TYPE) {
6396db1cdfea180251646dc68924ed2f18339f9d984maslovalex                return Byte.class;
6409629be70863521bead138c295351f3dec926ab1Andrey Somov            }
641eb1c68f2396b6da521f4ae5778e845aade5bff1dAndrey Somov            throw new YAMLException("Unexpected primitive " + clazz);
6429629be70863521bead138c295351f3dec926ab1Andrey Somov        }
643686d75fdde8a24dbe13646c3693f27776cd23831Andrey Somov
644686d75fdde8a24dbe13646c3693f27776cd23831Andrey Somov        @SuppressWarnings("unchecked")
645686d75fdde8a24dbe13646c3693f27776cd23831Andrey Somov        public void construct2ndStep(Node node, Object object) {
646686d75fdde8a24dbe13646c3693f27776cd23831Andrey Somov            SequenceNode snode = (SequenceNode) node;
6474cdfade09a608d4e09cdae6531fefe33048b685bmaslovalex            if (List.class.isAssignableFrom(node.getType())) {
6484cdfade09a608d4e09cdae6531fefe33048b685bmaslovalex                List<Object> list = (List<Object>) object;
649686d75fdde8a24dbe13646c3693f27776cd23831Andrey Somov                constructSequenceStep2(snode, list);
6504cdfade09a608d4e09cdae6531fefe33048b685bmaslovalex            } else if (node.getType().isArray()) {
6514cdfade09a608d4e09cdae6531fefe33048b685bmaslovalex                constructArrayStep2(snode, object);
652686d75fdde8a24dbe13646c3693f27776cd23831Andrey Somov            } else {
653050c422c295a0ff956f79ba91c4c5a21b255f721Andrey Somov                throw new YAMLException("Immutable objects cannot be recursive.");
654686d75fdde8a24dbe13646c3693f27776cd23831Andrey Somov            }
655686d75fdde8a24dbe13646c3693f27776cd23831Andrey Somov        }
6569629be70863521bead138c295351f3dec926ab1Andrey Somov    }
6579506e323ef3bd1554a138c978b8523e6831775bbAndrey Somov
658b5cbc4593dc009a3aa856bd70d5d1584609b8b8bAndrey Somov    protected Class<?> getClassForNode(Node node) {
659b5cbc4593dc009a3aa856bd70d5d1584609b8b8bAndrey Somov        Class<? extends Object> classForTag = typeTags.get(node.getTag());
660b5cbc4593dc009a3aa856bd70d5d1584609b8b8bAndrey Somov        if (classForTag == null) {
66187ff57908e8ccf62ef984bb067a61b815a9a1074Andrey Somov            String name = node.getTag().getClassName();
662b5cbc4593dc009a3aa856bd70d5d1584609b8b8bAndrey Somov            Class<?> cl;
663b5cbc4593dc009a3aa856bd70d5d1584609b8b8bAndrey Somov            try {
664db93e7b6ba4a6f93289325e236d278a510a59e47Andrey Somov                cl = getClassForName(name);
665b5cbc4593dc009a3aa856bd70d5d1584609b8b8bAndrey Somov            } catch (ClassNotFoundException e) {
666b5cbc4593dc009a3aa856bd70d5d1584609b8b8bAndrey Somov                throw new YAMLException("Class not found: " + name);
667b5cbc4593dc009a3aa856bd70d5d1584609b8b8bAndrey Somov            }
6681fa9989515d2c8fc77d5c7b363d735efd7e443cfAndrey Somov            typeTags.put(node.getTag(), cl);
6699506e323ef3bd1554a138c978b8523e6831775bbAndrey Somov            return cl;
6709506e323ef3bd1554a138c978b8523e6831775bbAndrey Somov        } else {
671b5cbc4593dc009a3aa856bd70d5d1584609b8b8bAndrey Somov            return classForTag;
6729506e323ef3bd1554a138c978b8523e6831775bbAndrey Somov        }
6739506e323ef3bd1554a138c978b8523e6831775bbAndrey Somov    }
674db93e7b6ba4a6f93289325e236d278a510a59e47Andrey Somov
675db93e7b6ba4a6f93289325e236d278a510a59e47Andrey Somov    protected Class<?> getClassForName(String name) throws ClassNotFoundException {
67651cc2aaca608d78bfd8c546ca3de60057e5488cfmaslovalex        try {
67751cc2aaca608d78bfd8c546ca3de60057e5488cfmaslovalex            return Class.forName(name, true, Thread.currentThread().getContextClassLoader());
67851cc2aaca608d78bfd8c546ca3de60057e5488cfmaslovalex        } catch (ClassNotFoundException e) {
67951cc2aaca608d78bfd8c546ca3de60057e5488cfmaslovalex            return Class.forName(name);
68051cc2aaca608d78bfd8c546ca3de60057e5488cfmaslovalex        }
681db93e7b6ba4a6f93289325e236d278a510a59e47Andrey Somov    }
6829629be70863521bead138c295351f3dec926ab1Andrey Somov}
683