import patch snakeyaml_recursive.patch from Alex Maslov
diff --git a/src/main/java/org/yaml/snakeyaml/composer/Composer.java b/src/main/java/org/yaml/snakeyaml/composer/Composer.java
index 80f52e2..bc400d0 100644
--- a/src/main/java/org/yaml/snakeyaml/composer/Composer.java
+++ b/src/main/java/org/yaml/snakeyaml/composer/Composer.java
@@ -4,9 +4,11 @@
 package org.yaml.snakeyaml.composer;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.yaml.snakeyaml.events.AliasEvent;
 import org.yaml.snakeyaml.events.Event;
@@ -35,10 +37,13 @@
     private final Resolver resolver;
     private final Map<String, Node> anchors;
 
+    private final Set<Node> recursiveNodes;
+    
     public Composer(Parser parser, Resolver resolver) {
         this.parser = parser;
         this.resolver = resolver;
         this.anchors = new HashMap<String, Node>();
+        this.recursiveNodes = new HashSet<Node>();
     }
 
     public boolean checkNode() {
@@ -86,10 +91,13 @@
         // Drop the DOCUMENT-END event.
         parser.getEvent();
         this.anchors.clear();
+//        recursiveNodes = new HashSet<Node>();
+        recursiveNodes.clear();
         return node;
     }
 
     private Node composeNode(Node parent, Object index) {
+        recursiveNodes.add(parent);
         if (parser.checkEvent(AliasEvent.class)) {
             AliasEvent event = (AliasEvent) parser.getEvent();
             String anchor = event.getAnchor();
@@ -97,7 +105,11 @@
                 throw new ComposerException(null, null, "found undefined alias " + anchor, event
                         .getStartMark());
             }
-            return (Node) anchors.get(anchor);
+            Node result = (Node) anchors.get(anchor);
+            if(recursiveNodes.remove(result)) {
+                result.setTwoStepsConstruction(true);
+            }
+            return result;
         }
         NodeEvent event = (NodeEvent) parser.peekEvent();
         String anchor = null;
@@ -117,6 +129,7 @@
             node = composeMappingNode(anchor);
         }
         // resolver.ascendResolver();
+        recursiveNodes.remove(parent);
         return node;
     }
 
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/AbstractConstruct.java b/src/main/java/org/yaml/snakeyaml/constructor/AbstractConstruct.java
new file mode 100644
index 0000000..6060dec
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/AbstractConstruct.java
@@ -0,0 +1,12 @@
+package org.yaml.snakeyaml.constructor;
+
+import org.yaml.snakeyaml.nodes.Node;
+
+public abstract class AbstractConstruct implements Construct {
+
+    public void construct2ndStep(Node node, Object data) {
+        assert node.isTwodStepsConstruction();
+        throw new IllegalStateException("Not Implemented in " + getClass().getName());
+    }
+
+}
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java b/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java
index 5b250ed..0e04396 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/BaseConstructor.java
@@ -4,10 +4,13 @@
 package org.yaml.snakeyaml.constructor;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
 
 import org.yaml.snakeyaml.composer.Composer;
 import org.yaml.snakeyaml.nodes.MappingNode;
@@ -23,13 +26,19 @@
 
     private Composer composer;
     private final Map<Node, Object> constructedObjects;
-    private final Map<Node, Object> recursiveObjects;
+    private final Set<Node> recursiveObjects;
+    private final Stack<Tuple<Node, Object>> toBeConstructedAt2ndStep;
+    private final LinkedList<Tuple<Map<Object, Object>, Tuple<Object, Object>>> maps2fill;
+    private final LinkedList<Tuple<Set<Object>, Object>> sets2fill;
 
     protected Class<? extends Object> rootType;
 
     public BaseConstructor() {
         constructedObjects = new HashMap<Node, Object>();
-        recursiveObjects = new HashMap<Node, Object>();
+        recursiveObjects = new HashSet<Node>();
+        toBeConstructedAt2ndStep = new Stack<Tuple<Node, Object>>();
+        maps2fill = new LinkedList<Tuple<Map<Object, Object>, Tuple<Object, Object>>>();
+        sets2fill = new LinkedList<Tuple<Set<Object>, Object>>();
         rootType = Object.class;
     }
 
@@ -62,8 +71,36 @@
 
     private Object constructDocument(Node node) {
         Object data = constructObject(node);
+
+        while (!toBeConstructedAt2ndStep.isEmpty()) {
+            Tuple<Node, Object> toBeProcessed = toBeConstructedAt2ndStep.pop();
+            callPostCreate(toBeProcessed._1(), toBeProcessed._2());
+        }
+
+        if (!maps2fill.isEmpty()) {
+            for (Tuple<Map<Object, Object>, Tuple<Object, Object>> entry : maps2fill) {
+                Tuple<Object, Object> key_value = entry._2();
+                entry._1().put(key_value._1(), key_value._2());
+            }
+            maps2fill.clear();
+        }
+
+        if (!sets2fill.isEmpty()) {
+            for (Tuple<Set<Object>, Object> value : sets2fill) {
+                value._1().add(value._2());
+            }
+            sets2fill.clear();
+        }
+
+        // constructedObjects = new HashMap<Node, Object>();
+        // recursiveObjects = new HashSet<Node>();
+        // toBeConstructedAt2ndStep = new Stack<Tuple<Node,Object>>();
+        // maps2fill = new
+        // LinkedList<Tuple<Map<Object,Object>,Tuple<Object,Object>>>();
+        // sets2fill = new LinkedList<Tuple<Set<Object>,Object>>();
         constructedObjects.clear();
         recursiveObjects.clear();
+        toBeConstructedAt2ndStep.clear();
         return data;
     }
 
@@ -71,11 +108,11 @@
         if (constructedObjects.containsKey(node)) {
             return constructedObjects.get(node);
         }
-        if (recursiveObjects.containsKey(node)) {
+        if (recursiveObjects.contains(node)) {
             throw new ConstructorException(null, null, "found unconstructable recursive node", node
                     .getStartMark());
         }
-        recursiveObjects.put(node, null);
+        recursiveObjects.add(node);
         Object data = callConstructor(node);
         constructedObjects.put(node, data);
         recursiveObjects.remove(node);
@@ -83,18 +120,25 @@
     }
 
     protected Object callConstructor(Node node) {
-        Object data = null;
-        Construct constructor = null;
-        constructor = yamlConstructors.get(node.getTag());
-        if (constructor == null) {
-            constructor = yamlConstructors.get(null);
-            data = constructor.construct(node);
-        } else {
-            data = constructor.construct(node);
+        Object data = getConstructor(node).construct(node);
+        if (node.isTwodStepsConstruction()) {
+            toBeConstructedAt2ndStep.push(new Tuple<Node, Object>(node, data));
         }
         return data;
     }
 
+    protected void callPostCreate(Node node, Object object) {
+        getConstructor(node).construct2ndStep(node, object);
+    }
+
+    private Construct getConstructor(Node node) {
+        Construct constructor = yamlConstructors.get(node.getTag());
+        if (constructor == null) {
+            return yamlConstructors.get(null);
+        }
+        return constructor;
+    }
+
     protected Object constructScalar(ScalarNode node) {
         return node.getValue();
     }
@@ -104,14 +148,20 @@
     }
 
     protected List<? extends Object> constructSequence(SequenceNode node) {
-        List<Node> nodeValue = (List<Node>) node.getValue();
-        List<Object> result = createDefaultList(nodeValue.size());
-        for (Node child : nodeValue) {
-            result.add(constructObject(child));
-        }
+        List<Object> result = createDefaultList(node.getValue().size());
+        constructSequenceStep2(node, result);
+        // for (Node child : nodeValue) {
+        // result.add(constructObject(child));
+        // }
         return result;
     }
 
+    protected void constructSequenceStep2(SequenceNode node, List<Object> list) {
+        for (Node child : node.getValue()) {
+            list.add(constructObject(child));
+        }
+    }
+
     protected Map<Object, Object> createDefaultMap() {
         // respect order from YAML document
         return new LinkedHashMap<Object, Object>();
@@ -119,6 +169,11 @@
 
     protected Map<Object, Object> constructMapping(MappingNode node) {
         Map<Object, Object> mapping = createDefaultMap();
+        constructMapping2ndStep(node, mapping);
+        return mapping;
+    }
+
+    protected void constructMapping2ndStep(MappingNode node, Map<Object, Object> mapping) {
         List<Node[]> nodeValue = (List<Node[]>) node.getValue();
         for (Node[] tuple : nodeValue) {
             Node keyNode = tuple[0];
@@ -134,10 +189,48 @@
                 }
             }
             Object value = constructObject(valueNode);
-            mapping.put(key, value);
+            if (keyNode.isTwodStepsConstruction()) {
+                /*
+                 * if keyObject is created it 2 steps we should postpone putting
+                 * it in map because it may have different hash after
+                 * initialization compared to clean just created one. And map of
+                 * course does not observe key hashCode changes.
+                 */
+                maps2fill.addFirst(new Tuple<Map<Object, Object>, Tuple<Object, Object>>(mapping,
+                        new Tuple<Object, Object>(key, value)));
+            } else {
+                mapping.put(key, value);
+            }
         }
-        return mapping;
     }
+
+    protected void constructSet2ndStep(MappingNode node, Set<Object> set) {
+        List<Node[]> nodeValue = (List<Node[]>) node.getValue();
+        for (Node[] tuple : nodeValue) {
+            Node keyNode = tuple[0];
+            Object key = constructObject(keyNode);
+            if (key != null) {
+                try {
+                    key.hashCode();// check circular dependencies
+                } catch (Exception e) {
+                    throw new ConstructorException("while constructing a Set", node.getStartMark(),
+                            "found unacceptable key " + key, tuple[0].getStartMark());
+                }
+            }
+            if (keyNode.isTwodStepsConstruction()) {
+                /*
+                 * if keyObject is created it 2 steps we should postpone putting
+                 * it into the set because it may have different hash after
+                 * initialization compared to clean just created one. And set of
+                 * course does not observe value hashCode changes.
+                 */
+                sets2fill.addFirst(new Tuple<Set<Object>, Object>(set, key));
+            } else {
+                set.add(key);
+            }
+        }
+    }
+
     // TODO protected List<Object[]> constructPairs(MappingNode node) {
     // List<Object[]> pairs = new LinkedList<Object[]>();
     // List<Node[]> nodeValue = (List<Node[]>) node.getValue();
@@ -149,4 +242,9 @@
     // }
     // return pairs;
     // }
+
+    protected void pushToConstruction2ndStep(Node node, Object object) {
+        toBeConstructedAt2ndStep.push(new Tuple<Node, Object>(node, object));
+    }
+
 }
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/Construct.java b/src/main/java/org/yaml/snakeyaml/constructor/Construct.java
index 55e27b0..c566100 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/Construct.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/Construct.java
@@ -7,4 +7,5 @@
 

 public interface Construct {

     public Object construct(Node node);

+    public void construct2ndStep(Node node, Object object);

 }

diff --git a/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
index 3483564..aae6acb 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/Constructor.java
@@ -14,6 +14,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.yaml.snakeyaml.TypeDescription;
 import org.yaml.snakeyaml.error.YAMLException;
@@ -22,6 +23,7 @@
 import org.yaml.snakeyaml.introspector.Property;
 import org.yaml.snakeyaml.nodes.MappingNode;
 import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeId;
 import org.yaml.snakeyaml.nodes.ScalarNode;
 import org.yaml.snakeyaml.nodes.SequenceNode;
 
@@ -90,7 +92,7 @@
         return typeDefinitions.put(definition.getType(), definition);
     }
 
-    private class ConstuctYamlObject implements Construct {
+    private class ConstuctYamlObject extends AbstractConstruct {
         @SuppressWarnings("unchecked")
         public Object construct(Node node) {
             Object result = null;
@@ -111,7 +113,11 @@
                 case mapping:
                     MappingNode mnode = (MappingNode) node;
                     mnode.setType(cl);
-                    result = constructMappingNode(mnode);
+                    if (node.isTwodStepsConstruction()) {
+                        result = createMappingNode(mnode, cl);
+                    } else {
+                        result = constructMappingNode(mnode);
+                    }
                     break;
                 case sequence:
                     SequenceNode seqNode = (SequenceNode) node;
@@ -148,6 +154,16 @@
             }
             return result;
         }
+
+        @Override
+        public void construct2ndStep(Node node, Object object) {
+            assert node.isTwodStepsConstruction();
+
+            if (node.getNodeId() == NodeId.mapping) {
+                constructMappingNode2ndStep((MappingNode) node, object, node.getType());
+            }
+        }
+
     }
 
     @Override
@@ -167,12 +183,45 @@
             if (Map.class.isAssignableFrom(node.getType())) {
                 result = super.constructMapping((MappingNode) node);
             } else {
-                result = constructMappingNode((MappingNode) node);
+                if (node.isTwodStepsConstruction()) {
+                    result = createMappingNode((MappingNode) node, node.getType());
+                } else {
+                    result = constructMappingNode((MappingNode) node);
+                }
             }
         }
         return result;
     }
 
+    @SuppressWarnings("unchecked")
+    @Override
+    protected void callPostCreate(Node node, Object object) {
+        assert node.isTwodStepsConstruction();
+
+        if (Object.class.equals(node.getType()) || "tag:yaml.org,2002:null".equals(node.getTag())) {
+            super.callPostCreate(node, object);
+
+        } else {
+
+            switch (node.getNodeId()) {
+            case scalar:
+                // result = constructScalarNode((ScalarNode) node);
+                break;
+            case sequence:
+                 constructSequenceStep2((SequenceNode) node, (List<Object>) object);
+                break;
+            default:// mapping
+                if (Map.class.isAssignableFrom(node.getType())) {
+                    constructMapping2ndStep((MappingNode)node, (Map<Object, Object>) object);
+                } else if(Set.class.isAssignableFrom(node.getType())) {
+                    constructSet2ndStep((MappingNode) node, (Set<Object>) object);
+                } else {
+                    constructMappingNode2ndStep((MappingNode) node, object, node.getType());
+                }
+            }
+        }
+    };
+
     private Object constructScalarNode(ScalarNode node) {
         Class<? extends Object> type = node.getType();
         Object result;
@@ -256,6 +305,16 @@
         return result;
     }
 
+    private Object createMappingNode(MappingNode mnode, Class<?> beanType) {
+        try {
+            return beanType.newInstance();
+        } catch (InstantiationException e) {
+            throw new YAMLException(e);
+        } catch (IllegalAccessException e) {
+            throw new YAMLException(e);
+        }
+    }
+
     /**
      * Construct JavaBean. If type safe collections are used please look at
      * <code>TypeDescription</code>.
@@ -268,14 +327,11 @@
     @SuppressWarnings("unchecked")
     private Object constructMappingNode(MappingNode node) {
         Class<? extends Object> beanType = node.getType();
-        Object object;
-        try {
-            object = beanType.newInstance();
-        } catch (InstantiationException e) {
-            throw new YAMLException(e);
-        } catch (IllegalAccessException e) {
-            throw new YAMLException(e);
-        }
+        return constructMappingNode2ndStep(node, createMappingNode(node, beanType), beanType);
+    }
+
+    private Object constructMappingNode2ndStep(MappingNode node, Object object,
+            Class<? extends Object> beanType) {
         List<Node[]> nodeValue = (List<Node[]>) node.getValue();
         for (Node[] tuple : nodeValue) {
             ScalarNode keyNode;
diff --git a/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java b/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java
index 450954a..7120cfe 100644
--- a/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java
+++ b/src/main/java/org/yaml/snakeyaml/constructor/SafeConstructor.java
@@ -11,6 +11,7 @@
 import java.util.LinkedList;

 import java.util.List;

 import java.util.Map;

+import java.util.Set;

 import java.util.TimeZone;

 import java.util.regex.Matcher;

 import java.util.regex.Pattern;

@@ -101,7 +102,17 @@
         return super.constructMapping(node);

     }

 

-    private class ConstuctYamlNull implements Construct {

+    protected void constructMapping2ndStep(MappingNode node, Map<Object, Object> mapping) {

+        flattenMapping(node);

+        super.constructMapping2ndStep(node, mapping);

+    }

+

+    @Override protected void constructSet2ndStep(MappingNode node, java.util.Set<Object> set) {

+        flattenMapping(node);

+        super.constructSet2ndStep(node, set);

+    };

+    

+    private class ConstuctYamlNull extends AbstractConstruct {

         public Object construct(Node node) {

             constructScalar((ScalarNode) node);

             return null;

@@ -118,14 +129,14 @@
         BOOL_VALUES.put("off", Boolean.FALSE);

     }

 

-    private class ConstuctYamlBool implements Construct {

+    private class ConstuctYamlBool extends AbstractConstruct {

         public Object construct(Node node) {

             String val = (String) constructScalar((ScalarNode) node);

             return BOOL_VALUES.get(val.toLowerCase());

         }

     }

 

-    private class ConstuctYamlInt implements Construct {

+    private class ConstuctYamlInt extends AbstractConstruct {

         public Object construct(Node node) {

             String value = constructScalar((ScalarNode) node).toString().replaceAll("_", "");

             int sign = +1;

@@ -183,7 +194,7 @@
         return result;

     }

 

-    private class ConstuctYamlFloat implements Construct {

+    private class ConstuctYamlFloat extends AbstractConstruct {

         public Object construct(Node node) {

             String value = constructScalar((ScalarNode) node).toString().replaceAll("_", "");

             int sign = +1;

@@ -219,7 +230,7 @@
         }

     }

 

-    private class ConstuctYamlBinary implements Construct {

+    private class ConstuctYamlBinary extends AbstractConstruct {

         public Object construct(Node node) {

             byte[] decoded = Base64Coder.decode(constructScalar((ScalarNode) node).toString()

                     .toCharArray());

@@ -232,7 +243,7 @@
     private final static Pattern YMD_REGEXP = Pattern

             .compile("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)$");

 

-    private class ConstuctYamlTimestamp implements Construct {

+    private class ConstuctYamlTimestamp extends AbstractConstruct {

         public Object construct(Node node) {

             Matcher match = YMD_REGEXP.matcher((String) node.getValue());

             if (match.matches()) {

@@ -300,7 +311,7 @@
         }

     }

 

-    private class ConstuctYamlOmap implements Construct {

+    private class ConstuctYamlOmap extends AbstractConstruct {

         public Object construct(Node node) {

             // Note: we do not check for duplicate keys, because it's too

             // CPU-expensive.

@@ -334,7 +345,7 @@
     }

 

     // Note: the same code as `construct_yaml_omap`.

-    private class ConstuctYamlPairs implements Construct {

+    private class ConstuctYamlPairs extends AbstractConstruct {

         public Object construct(Node node) {

             // Note: we do not check for duplicate keys, because it's too

             // CPU-expensive.

@@ -366,36 +377,73 @@
         }

     }

 

-    private class ConstuctYamlSet implements Construct {

+    private class ConstuctYamlSet extends AbstractConstruct {

+        

         public Object construct(Node node) {

-            Map<Object, Object> value = constructMapping((MappingNode) node);

-            return value.keySet();

+            if(node.isTwodStepsConstruction()) {

+                return createDefaultMap().keySet();

+            } else {

+                return constructMapping((MappingNode) node).keySet();

+            }

+        }

+        

+        @SuppressWarnings("unchecked")

+        @Override

+        public void construct2ndStep(Node node, Object object) {

+            assert node.isTwodStepsConstruction();

+            constructSet2ndStep((MappingNode)node, (Set<Object>) object);

         }

     }

 

-    private class ConstuctYamlStr implements Construct {

+    private class ConstuctYamlStr extends AbstractConstruct {

         public Object construct(Node node) {

             return (String) constructScalar((ScalarNode) node);

         }

     }

 

-    private class ConstuctYamlSeq implements Construct {

+    private class ConstuctYamlSeq extends AbstractConstruct {

+        @SuppressWarnings("unchecked")

         public Object construct(Node node) {

-            return constructSequence((SequenceNode) node);

+            if(node.isTwodStepsConstruction()) {

+                List<Node> nodeValue = (List<Node>) node.getValue();

+                return createDefaultList(nodeValue.size()); 

+            } else {

+                return constructSequence((SequenceNode) node);

+            }

+        }

+        

+        @SuppressWarnings("unchecked")

+        @Override

+        public void construct2ndStep(Node node, Object data) {

+            assert node.isTwodStepsConstruction();

+            constructSequenceStep2((SequenceNode) node, (List<Object>) data);

         }

     }

 

-    private class ConstuctYamlMap implements Construct {

+    private class ConstuctYamlMap extends AbstractConstruct {

         public Object construct(Node node) {

-            return constructMapping((MappingNode) node);

+            if(node.isTwodStepsConstruction()) {

+                return createDefaultMap();

+            } else {

+                return constructMapping((MappingNode) node);

+            }

         }

+

+        @SuppressWarnings("unchecked")

+        @Override

+        public void construct2ndStep(Node node, Object object) {

+            assert node.isTwodStepsConstruction();

+            constructMapping2ndStep((MappingNode)node, (Map<Object, Object>) object);

+        }

+       

     }

 

-    private class ConstuctUndefined implements Construct {

+    private class ConstuctUndefined extends AbstractConstruct {

         public Object construct(Node node) {

             throw new ConstructorException(null, null,

                     "could not determine a constructor for the tag " + node.getTag(), node

                             .getStartMark());

         }

     }

+

 }

diff --git a/src/main/java/org/yaml/snakeyaml/constructor/Tuple.java b/src/main/java/org/yaml/snakeyaml/constructor/Tuple.java
new file mode 100644
index 0000000..45994d0
--- /dev/null
+++ b/src/main/java/org/yaml/snakeyaml/constructor/Tuple.java
@@ -0,0 +1,21 @@
+package org.yaml.snakeyaml.constructor;
+
+public class Tuple<T, K> {
+
+    private final T _1;
+    private final K _2;
+
+    public Tuple(T _1, K _2) {
+        assert _1 != null && _2 != null;
+        this._1 = _1;
+        this._2 = _2;
+    }
+    
+    public K _2() {
+        return _2;
+    }
+
+    public T _1() {
+        return _1;
+    }
+}
diff --git a/src/main/java/org/yaml/snakeyaml/nodes/Node.java b/src/main/java/org/yaml/snakeyaml/nodes/Node.java
index 6fbd8aa..418b126 100644
--- a/src/main/java/org/yaml/snakeyaml/nodes/Node.java
+++ b/src/main/java/org/yaml/snakeyaml/nodes/Node.java
@@ -14,6 +14,7 @@
     private Mark startMark;
     protected Mark endMark;
     private Class<? extends Object> type;
+    private boolean twoStepsConstruction;
 
     public Node(String tag, Object value, Mark startMark, Mark endMark) {
         setTag(tag);
@@ -24,6 +25,7 @@
         this.startMark = startMark;
         this.endMark = endMark;
         this.type = Object.class;
+        this.twoStepsConstruction = false;
     }
 
     public String getTag() {
@@ -77,4 +79,12 @@
     public void setType(Class<? extends Object> type) {
         this.type = type;
     }
+    
+    public void setTwoStepsConstruction(boolean twoStepsConstruction) {
+        this.twoStepsConstruction = twoStepsConstruction;
+    }
+    
+    public boolean isTwodStepsConstruction() {
+        return twoStepsConstruction;
+    }
 }
diff --git a/src/test/java/examples/DiceExampleTest.java b/src/test/java/examples/DiceExampleTest.java
index 703990f..2b7a761 100644
--- a/src/test/java/examples/DiceExampleTest.java
+++ b/src/test/java/examples/DiceExampleTest.java
@@ -14,7 +14,7 @@
 import org.yaml.snakeyaml.DumperOptions;

 import org.yaml.snakeyaml.Loader;

 import org.yaml.snakeyaml.Yaml;

-import org.yaml.snakeyaml.constructor.Construct;

+import org.yaml.snakeyaml.constructor.AbstractConstruct;

 import org.yaml.snakeyaml.constructor.Constructor;

 import org.yaml.snakeyaml.nodes.Node;

 import org.yaml.snakeyaml.nodes.ScalarNode;

@@ -57,7 +57,7 @@
             this.yamlConstructors.put("!dice", new ConstructDice());

         }

 

-        private class ConstructDice implements Construct {

+        private class ConstructDice extends AbstractConstruct {

             public Object construct(Node node) {

                 String val = (String) constructScalar((ScalarNode) node);

                 int position = val.indexOf('d');

diff --git a/src/test/java/org/pyyaml/PyRecursiveTest.java b/src/test/java/org/pyyaml/PyRecursiveTest.java
index 000b36f..22c6fea 100644
--- a/src/test/java/org/pyyaml/PyRecursiveTest.java
+++ b/src/test/java/org/pyyaml/PyRecursiveTest.java
@@ -13,7 +13,6 @@
 import junit.framework.TestCase;

 

 import org.yaml.snakeyaml.Yaml;

-import org.yaml.snakeyaml.constructor.ConstructorException;

 

 public class PyRecursiveTest extends TestCase {

 

@@ -23,27 +22,34 @@
         AnInstance instance = new AnInstance(value, value);

         value.put(instance, instance);

         Yaml yaml = new Yaml();

-        try {

-            String output1 = yaml.dump(value);

-            Map<AnInstance, AnInstance> value2 = (Map<AnInstance, AnInstance>) yaml.load(output1);

-            assertEquals(value, value2);

-        } catch (ConstructorException e) {

-            // TODO recursive objects are not allowed

+        String output1 = yaml.dump(value);

+        Map<AnInstance, AnInstance> value2 = (Map<AnInstance, AnInstance>) yaml.load(output1);

+        assertEquals(value.size(), value2.size());

+        for (AnInstance tmpInstance : value2.values()) {

+            assertSame(tmpInstance.getBar(), tmpInstance.getFoo());

+            assertSame(tmpInstance.getBar(), value2);

+            assertSame(tmpInstance, value2.get(tmpInstance));

         }

+        // assertEquals(value,value2);

     }

 

     @SuppressWarnings("unchecked")

     public void testList() {

         List value = new ArrayList();

         value.add(value);

+        value.add("test");

+        value.add(new Integer(1));

+

         Yaml yaml = new Yaml();

-        try {

-            String output1 = yaml.dump(value);

-            List value2 = (List) yaml.load(output1);

-            assertEquals(value, value2);

-        } catch (ConstructorException e) {

-            // TODO recursive objects are not allowed

-        }

+        String output1 = yaml.dump(value);

+        List value2 = (List) yaml.load(output1);

+        assertSame(value2, value2.get(0));

+        // we expect self-reference as 1st element of the list

+        // let's remove self-reference and check other "simple" members of the

+        // list. otherwise assertEquals will lead us to StackOverflow

+        value.remove(0);

+        value2.remove(0);

+        assertEquals(value, value2);

     }

 

     @SuppressWarnings("unchecked")

@@ -51,12 +57,16 @@
         Set value = new HashSet();

         value.add(new AnInstance(value, value));

         Yaml yaml = new Yaml();

-        try {

-            String output1 = yaml.dump(value);

-            List value2 = (List) yaml.load(output1);

-            assertEquals(value, value2);

-        } catch (ConstructorException e) {

-            // TODO recursive objects are not allowed

+        String output1 = yaml.dump(value);

+        Set<AnInstance> value2 = (Set<AnInstance>) yaml.load(output1);

+

+        assertEquals(value.size(), value2.size());

+        for (AnInstance tmpInstance : value2) {

+            assertSame(tmpInstance.getBar(), tmpInstance.getFoo());

+            assertSame(tmpInstance.getBar(), value2);

         }

+        // assertEquals(value, value2);

     }

+

+    // TODO write same more complex tests for recursions. maybe recursion in Arrays, bean properties...

 }

diff --git a/src/test/java/org/pyyaml/PyStructureTest.java b/src/test/java/org/pyyaml/PyStructureTest.java
index 56cf7d3..719a712 100644
--- a/src/test/java/org/pyyaml/PyStructureTest.java
+++ b/src/test/java/org/pyyaml/PyStructureTest.java
@@ -14,7 +14,7 @@
 import org.yaml.snakeyaml.Loader;

 import org.yaml.snakeyaml.Yaml;

 import org.yaml.snakeyaml.composer.Composer;

-import org.yaml.snakeyaml.constructor.Construct;

+import org.yaml.snakeyaml.constructor.AbstractConstruct;

 import org.yaml.snakeyaml.constructor.Constructor;

 import org.yaml.snakeyaml.events.AliasEvent;

 import org.yaml.snakeyaml.events.CollectionStartEvent;

@@ -248,7 +248,7 @@
             this.yamlConstructors.put(null, new ConstructUndefined());

         }

 

-        private class ConstructUndefined implements Construct {

+        private class ConstructUndefined extends AbstractConstruct {

             public Object construct(Node node) {

                 return constructScalar((ScalarNode) node);

             }

diff --git a/src/test/java/org/yaml/snakeyaml/Chapter2_4Test.java b/src/test/java/org/yaml/snakeyaml/Chapter2_4Test.java
index 2a2ce53..0c01bee 100644
--- a/src/test/java/org/yaml/snakeyaml/Chapter2_4Test.java
+++ b/src/test/java/org/yaml/snakeyaml/Chapter2_4Test.java
@@ -15,7 +15,7 @@
 

 import junit.framework.TestCase;

 

-import org.yaml.snakeyaml.constructor.Construct;

+import org.yaml.snakeyaml.constructor.AbstractConstruct;

 import org.yaml.snakeyaml.constructor.Constructor;

 import org.yaml.snakeyaml.nodes.Node;

 import org.yaml.snakeyaml.nodes.ScalarNode;

@@ -121,7 +121,7 @@
             this.yamlConstructors.put("!something", new ConstructSomething());

         }

 

-        private class ConstructSomething implements Construct {

+        private class ConstructSomething extends AbstractConstruct {

             public Object construct(Node node) {

                 // convert to upper case

                 String val = (String) constructScalar((ScalarNode) node);

diff --git a/src/test/java/org/yaml/snakeyaml/Example2_24Test.java b/src/test/java/org/yaml/snakeyaml/Example2_24Test.java
index fbb0e21..9d2d7a5 100644
--- a/src/test/java/org/yaml/snakeyaml/Example2_24Test.java
+++ b/src/test/java/org/yaml/snakeyaml/Example2_24Test.java
@@ -10,7 +10,7 @@
 

 import junit.framework.TestCase;

 

-import org.yaml.snakeyaml.constructor.Construct;

+import org.yaml.snakeyaml.constructor.AbstractConstruct;

 import org.yaml.snakeyaml.constructor.Constructor;

 import org.yaml.snakeyaml.nodes.MappingNode;

 import org.yaml.snakeyaml.nodes.Node;

@@ -33,7 +33,7 @@
             this.yamlConstructors.put("tag:clarkevans.com,2002:label", new ConstructLabel());

         }

 

-        private class ConstructShape implements Construct {

+        private class ConstructShape extends AbstractConstruct {

             @SuppressWarnings("unchecked")

             public Object construct(Node node) {

                 SequenceNode snode = (SequenceNode) node;

@@ -43,7 +43,7 @@
             }

         }

 

-        private class ConstructCircle implements Construct {

+        private class ConstructCircle extends AbstractConstruct {

             @SuppressWarnings("unchecked")

             public Object construct(Node node) {

                 MappingNode mnode = (MappingNode) node;

@@ -54,7 +54,7 @@
             }

         }

 

-        private class ConstructLine implements Construct {

+        private class ConstructLine extends AbstractConstruct {

             @SuppressWarnings("unchecked")

             public Object construct(Node node) {

                 MappingNode mnode = (MappingNode) node;

@@ -64,7 +64,7 @@
             }

         }

 

-        private class ConstructLabel implements Construct {

+        private class ConstructLabel extends AbstractConstruct {

             @SuppressWarnings("unchecked")

             public Object construct(Node node) {

                 MappingNode mnode = (MappingNode) node;

diff --git a/src/test/java/org/yaml/snakeyaml/ParallelTest.java b/src/test/java/org/yaml/snakeyaml/ParallelTest.java
index 1de2f2b..015e792 100644
--- a/src/test/java/org/yaml/snakeyaml/ParallelTest.java
+++ b/src/test/java/org/yaml/snakeyaml/ParallelTest.java
@@ -46,14 +46,14 @@
             System.out.println("Started: " + id);

             Loader loader = new Loader(new Constructor(Invoice.class));

             Yaml yaml = new Yaml(loader);

-            long time1 = System.currentTimeMillis();

+            long time1 = System.nanoTime();

             int cycles = 200;

             for (int i = 0; i < cycles; i++) {

                 Invoice invoice = (Invoice) yaml.load(doc);

                 assertNotNull(invoice);

             }

-            long time2 = System.currentTimeMillis();

-            float duration = (time2 - time1) / (float) cycles;

+            long time2 = System.nanoTime();

+            float duration = ((time2 - time1) / 1000000) / (float) cycles;

             System.out.println("Duration of " + id + " was " + duration + " ms/load.");

             progress++;

         }

diff --git a/src/test/java/org/yaml/snakeyaml/StressTest.java b/src/test/java/org/yaml/snakeyaml/StressTest.java
index 708366a..bc2e4eb 100644
--- a/src/test/java/org/yaml/snakeyaml/StressTest.java
+++ b/src/test/java/org/yaml/snakeyaml/StressTest.java
@@ -17,42 +17,42 @@
     }

 

     public void testPerformance() throws IOException {

-        long time1 = System.currentTimeMillis();

+        long time1 = System.nanoTime();

         new Yaml(new Loader(new Constructor(Invoice.class)));

-        long time2 = System.currentTimeMillis();

-        float duration = time2 - time1;

+        long time2 = System.nanoTime();

+        float duration = (time2 - time1) / 1000000;

         System.out.println("Init was " + duration + " ms.");

 

         Yaml yaml = new Yaml(new Loader(new Constructor(Invoice.class)));

-        time1 = System.currentTimeMillis();

+        time1 = System.nanoTime();

         yaml.load(doc);

-        time2 = System.currentTimeMillis();

-        duration = time2 - time1;

+        time2 = System.nanoTime();

+        duration = (time2 - time1) / 1000000;

         System.out.println("\nSingle load was " + duration + " ms.");

 

         yaml = new Yaml(new Loader(new Constructor(Invoice.class)));

         int[] range = new int[] { 1000, 2000 };

         System.out.println("\nOne instance.");

         for (int number : range) {

-            time1 = System.currentTimeMillis();

+            time1 = System.nanoTime();

             for (int i = 0; i < number; i++) {

                 yaml.load(doc);

             }

-            time2 = System.currentTimeMillis();

-            duration = (time2 - time1) / (float) number;

+            time2 = System.nanoTime();

+            duration = ((time2 - time1) / 1000000) / (float) number;

             System.out.println("Duration for r=" + number + " was " + duration + " ms/load.");

             assertTrue("duration=" + duration, duration < 5);

         }

 

         System.out.println("\nMany instances.");

         for (int number : range) {

-            time1 = System.currentTimeMillis();

+            time1 = System.nanoTime();

             for (int i = 0; i < number; i++) {

                 yaml = new Yaml(new Loader(new Constructor(Invoice.class)));

                 yaml.load(doc);

             }

-            time2 = System.currentTimeMillis();

-            duration = (time2 - time1) / (float) number;

+            time2 = System.nanoTime();

+            duration = ((time2 - time1) / 1000000) / (float) number;

             System.out.println("Duration for r=" + number + " was " + duration + " ms/load.");

             assertTrue("duration=" + duration, duration < 5);

         }

diff --git a/src/test/java/org/yaml/snakeyaml/emitter/EventConstructor.java b/src/test/java/org/yaml/snakeyaml/emitter/EventConstructor.java
index 7309e1a..d542376 100644
--- a/src/test/java/org/yaml/snakeyaml/emitter/EventConstructor.java
+++ b/src/test/java/org/yaml/snakeyaml/emitter/EventConstructor.java
@@ -7,7 +7,7 @@
 import java.util.List;

 import java.util.Map;

 

-import org.yaml.snakeyaml.constructor.Construct;

+import org.yaml.snakeyaml.constructor.AbstractConstruct;

 import org.yaml.snakeyaml.constructor.Constructor;

 import org.yaml.snakeyaml.events.AliasEvent;

 import org.yaml.snakeyaml.events.DocumentEndEvent;

@@ -30,7 +30,7 @@
         this.yamlConstructors.put(null, new ConstructEvent());

     }

 

-    private class ConstructEvent implements Construct {

+    private class ConstructEvent extends AbstractConstruct {

 

         @SuppressWarnings("unchecked")

         public Object construct(Node node) {

diff --git a/src/test/java/org/yaml/snakeyaml/representer/RepresentTest.java b/src/test/java/org/yaml/snakeyaml/representer/RepresentTest.java
index 89f1c38..bf7b942 100644
--- a/src/test/java/org/yaml/snakeyaml/representer/RepresentTest.java
+++ b/src/test/java/org/yaml/snakeyaml/representer/RepresentTest.java
@@ -9,7 +9,7 @@
 import org.yaml.snakeyaml.DumperOptions;

 import org.yaml.snakeyaml.Loader;

 import org.yaml.snakeyaml.Yaml;

-import org.yaml.snakeyaml.constructor.Construct;

+import org.yaml.snakeyaml.constructor.AbstractConstruct;

 import org.yaml.snakeyaml.constructor.Constructor;

 import org.yaml.snakeyaml.nodes.Node;

 import org.yaml.snakeyaml.nodes.ScalarNode;

@@ -73,7 +73,7 @@
             this.yamlConstructors.put("tag:yaml.org,2002:Dice", new ConstuctDice());

         }

 

-        private class ConstuctDice implements Construct {

+        private class ConstuctDice extends AbstractConstruct {

             public Object construct(Node node) {

                 String val = (String) constructScalar((ScalarNode) node);

                 return new CustomBean(val.substring(0, 1), Integer.parseInt(val.substring(2)));

diff --git a/src/test/java/org/yaml/snakeyaml/resolver/ResolverTest.java b/src/test/java/org/yaml/snakeyaml/resolver/ResolverTest.java
index 8c3d56f..8878293 100644
--- a/src/test/java/org/yaml/snakeyaml/resolver/ResolverTest.java
+++ b/src/test/java/org/yaml/snakeyaml/resolver/ResolverTest.java
@@ -16,7 +16,7 @@
 import org.yaml.snakeyaml.DumperOptions;

 import org.yaml.snakeyaml.Loader;

 import org.yaml.snakeyaml.Yaml;

-import org.yaml.snakeyaml.constructor.Construct;

+import org.yaml.snakeyaml.constructor.AbstractConstruct;

 import org.yaml.snakeyaml.constructor.Constructor;

 import org.yaml.snakeyaml.nodes.Node;

 import org.yaml.snakeyaml.nodes.ScalarNode;

@@ -108,7 +108,7 @@
             this.yamlConstructors.put("tag:yaml.org,2002:Phone", new ConstuctPhone());

         }

 

-        private class ConstuctPhone implements Construct {

+        private class ConstuctPhone extends AbstractConstruct {

             public Object construct(Node node) {

                 String val = (String) constructScalar((ScalarNode) node);

                 return new Phone(val);