Repository: decorators-squad/eo-yaml
Pull request #322 (2020-04-14 14:29:37)

Implement Bean-to-YAML with Reflection
PR for #306 
Implemented Bean-To-Yaml ("dumping") using Reflection API, without 3rd party libs.


Patch:
diff --git a/src/main/java/com/amihaiemil/eoyaml/AbstractYamlDump.java b/src/main/java/com/amihaiemil/eoyaml/AbstractYamlDump.java
index 2dfb7b9..1d5406d 100644
--- a/src/main/java/com/amihaiemil/eoyaml/AbstractYamlDump.java
+++ b/src/main/java/com/amihaiemil/eoyaml/AbstractYamlDump.java
@@ -29,13 +29,13 @@ package com.amihaiemil.eoyaml;
 
 /**
  * A Yaml representer.
+ * @deprecated Will be removed in one of the future versions. You can dump any
+ *  Java Object by starting from the method Yaml.createYamlDump(...).
  * @author Sherif Waly (sherifwaly95@gmail.com)
  * @version $Id$
  * @since 1.0.0
- * @todo #30:30m/DEV Add method ``serlialize()`` in YamlNode interface
- *  and implement it in the YamlNode implementors (e.g. Scalar) to serlialize
- *  it and return the Yaml node as a Yaml tree.
  */
+@Deprecated
 public abstract class AbstractYamlDump {
 
     /**
diff --git a/src/main/java/com/amihaiemil/eoyaml/ReflectedYamlDump.java b/src/main/java/com/amihaiemil/eoyaml/ReflectedYamlDump.java
new file mode 100644
index 0000000..7de3e67
--- /dev/null
+++ b/src/main/java/com/amihaiemil/eoyaml/ReflectedYamlDump.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2016-2020, Mihai Emil Andronache
+ * All rights reserved.
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+package com.amihaiemil.eoyaml;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * A YamlDump that works with the Reflection API.
+ * @checkstyle LineLength (100 lines)
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 4.3.3
+ */
+final class ReflectedYamlDump implements YamlDump {
+
+    /**
+     * If the value is any of these types, it is a Scalar.
+     */
+    private static final List<Class> SCALAR_TYPES = Arrays.asList(
+        Integer.class, Long.class, Float.class, Double.class, Short.class,
+        String.class, Boolean.class, Character.class, Byte.class
+    );
+
+    /**
+     * Object to dump.
+     */
+    private final Object object;
+
+    /**
+     * Constructor.
+     * @param object Object to dump.
+     */
+    ReflectedYamlDump(final Object object){
+        this.object = object;
+    }
+
+    @Override
+    public YamlNode dump() {
+        final YamlNode node;
+        if(this.object == null || SCALAR_TYPES.contains(this.object.getClass())) {
+            node = new ReflectedYamlScalar(this.object);
+        } else if(this.object instanceof Collection || this.object.getClass().isArray()){
+            node = new ReflectedYamlScalar(this.object);
+        } else {
+            node = new ReflectedYamlMapping(this.object);
+        }
+        return node;
+    }
+}
diff --git a/src/main/java/com/amihaiemil/eoyaml/ReflectedYamlMapping.java b/src/main/java/com/amihaiemil/eoyaml/ReflectedYamlMapping.java
new file mode 100644
index 0000000..b09d17a
--- /dev/null
+++ b/src/main/java/com/amihaiemil/eoyaml/ReflectedYamlMapping.java
@@ -0,0 +1,215 @@
+/**
+ * Copyright (c) 2016-2020, Mihai Emil Andronache
+ * All rights reserved.
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+package com.amihaiemil.eoyaml;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+
+/**
+ * YamlMapping reflected from a Java Bean.
+ * @checkstyle BooleanExpressionComplexity (300 lines)
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 4.3.3
+ */
+final class ReflectedYamlMapping extends BaseYamlMapping {
+
+    /**
+     * Java Bean being reflected.
+     */
+    private final Object bean;
+
+    /**
+     * Constructor.
+     * @param bean Serializable get/set Java Bean.
+     */
+    ReflectedYamlMapping(final Object bean) {
+        if(bean instanceof Collection || bean.getClass().isArray()) {
+            throw new IllegalArgumentException(
+                "YamlMapping can only be reflected "
+              + "from an Object or from a Map."
+            );
+        }
+        this.bean = bean;
+    }
+
+    @Override
+    public Set<YamlNode> keys() {
+        final Set<YamlNode> keys = new LinkedHashSet<>();
+        if(this.bean instanceof Map) {
+            for(final Object key : ((Map) this.bean).keySet()) {
+                keys.add(this.objectToYamlNode(key));
+            }
+        } else {
+            final Method[] methods = this.bean.getClass().getDeclaredMethods();
+            for (final Method method : methods) {
+                if (Modifier.isPublic(method.getModifiers())
+                    && method.getParameterCount() == 0
+                    && !method.getReturnType().equals(Void.TYPE)
+                ) {
+                    keys.add(new MethodKey(method));
+                }
+            }
+        }
+        return keys;
+    }
+
+    @Override
+    public YamlNode value(final YamlNode key) {
+        YamlNode node = null;
+        if(this.bean instanceof Map) {
+            for(final Object mapKey : ((Map) bean).keySet()) {
+                if(key.equals(this.objectToYamlNode(mapKey))) {
+                    node = this.objectToYamlNode(((Map) bean).get(mapKey));
+                    break;
+                }
+            }
+        } else {
+            if (key instanceof Scalar) {
+                node = this.objectToYamlNode(
+                    this.invokeMethod(((Scalar) key).value())
+                );
+            } else {
+                throw new IllegalArgumentException(
+                    "Reflected YamlMapping can only have string keys "
+                  + "representing the method names of the reflected Java Bean!"
+                );
+            }
+        }
+        return node;
+    }
+
+    @Override
+    public Comment comment() {
+        return new Comment() {
+            @Override
+            public YamlNode yamlNode() {
+                return ReflectedYamlMapping.this;
+            }
+
+            @Override
+            public String value() {
+                return "";
+            }
+        };
+    }
+
+    /**
+     * Invoke the method represented by given YamlNode key, on the
+     * encapsulated Java Bean.
+     * @param keyName String key in the YamlMapping, representing a method.
+     * @return Object, the result of the method's invocation.
+     */
+    private Object invokeMethod(final String keyName) {
+        Object value = null;
+        final Method[] methods = this.bean.getClass().getDeclaredMethods();
+        for(final Method method : methods) {
+            if (Modifier.isPublic(method.getModifiers())
+                && method.getParameterCount() == 0
+                && !method.getReturnType().equals(Void.TYPE)
+                && (method.getName().equalsIgnoreCase(keyName)
+                || method.getName().equalsIgnoreCase("get" + keyName))
+            ) {
+                try {
+                    value = method.invoke(this.bean);
+                } catch (final IllegalAccessException iae) {
+                    throw new IllegalStateException(iae);
+                } catch (final InvocationTargetException ite) {
+                    throw new IllegalStateException(ite);
+                }
+            }
+        }
+        return value;
+    }
+
+    /**
+     * Turn a Java Object to an appropriate YAML Node.
+     * @param value Object value.
+     * @return YamlNode.
+     */
+    private YamlNode objectToYamlNode(final Object value) {
+        return Yaml.createYamlDump(value).dump();
+    }
+
+    /**
+     * A YAML Scalar which will be the key in this reflected
+     * YamlMapping.
+     */
+    static class MethodKey extends BaseScalar {
+
+        /**
+         * The object's method which is the key in the
+         * reflected YamlMapping.
+         */
+        private final Method method;
+
+        /**
+         * Constructor.
+         * @param method Method key.
+         */
+        MethodKey(final Method method) {
+            this.method = method;
+        }
+
+        @Override
+        public String value() {
+            String keyName;
+            final String methodName = this.method.getName();
+            if(methodName.startsWith("get") && methodName.length() > 3) {
+                final String first = String.valueOf(
+                        this.method.getName().substring(3).charAt(0)
+                );
+                keyName = first.toLowerCase();
+                if(methodName.substring(3).length() > 1) {
+                    keyName = keyName + methodName.substring(4);
+                }
+
+            } else {
+                keyName = this.method.getName();
+            }
+            return keyName;
+        }
+
+        @Override
+        public Comment comment() {
+            return new Comment() {
+                @Override
+                public YamlNode yamlNode() {
+                    return MethodKey.this;
+                }
+
+                @Override
+                public String value() {
+                    return "";
+                }
+            };
+        }
+    }
+}
diff --git a/src/main/java/com/amihaiemil/eoyaml/ReflectedYamlScalar.java b/src/main/java/com/amihaiemil/eoyaml/ReflectedYamlScalar.java
new file mode 100644
index 0000000..bfd0c9e
--- /dev/null
+++ b/src/main/java/com/amihaiemil/eoyaml/ReflectedYamlScalar.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2016-2020, Mihai Emil Andronache
+ * All rights reserved.
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+package com.amihaiemil.eoyaml;
+
+/**
+ * YAML Scalar reflected from an Object.
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 4.3.3
+ */
+final class ReflectedYamlScalar extends BaseScalar {
+
+    /**
+     * Scalar object being reflected.
+     */
+    private final Object scalar;
+
+    /**
+     * Constructor.
+     * @param scalar Scalar Object
+     */
+    ReflectedYamlScalar(final Object scalar) {
+        this.scalar = scalar;
+    }
+
+    @Override
+    public String value() {
+        final String value;
+        if(this.scalar == null) {
+            value = null;
+        } else {
+            value = String.valueOf(scalar);
+        }
+        return value;
+    }
+
+    @Override
+    public Comment comment() {
+        return new Comment() {
+            @Override
+            public YamlNode yamlNode() {
+                return ReflectedYamlScalar.this;
+            }
+
+            @Override
+            public String value() {
+                return "";
+            }
+        };
+    }
+}
diff --git a/src/main/java/com/amihaiemil/eoyaml/ReflectedYamlSequence.java b/src/main/java/com/amihaiemil/eoyaml/ReflectedYamlSequence.java
new file mode 100644
index 0000000..bf7105f
--- /dev/null
+++ b/src/main/java/com/amihaiemil/eoyaml/ReflectedYamlSequence.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (c) 2016-2020, Mihai Emil Andronache
+ * All rights reserved.
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+package com.amihaiemil.eoyaml;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * YamlSequence reflected from a Collection or an array of Object.
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 4.3.3
+ */
+final class ReflectedYamlSequence extends BaseYamlSequence {
+
+    /**
+     * Object sequence.
+     */
+    private final Collection<Object> sequence;
+
+    /**
+     * Constructor.
+     * @param sequence Collection or array of Object.
+     */
+    ReflectedYamlSequence(final Object sequence) {
+        if(sequence instanceof Collection) {
+            this.sequence = (Collection<Object>) sequence;
+        } else if(sequence.getClass().isArray()) {
+            final Object[] array = (Object[]) sequence;
+            this.sequence = Arrays.asList(array);
+        } else {
+            throw new IllegalArgumentException(
+                "YamlSequence can only be reflected "
+              + "from a Collection or from an array."
+            );
+        }
+    }
+
+    @Override
+    public Collection<YamlNode> values() {
+        final List<YamlNode> values = new ArrayList<>();
+        for(final Object value : this.sequence) {
+            values.add(Yaml.createYamlDump(value).dump());
+        }
+        return values;
+    }
+
+    @Override
+    public Comment comment() {
+        return new Comment() {
+            @Override
+            public YamlNode yamlNode() {
+                return ReflectedYamlSequence.this;
+            }
+
+            @Override
+            public String value() {
+                return "";
+            }
+        };
+    }
+
+}
diff --git a/src/main/java/com/amihaiemil/eoyaml/Yaml.java b/src/main/java/com/amihaiemil/eoyaml/Yaml.java
index cd1ced8..2f4f35a 100644
--- a/src/main/java/com/amihaiemil/eoyaml/Yaml.java
+++ b/src/main/java/com/amihaiemil/eoyaml/Yaml.java
@@ -122,4 +122,13 @@ public final class Yaml {
     public static YamlPrinter createYamlPrinter(final Writer destination) {
         return new RtYamlPrinter(destination);
     }
+
+    /**
+     * Create a YAML dump to represent the given object as YAML.
+     * @param object Object to dump.
+     * @return YamlDump.
+     */
+    public static YamlDump createYamlDump(final Object object) {
+        return new ReflectedYamlDump(object);
+    }
 }
diff --git a/src/main/java/com/amihaiemil/eoyaml/YamlCollectionDump.java b/src/main/java/com/amihaiemil/eoyaml/YamlCollectionDump.java
index 6bab6a4..e28542d 100644
--- a/src/main/java/com/amihaiemil/eoyaml/YamlCollectionDump.java
+++ b/src/main/java/com/amihaiemil/eoyaml/YamlCollectionDump.java
@@ -31,11 +31,14 @@ import java.util.Collection;
 
 /**
  * A collection represented as YamlNode.
+ * @deprecated Will be removed in one of the future versions. You can dump any
+ *  Java Object by starting from the method Yaml.createYamlDump(...).
  * @author Sherif Waly (sherifwaly95@gmail.com)
  * @version $Id$
  * @since 1.0.0
  *
  */
+@Deprecated
 public final class YamlCollectionDump extends AbstractYamlDump {
     /**
      * Collection<Object> to dump.
diff --git a/src/main/java/com/amihaiemil/eoyaml/YamlDump.java b/src/main/java/com/amihaiemil/eoyaml/YamlDump.java
new file mode 100644
index 0000000..31e3246
--- /dev/null
+++ b/src/main/java/com/amihaiemil/eoyaml/YamlDump.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright (c) 2016-2020, Mihai Emil Andronache
+ * All rights reserved.
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+package com.amihaiemil.eoyaml;
+
+/**
+ * In YAML, "dumping" means representing the state of an Object as YAML.
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 4.3.3
+ */
+public interface YamlDump {
+
+    /**
+     *
+     * Dump an Object, represent it as YAML.
+     * Generally, if the Object is a Collection or on Array, the resulting
+     * YamlNode will be a YamlSequence.<br><br>
+     * If the Object is a Map or other kind of Object, the resulting
+     * YamlNode will be a YamlSequence.<br><br>
+     * If the Object is a String, LocalDate, LocaDateTime or a primitive,
+     * the resulting YamlNode will be a plain Scalar.
+     * @return YAML Representation.
+     */
+    YamlNode dump();
+
+    /**
+     * Convenience method, equivalent to calling the
+     * dump(...) method and casting the YamlNode to YamlMapping.
+     * @return YamlMapping.
+     */
+    default YamlMapping dumpMapping() {
+        return (YamlMapping) this.dump();
+    }
+
+    /**
+     * Convenience method, equivalent to calling the
+     * dump(...) method and casting the YamlNode to YamlSequence.
+     * @return YamlSequence.
+     */
+    default YamlSequence dumpSequence() {
+        return (YamlSequence) this.dump();
+    }
+
+    /**
+     * Convenience method, equivalent to calling the
+     * dump(...) method and casting the YamlNode to Scalar.
+     * @return Scalar.
+     */
+    default Scalar dumpScalar() {
+        return (Scalar) this.dump();
+    }
+
+}
diff --git a/src/main/java/com/amihaiemil/eoyaml/YamlMapDump.java b/src/main/java/com/amihaiemil/eoyaml/YamlMapDump.java
index 6071202..581fcf0 100644
--- a/src/main/java/com/amihaiemil/eoyaml/YamlMapDump.java
+++ b/src/main/java/com/amihaiemil/eoyaml/YamlMapDump.java
@@ -32,11 +32,13 @@ import java.util.Set;
 
 /**
  * A Map represented as YamlNode.
+ * @deprecated Will be removed in one of the future versions. You can dump any
+ *  Java Object by starting from the method Yaml.createYamlDump(...).
  * @author Sherif Waly (sherifwaly95@gmail.com)
  * @version $Id$
  * @since 1.0.0
- *
  */
+@Deprecated
 public final class YamlMapDump extends AbstractYamlDump {
 
     /**
diff --git a/src/main/java/com/amihaiemil/eoyaml/YamlObjectDump.java b/src/main/java/com/amihaiemil/eoyaml/YamlObjectDump.java
index 4038fc8..2a9f25e 100644
--- a/src/main/java/com/amihaiemil/eoyaml/YamlObjectDump.java
+++ b/src/main/java/com/amihaiemil/eoyaml/YamlObjectDump.java
@@ -35,11 +35,13 @@ import org.apache.commons.beanutils.BeanMap;
 
 /**
  * An Object represented as a YamlMapping.
+ * @deprecated Will be removed in one of the future versions. You can dump any
+ *  Java Object by starting from the method Yaml.createYamlDump(...).
  * @author Mihai Andronache (amihaiemil@gmail.com)
  * @version $Id$
  * @since 1.0.0
- *
  */
+@Deprecated
 public final class YamlObjectDump extends AbstractYamlDump {
 
     /**


Test patch:
diff --git a/src/test/java/com/amihaiemil/eoyaml/ReflectedYamlMappingTest.java b/src/test/java/com/amihaiemil/eoyaml/ReflectedYamlMappingTest.java
new file mode 100644
index 0000000..90ebb0b
--- /dev/null
+++ b/src/test/java/com/amihaiemil/eoyaml/ReflectedYamlMappingTest.java
@@ -0,0 +1,172 @@
+/**
+ * Copyright (c) 2016-2020, Mihai Emil Andronache
+ * All rights reserved.
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+package com.amihaiemil.eoyaml;
+
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Unit tests for {@link ReflectedYamlMapping}.
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 4.3.3
+ */
+public final class ReflectedYamlMappingTest {
+    /**
+     * A reflected mapping has no comment.
+     */
+    @Test
+    public void returnsEmptyComment() {
+        final YamlMapping mapping = new ReflectedYamlMapping("map: value");
+        MatcherAssert.assertThat(
+            mapping.comment().yamlNode(),
+            Matchers.is(mapping)
+        );
+        MatcherAssert.assertThat(
+            mapping.comment().value(),
+            Matchers.isEmptyString()
+        );
+    }
+
+    /**
+     * A reflected mapping reflects the object's public and non-void methods
+     * as Scalar keys.
+     */
+    @Test
+    public void reflectsKeys() {
+        final YamlMapping mapping = new ReflectedYamlMapping(
+            new Student("Mihai", "Test", 20, 3.5)
+        );
+        final List<String> keys = mapping.keys().stream().map(
+            key -> ((ReflectedYamlMapping.MethodKey) key).value()
+        ).collect(Collectors.toList());
+        MatcherAssert.assertThat(keys.size(), Matchers.equalTo(5));
+        MatcherAssert.assertThat(keys, Matchers.hasItem("firstName"));
+        MatcherAssert.assertThat(keys, Matchers.hasItem("lastName"));
+        MatcherAssert.assertThat(keys, Matchers.hasItem("age"));
+        MatcherAssert.assertThat(keys, Matchers.hasItem("gpa"));
+        MatcherAssert.assertThat(keys, Matchers.hasItem("grades"));
+    }
+
+    /**
+     * A reflected mapping reflects the object's values (method returns).
+     */
+    @Test
+    public void reflectsValuess() {
+        final YamlMapping mapping = new ReflectedYamlMapping(
+            new Student("Mihai", "Test", 20, 3.5)
+        );
+        MatcherAssert.assertThat(
+            mapping.string("firstName"),
+            Matchers.equalTo("Mihai")
+        );
+        MatcherAssert.assertThat(
+            mapping.string("lastName"),
+            Matchers.equalTo("Test")
+        );
+        MatcherAssert.assertThat(
+            mapping.integer("age"),
+            Matchers.is(20)
+        );
+        MatcherAssert.assertThat(
+            mapping.doubleNumber("gpa"),
+            Matchers.is(3.5)
+        );
+        MatcherAssert.assertThat(
+            mapping.yamlMapping("grades"),
+            Matchers.instanceOf(ReflectedYamlMapping.class)
+        );
+    }
+
+    /**
+     * Simple student pojo for test.
+     * @checkstyle JavadocVariable (100 lines)
+     * @checkstyle JavadocMethod (100 lines)
+     * @checkstyle HiddenField (100 lines)
+     * @checkstyle ParameterNumber (100 lines)
+     * @checkstyle FinalParameters (100 lines)
+     */
+    static final class Student {
+
+        private String firstName;
+        private String lastName;
+        private int age;
+        private double gpa;
+        private Map<String, Integer> grades = new LinkedHashMap<>();
+
+        Student(
+            String firstName, String lastName,
+            int age, double gpa
+        ) {
+            this.firstName = firstName;
+            this.lastName = lastName;
+            this.age = age;
+            this.gpa = gpa;
+            this.grades.put("Math", 9);
+            this.grades.put("CS", 10);
+        }
+
+        public String getFirstName() {
+            return this.firstName;
+        }
+        public void setFirstName(String firstName) {
+            this.firstName = firstName;
+        }
+        public String getLastName() {
+            return this.lastName;
+        }
+        public void setLastName(String lastName) {
+            this.lastName = lastName;
+        }
+        public int getAge() {
+            return this.age;
+        }
+        public void setAge(int age) {
+            this.age = age;
+        }
+        public double getGpa() {
+            return this.gpa;
+        }
+        public void setGpa(double gpa) {
+            this.gpa = gpa;
+        }
+
+        public Map<String, Integer> getGrades() {
+            return this.grades;
+        }
+
+        public void setGrades(Map<String, Integer> grades) {
+            this.grades = grades;
+        }
+
+    }
+}
diff --git a/src/test/java/com/amihaiemil/eoyaml/ReflectedYamlScalarTest.java b/src/test/java/com/amihaiemil/eoyaml/ReflectedYamlScalarTest.java
new file mode 100644
index 0000000..c382b40
--- /dev/null
+++ b/src/test/java/com/amihaiemil/eoyaml/ReflectedYamlScalarTest.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) 2016-2020, Mihai Emil Andronache
+ * All rights reserved.
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+package com.amihaiemil.eoyaml;
+
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link ReflectedYamlScalar}.
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 4.3.3
+ */
+public final class ReflectedYamlScalarTest {
+
+    /**
+     * A reflected scalar has no comment.
+     */
+    @Test
+    public void returnsEmptyComment() {
+        final Scalar scalar = new ReflectedYamlScalar("scalar");
+        MatcherAssert.assertThat(
+            scalar.comment().yamlNode(),
+            Matchers.is(scalar)
+        );
+        MatcherAssert.assertThat(
+            scalar.comment().value(),
+            Matchers.isEmptyString()
+        );
+    }
+
+    /**
+     * It can represent different scalar objects.
+     */
+    @Test
+    public void reflectsDifferentScalarObjects() {
+        MatcherAssert.assertThat(
+            new ReflectedYamlScalar("scalar").value(),
+            Matchers.equalTo("scalar")
+        );
+        MatcherAssert.assertThat(
+            new ReflectedYamlScalar(233).value(),
+            Matchers.equalTo("233")
+        );
+        MatcherAssert.assertThat(
+            new ReflectedYamlScalar(10.5).value(),
+            Matchers.equalTo("10.5")
+        );
+        MatcherAssert.assertThat(
+            new ReflectedYamlScalar(10.34F).value(),
+            Matchers.equalTo("10.34")
+        );
+    }
+
+    /**
+     * The scalar's value is null if the passed object is null.
+     */
+    @Test
+    public void reflectsNull() {
+        MatcherAssert.assertThat(
+            new ReflectedYamlScalar(null).value(),
+            Matchers.nullValue()
+        );
+    }
+}
diff --git a/src/test/java/com/amihaiemil/eoyaml/ReflectedYamlSequenceTest.java b/src/test/java/com/amihaiemil/eoyaml/ReflectedYamlSequenceTest.java
new file mode 100644
index 0000000..d79a9da
--- /dev/null
+++ b/src/test/java/com/amihaiemil/eoyaml/ReflectedYamlSequenceTest.java
@@ -0,0 +1,181 @@
+/**
+ * Copyright (c) 2016-2020, Mihai Emil Andronache
+ * All rights reserved.
+ * <p>
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+package com.amihaiemil.eoyaml;
+
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.*;
+
+/**
+ * Unit tests for {@link ReflectedYamlSequence}.
+ * @author Mihai Andronache (amihaiemil@gmail.com)
+ * @version $Id$
+ * @since 4.3.3
+ */
+public final class ReflectedYamlSequenceTest {
+
+    /**
+     * A reflected sequence has no comment.
+     */
+    @Test
+    public void returnsEmptyComment() {
+        final YamlSequence sequence = new ReflectedYamlSequence(
+            new ArrayList<String>()
+        );
+        MatcherAssert.assertThat(
+            sequence.comment().yamlNode(),
+            Matchers.is(sequence)
+        );
+        MatcherAssert.assertThat(
+            sequence.comment().value(),
+            Matchers.isEmptyString()
+        );
+    }
+
+    /**
+     * A reflected YamlSequence can be created from a Collection.
+     */
+    @Test
+    public void instantiatesWithCollection() {
+        new ReflectedYamlSequence(new ArrayList<>());
+        new ReflectedYamlSequence(new LinkedList<>());
+        new ReflectedYamlSequence(new HashSet<>());
+        new ReflectedYamlSequence(new LinkedHashSet<>());
+        new ReflectedYamlSequence(Mockito.mock(Collection.class));
+    }
+
+    /**
+     * A reflected YamlSequence can be created from an Array.
+     */
+    @Test
+    public void instantiatesWithArray() {
+        new ReflectedYamlSequence(new String[] {"one", "two", "three"});
+        new ReflectedYamlSequence(new Object[] {});
+        new ReflectedYamlSequence(new Integer[] {});
+        new ReflectedYamlSequence(new Double[] {});
+    }
+
+    /**
+     * ReflectedYamlSequence can reflect String scalars from an array.
+     */
+    @Test
+    public void reflectsStringArray() {
+        final YamlSequence sequence = new ReflectedYamlSequence(
+            new String[] {"one", "two", "three"}
+        );
+        MatcherAssert.assertThat(sequence, Matchers.iterableWithSize(3));
+        final Iterator<YamlNode> valuesIt = sequence.values().iterator();
+        MatcherAssert.assertThat(
+            ((ReflectedYamlScalar) valuesIt.next()).value(),
+            Matchers.equalTo("one")
+        );
+        MatcherAssert.assertThat(
+            ((ReflectedYamlScalar) valuesIt.next()).value(),
+            Matchers.equalTo("two")
+        );
+        MatcherAssert.assertThat(
+            ((ReflectedYamlScalar) valuesIt.next()).value(),
+            Matchers.equalTo("three")
+        );
+    }
+
+    /**
+     * ReflectedYamlSequence can reflect String scalars from a collection.
+     */
+    @Test
+    public void reflectsStringCollection() {
+        final YamlSequence sequence = new ReflectedYamlSequence(
+            Arrays.asList("one", "two", "three")
+        );
+        MatcherAssert.assertThat(sequence, Matchers.iterableWithSize(3));
+        final Iterator<YamlNode> valuesIt = sequence.values().iterator();
+        MatcherAssert.assertThat(
+            ((ReflectedYamlScalar) valuesIt.next()).value(),
+            Matchers.equalTo("one")
+        );
+        MatcherAssert.assertThat(
+            ((ReflectedYamlScalar) valuesIt.next()).value(),
+            Matchers.equalTo("two")
+        );
+        MatcherAssert.assertThat(
+            ((ReflectedYamlScalar) valuesIt.next()).value(),
+            Matchers.equalTo("three")
+        );
+    }
+
+    /**
+     * ReflectedYamlSequence can reflect Integer scalars from an array.
+     */
+    @Test
+    public void reflectsIntegerArray() {
+        final YamlSequence sequence = new ReflectedYamlSequence(
+            new Integer[] {1, 2, 3}
+        );
+        MatcherAssert.assertThat(sequence, Matchers.iterableWithSize(3));
+        final Iterator<YamlNode> valuesIt = sequence.values().iterator();
+        MatcherAssert.assertThat(
+            ((ReflectedYamlScalar) valuesIt.next()).value(),
+            Matchers.equalTo("1")
+        );
+        MatcherAssert.assertThat(
+            ((ReflectedYamlScalar) valuesIt.next()).value(),
+            Matchers.equalTo("2")
+        );
+        MatcherAssert.assertThat(
+            ((ReflectedYamlScalar) valuesIt.next()).value(),
+            Matchers.equalTo("3")
+        );
+    }
+
+    /**
+     * ReflectedYamlSequence can reflect Integer scalars from a collection.
+     */
+    @Test
+    public void reflectsIntegerCollection() {
+        final YamlSequence sequence = new ReflectedYamlSequence(
+            Arrays.asList(1, 2, 3)
+        );
+        MatcherAssert.assertThat(sequence, Matchers.iterableWithSize(3));
+        final Iterator<YamlNode> valuesIt = sequence.values().iterator();
+        MatcherAssert.assertThat(
+            ((ReflectedYamlScalar) valuesIt.next()).value(),
+            Matchers.equalTo("1")
+        );
+        MatcherAssert.assertThat(
+            ((ReflectedYamlScalar) valuesIt.next()).value(),
+            Matchers.equalTo("2")
+        );
+        MatcherAssert.assertThat(
+            ((ReflectedYamlScalar) valuesIt.next()).value(),
+            Matchers.equalTo("3")
+        );
+    }
+}