ソースを参照

#37 javadoc: reflection.walker

Ranides Atterwim 3 年 前
コミット
f685261846

+ 1 - 1
assira.core/src/main/java/net/ranides/assira/reflection/util/MethodUtils.java

@@ -30,7 +30,7 @@ public final class MethodUtils {
      *
      * @param candidate candidate
      * @param original original
-     * @return 
+     * @return boolean
      */
     public static boolean overrides(Method original, Method candidate) {
         if( !original.getName().equals(candidate.getName()) ) {

+ 16 - 10
assira.core/src/main/java/net/ranides/assira/reflection/util/ReflectUtils.java

@@ -165,11 +165,15 @@ public final class ReflectUtils {
     }
 
     /**
-     * Zwraca lokalizację, w której został wyszukany odpowiedni plik .class z
-     * definicją załadowanej klasy. Lokalizacja nie wskazuje na  konkretny
-     * plik .class, aby uzyskać pełną ścieżkę, należy uzyć metody {@link #getFQLocation}
-     * @param clazz
-     * @return
+     * Returns location used to find ".class" file used to load provided class.
+     *
+     * Please note, that it does not return path to ".class" file, but path to
+     * directory/JAR used for classpath search.
+     *
+     * If you want to obtain specific ".class" file, you should use getFQLocation
+     *
+     * @param clazz clazz
+     * @return Path
      */
     public static Path getLocation(Class<?> clazz) {
         CodeSource cs = clazz.getProtectionDomain().getCodeSource();
@@ -180,11 +184,13 @@ public final class ReflectUtils {
     }
 
     /**
-     * Zwraca ścieżkę do pliku .class, z którego została załadowana klasa. Aby
-     * uzyskać lokalizację, w której rozpoczęto wyszukiwanie pliku .class, należy
-     * użyć metody {@link #getLocation}
-     * @param clazz
-     * @return
+     * Returns location to ".class" file used to load provided class.
+     *
+     * Please note, that it does not return classpath.
+     * If you want to obtain directory used to search for a ".class" file, you should use getLocation
+     *
+     * @param clazz clazz
+     * @return Path
      */
     public static Path getFQLocation(Class<?> clazz) {
         ClassLoader cr = clazz.getClassLoader();

+ 82 - 1
assira.core/src/main/java/net/ranides/assira/reflection/walker/ObjectVisitor.java

@@ -8,20 +8,77 @@ import java.util.Map;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
+/**
+ * This visitor is interface used by ObjectWalker.
+ *
+ * ObjectWalker executes different "visit" objects for different field types.
+ * Every visit method can inform walker if it should continue inspection recursively.
+ * If method returns false, then recursive inspection is not continued for this field.
+ *
+ * ObjectVisitor receives information about visited field in the form of ObjectContext.
+ * Specialized methods (for example arrays, collections, lists) receive a bit more detailed subclasses
+ * with additional context information (for example collection size)
+ *
+ * ObjectVisitor stores custom properties accessible from every context: it is prototype for every scope.
+ * Especially, those custom properties can be used by custom visitors executed from "visit..." methods.
+ */
 public interface ObjectVisitor {
 
+    /**
+     * Returns ResolveContext which is used as parent scope by every ObjectContext.
+     * In other words: returns custom global properties shared during inspection time.
+     *
+     * @return ResolveContext
+     */
     ResolveContext scope();
 
+    /**
+     * Method executed for "singular" fields, that means: not collections, arrays, or maps.
+     * Some implementations of ObjectVisitor call this method in other, more specific cases too, as default handler.
+     *
+     * @param ctx ctx
+     * @return true if should be visited recursively
+     */
     boolean visitObject(ObjectContext<?> ctx);
 
+    /**
+     * Method executed for fields which are array.
+     *
+     * @param ctx ctx
+     * @return true if should be visited recursively
+     */
     boolean visitArray(WalkerContexts.ArrayContext<?> ctx);
 
+    /**
+     * Method executed for fields which are collection.
+     *
+     * @param ctx ctx
+     * @return true if should be visited recursively
+     */
     boolean visitCollection(WalkerContexts.CollectionContext<?> ctx);
 
+    /**
+     * Method executed for fields which are list.
+     *
+     * @param ctx ctx
+     * @return true if should be visited recursively
+     */
     boolean visitList(WalkerContexts.ListContext<?> ctx);
 
+    /**
+     * Method executed for fields which are maps.
+     *
+     * @param ctx ctx
+     * @return true if should be visited recursively
+     */
     boolean visitMap(WalkerContexts.MapContext<?> ctx);
 
+    /**
+     * Creates SimpleVisitor which calls predicate for every field.
+     *
+     * @param predicate predicate
+     * @return ObjectVisitor
+     */
     static ObjectVisitor of(Predicate<ObjectContext<?>> predicate) {
         return new SimpleVisitor() {
             @Override
@@ -31,6 +88,11 @@ public interface ObjectVisitor {
         };
     }
 
+    /**
+     * Basic ObjectVisitor implementation which delegates all work to "visitObject".
+     *
+     * It does not support custom properties, it returns just empty, immutable ResolveContext.
+     */
     abstract class SimpleVisitor implements ObjectVisitor {
 
         @Override
@@ -63,6 +125,11 @@ public interface ObjectVisitor {
 
     }
 
+    /**
+     * Basic ObjectVisitor implementation which delegates all work to "visitObject".
+     *
+     * It supports custom properties, it stores them inside provided PrototypeMap.
+     */
     abstract class AbstractVisitor implements ObjectVisitor {
         private final PrototypeMap scope;
 
@@ -99,6 +166,14 @@ public interface ObjectVisitor {
         }
     }
 
+    /**
+     * Basic ObjectVisitor implementation which delegates all work to provided "visitObject".
+     *
+     * It supports custom properties, it stores them inside provided PrototypeMap.
+     *
+     * It stores additionally provided "consumer".
+     * It is responsibility of implementor to call this "consumer" and/or decide if scan field recursively.
+     */
     abstract class ConsumeVisitor<T> extends AbstractVisitor {
         private final Consumer<T> target;
 
@@ -107,7 +182,13 @@ public interface ObjectVisitor {
             this.target = target;
         }
 
-        public void accept(T value) {
+        /**
+         * This method should be called by "visitObject" implementation.
+         * Provided field value will be processed by consumer defined at construction time.
+         *
+         * @param value value
+         */
+        public final void accept(T value) {
             target.accept(value);
         }
 

+ 62 - 1
assira.core/src/main/java/net/ranides/assira/reflection/walker/ObjectWalker.java

@@ -16,6 +16,16 @@ import java.util.*;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 
+/**
+ * ObjectWalker is a class for deep inspection of objects.
+ * It implements listing all fields, optionally recursively.
+ *
+ * ObjectWalker takes ObjectVisitor as input. This visitor has more than one method
+ * and implement separate behaviour for pure objects, arrays, lists and maps.
+ *
+ * Every visited field is represented as ObjectContext. This contenxt contains information
+ * about type, values, enclosing object etc.
+ */
 public class ObjectWalker {
 
     private final Map<Object, Long> visited = new IdentityHashMap<>();
@@ -31,18 +41,64 @@ public class ObjectWalker {
         this.visitor = visitor;
     }
 
+    /**
+     * Inspects all fields inside input.
+     * Every visited field is passed to "visitor" as ObjectContext.
+     *
+     * If visitor returns "true", then visited field is inspected recursively.
+     *
+     * @param input input
+     * @param visitor visitor
+     */
     public static void walk(Object input, Predicate<ObjectContext<?>> visitor) {
         walk(input, "var", visitor);
     }
 
+    /**
+     * Inspects all fields inside input.
+     * Every visited field is passed to "visitor" as ObjectContext.
+     *
+     * If visitor returns "true", then visited field is inspected recursively.
+     *
+     * Please note that ObjectVisitor must implement ResolveContext interface.
+     * This context stores public properties accessible from every ObjectContext (using PrototypeMap).
+     *
+     * @param input input
+     * @param visitor visitor
+     */
     public static void walk(Object input, ObjectVisitor visitor) {
         walk(input, "var", visitor);
     }
 
+    /**
+     * Inspects all fields inside input.
+     * Every visited field is passed to "visitor" as ObjectContext.
+     * String "root" is used when asking context for e.g. "namePath"
+     *
+     * If visitor returns "true", then visited field is inspected recursively.
+     *
+     * @param input input
+     * @param root root
+     * @param visitor visitor
+     */
     public static void walk(Object input, String root, Predicate<ObjectContext<?>> visitor) {
         walk(input, root, ObjectVisitor.of(visitor));
     }
 
+    /**
+     * Inspects all fields inside input.
+     * Every visited field is passed to "visitor" as ObjectContext.
+     * String "root" is used when asking context for e.g. "namePath"
+     *
+     * If visitor returns "true", then visited field is inspected recursively.
+     *
+     * Please note that ObjectVisitor must implement ResolveContext interface.
+     * This context stores public properties accessible from every ObjectContext (using PrototypeMap).
+     *
+     * @param input input
+     * @param root root
+     * @param visitor visitor
+     */
     public static void walk(Object input, String root, ObjectVisitor visitor) {
         new ObjectWalker(input, visitor).start(root);
     }
@@ -263,7 +319,7 @@ public class ObjectWalker {
 
         @Override
         public boolean isDefined() {
-            return value == WalkerUtils.UNDEFINED;
+            return value != WalkerUtils.UNDEFINED;
         }
 
         @Override
@@ -426,6 +482,11 @@ public class ObjectWalker {
             return value().get(index);
         }
 
+        @Override
+        public Iterator<?> iterator() {
+            return value().iterator();
+        }
+
         @Override
         public void accept(ObjectVisitor visitor) {
             try {

+ 300 - 0
assira.core/src/main/java/net/ranides/assira/reflection/walker/WalkerContexts.java

@@ -9,118 +9,418 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+/**
+ * ResolveContext interfaces.
+ *
+ */
 public class WalkerContexts {
 
+    /**
+     * Base interface describing visited field.
+     * It stores information both declared and actual type, value and others.
+     *
+     * ObjectContext implements ResolveContext and stores custom properties.
+     * Additionaly, every context should use data from visitor as prototype.
+     *
+     * If you use ResolveFormat or ResolvePattern, you can use those custom properties.
+     *
+     * Please note that custom properties have higher priority than methods declared by ObjectContext.
+     * For example you can put value under "name" key, and then this value will be returned instead of calling method.
+     *
+     * @param <T> T
+     */
     public interface ObjectContext<T> extends ResolveContext {
 
+        /**
+         * IClass representing this interface.
+         * This value is returned as "kind" by every ObjectContext implementation.
+         */
         IClass<ObjectContext<?>> KIND = new TypeToken<ObjectContext<?>>() {};
 
+        /**
+         * This method executes provided visitor.
+         * Marks field value as "visited" to break cyclic references.
+         *
+         * It continues recursive scan, if visitor returned "true"
+         *
+         * @param visitor visitor
+         */
         void accept(ObjectVisitor visitor);
 
+        /**
+         * Returns description of enclosing object.
+         *
+         * @return ObjectContext
+         */
         ObjectContext<?> parent();
 
+        /**
+         * Returns short name for declared type of object
+         *
+         * @return String
+         */
         String typeName();
 
+        /**
+         * Returns declared name of field
+         *
+         * @return String
+         */
         String name();
 
+        /**
+         * Returns declared type of field
+         *
+         * @return IClass
+         */
         IClass<? extends T> type();
 
+        /**
+         * Returns actual type of field.
+         * Please note, that actual type can have more details about subclasses,
+         * but less information about generic parameters.
+         *
+         * @return IClass
+         */
         IClass<? extends T> actual();
 
+        /**
+         * Returns actual value of field
+         *
+         * @return Object
+         */
         T value();
 
+        /**
+         * Returns synthetic id of field.
+         * Every visited field receives "id" auto-generated by walker.
+         *
+         * @return long
+         */
         long id();
 
+        /**
+         * Returns synthetic id of value.
+         * Every visited non-primitive value receives "id" auto-generated by walker.
+         *
+         * "ref" can be used to avoid cycles. If two different fields have identical value,
+         * their ids will be the different, but refs will be the same.
+         *
+         * @return long
+         */
         long ref();
 
+        /**
+         * Returns depth of recursive scan
+         *
+         * @return int
+         */
         int depth();
 
+        /**
+         * Returns slash separated list of declared type and all enclosing types.
+         *
+         * @return string
+         */
         String typePath();
 
+        /**
+         * Returns list of declared type and all enclosing types.
+         * Type of root object is first, current type is last.
+         *
+         * @return list
+         */
         List<IClass<?>> typeList();
 
+        /**
+         * Returns slash separated list of field name all enclosing fields.
+         *
+         * @return string
+         */
         String namePath();
 
+        /**
+         * Returns list of field name all enclosing fields.
+         *
+         * @return list
+         */
         List<String> nameList();
 
+        /**
+         * Returns dot separated list of field id all enclosing fields.
+         *
+         * @return string
+         */
         String idPath();
 
+        /**
+         * Returns true if this context represents root object, passed to ObjectWalker.
+         *
+         * @return boolean
+         */
         boolean isRoot();
 
+        /**
+         * Returns true if this context represents field.
+         * Some scanned values are not real fields: for example map entries.
+         *
+         * @return boolean
+         */
         boolean isField();
 
+        /**
+         * Returns true if this context represents field and it is transient.
+         *
+         * @return boolean
+         */
         boolean isTransient();
 
+        /**
+         * Returns true if this context contains value which was already visited.
+         *
+         * @return boolean
+         */
         boolean isVisited();
 
+        /**
+         * Returns true if this context contains readable value
+         *
+         * @return boolean
+         */
         boolean isDefined();
 
+        /**
+         * Returns true if this context contains primitive value
+         *
+         * @return boolean
+         */
         boolean isPrimitive();
 
+        /**
+         * Returns true if this context contains null value
+         *
+         * @return boolean
+         */
         boolean isNull();
 
+        /**
+         * Returns true if this context contains actual value more specific than declared
+         *
+         * @return boolean
+         */
         boolean isSubclass();
 
+        /**
+         * Returns true if this context contains actual value of provided type
+         *
+         * @param type type
+         * @return boolean
+         */
         boolean isSubclass(IClass<?> type);
 
+        /**
+         * Returns interface implemented by context.
+         *
+         * It is similar to this.getClass() but it does not return specific implementation.
+         * It returns just one of interface declared inside WalkerContexts.
+         *
+         * @return type
+         */
         IClass<? extends ObjectContext<?>> kind();
 
+        /**
+         * Creates new nested context for field found inside this object.
+         *
+         * @param field field
+         * @return context
+         */
         ObjectContext<?> context(IField field);
 
+        /**
+         * Creates new nested context for value found inside this object.
+         * It shouldn't be field, for example it could be collection item.
+         *
+         * @param name name
+         * @param declared declared
+         * @param value value
+         * @param <S> S
+         * @return context
+         */
         <S> ObjectContext<S> context(String name, IClass<S> declared, Object value);
 
+        /**
+         * Inserts provided value into custom properties associated with this context.
+         *
+         * @param values values
+         */
         void custom(Map<String, ?> values);
 
+        /**
+         * Inserts provided value into custom properties associated with this context.
+         *
+         * @param key key
+         * @param value value
+         */
         void custom(String key, Object value);
 
     }
 
+    /**
+     * Specialized context describing arrays.
+     *
+     * @param <T> T
+     */
     public interface ArrayContext<T> extends ObjectContext<T> {
 
+        /**
+         * IClass representing this interface.
+         * This value is returned as "kind" by every ArrayContext implementation.
+         */
         IClass<ArrayContext<?>> KIND = new TypeToken<ArrayContext<?>>() {};
 
+        /**
+         * Returns declared component type of array
+         *
+         * @return type
+         */
         IClass<?> component();
 
+        /**
+         * Returns size of array
+         *
+         * @return int
+         */
         int size();
 
+        /**
+         * Returns array element at specified index
+         *
+         * @param index index
+         * @return Object
+         */
         Object at(int index);
 
     }
 
+    /**
+     * Specialized context describing List
+     *
+     * @param <T> T
+     */
     public interface ListContext<T extends List<?>> extends ObjectContext<T> {
 
+        /**
+         * IClass representing this interface.
+         * This value is returned as "kind" by every ListContext implementation.
+         */
         IClass<ListContext<?>> KIND = new TypeToken<ListContext<?>>() {};
 
+        /**
+         * Returns declared component type of list
+         *
+         * @return type
+         */
         IClass<?> component();
 
+        /**
+         * Returns size of list
+         *
+         * @return int
+         */
         int size();
 
+        /**
+         * Returns list element at specified index
+         *
+         * @param index index
+         * @return Object
+         */
         Object at(int index);
 
+        /**
+         * Returns iterator with elements contained inside list
+         *
+         * @return iterator
+         */
+        Iterator<?> iterator();
     }
 
+    /**
+     * Specialized context describing Collection
+     * It is similar to List, but does not support random access.
+     *
+     * @param <T> T
+     */
     public interface CollectionContext<T extends Collection<?>> extends ObjectContext<T> {
 
+        /**
+         * IClass representing this interface.
+         * This value is returned as "kind" by every CollectionContext implementation.
+         */
         IClass<CollectionContext<?>> KIND = new TypeToken<CollectionContext<?>>() {};
 
+        /**
+         * Returns declared component type of collection
+         *
+         * @return type
+         */
         IClass<?> component();
 
+        /**
+         * Returns size of collection
+         *
+         * @return int
+         */
         int size();
 
+        /**
+         * Returns iterator with elements contained inside collection
+         *
+         * @return iterator
+         */
         Iterator<?> iterator();
 
     }
 
+    /**
+     * Specialized context describing Map
+     *
+     * @param <T> T
+     */
     public interface MapContext<T extends Map<?,?>> extends ObjectContext<T> {
 
+        /**
+         * IClass representing this interface.
+         * This value is returned as "kind" by every MapContext implementation.
+         */
         IClass<MapContext<?>> KIND = new TypeToken<MapContext<?>>() {};
 
+        /**
+         * Returns declared key type of map
+         *
+         * @return type
+         */
         IClass<?> keyComponent();
 
+        /**
+         * Returns declared value type of map
+         *
+         * @return type
+         */
         IClass<?> valueComponent();
 
+        /**
+         * Returns size of map
+         *
+         * @return int
+         */
         int size();
 
+        /**
+         * Returns set of entries contained inside map
+         *
+         * @return set
+         */
         Set<? extends Map.Entry<?, ?>> entries();
 
     }

+ 55 - 0
assira.core/src/main/java/net/ranides/assira/reflection/walker/WalkerRules.java

@@ -1,5 +1,6 @@
 package net.ranides.assira.reflection.walker;
 
+import lombok.experimental.UtilityClass;
 import net.ranides.assira.reflection.IClass;
 import net.ranides.assira.reflection.walker.WalkerContexts.ArrayContext;
 import net.ranides.assira.reflection.walker.WalkerContexts.ObjectContext;
@@ -11,8 +12,18 @@ import javax.xml.datatype.XMLGregorianCalendar;
 import java.time.temporal.Temporal;
 import java.util.*;
 
+/**
+ * This utility class contains default rules for ObjectWalker.
+ *
+ * WalkerRules represent configuration which can be used to create specific ObjectVisitor
+ * just before inspection.
+ */
+@UtilityClass
 public class WalkerRules {
 
+    /**
+     * Default set of rules, which can be used to create printing ObjectVisitor.
+     */
     public static final PrintRules PRINTER = new PrintRules.Builder()
         .tag("PATH", "{id,text,4}.{namePath,text,-50}")
         .rule()
@@ -56,6 +67,9 @@ public class WalkerRules {
             .hint("{PATH} {actual.shortName} = {value}")
         .prepare();
 
+    /**
+     * Default set of rules, which can be used to create collecting ObjectVisitor.
+     */
     public static final CollectRules<WalkerEntry> COLLECT = new CollectRules.Builder<WalkerEntry>()
             .rule()
                 .match(ObjectContext::isVisited)
@@ -86,32 +100,73 @@ public class WalkerRules {
                 .follow(WalkerEntry::new)
             .prepare();
 
+    /**
+     * Returns new builder for custom PrintRules
+     *
+     * @return builder
+     */
     public static PrintRules.Builder printer() {
         return new PrintRules.Builder();
     }
 
+    /**
+     * Returns new builder for custom CollectRules
+     *
+     * @return builder
+     */
     public static CollectRules.Builder<WalkerEntry> collectEntries() {
         return new CollectRules.Builder<>();
     }
 
+    /**
+     * Returns new builder for custom CollectRules
+     *
+     * @return builder
+     */
     public static CollectRules.Builder<String> collectLines() {
         return new CollectRules.Builder<>();
     }
 
+    /**
+     * Returns new builder for custom CollectRules
+     *
+     * @param type type
+     * @param <T> T
+     * @return builder
+     */
     public static <T> CollectRules.Builder<T> collect(Class<T> type) {
         return new CollectRules.Builder<>();
     }
 
+    /**
+     * Returns new builder for custom CollectRules
+     *
+     * @param type type
+     * @param <T> T
+     * @return builder
+     */
     public static <T> CollectRules.Builder<T> collect(IClass<T> type) {
         return new CollectRules.Builder<>();
     }
 
+    /**
+     * It is simplified representation of ObjectContext.
+     * It is just key-value pair, which could be stored inside map.
+     *
+     * Visitor generated by CollectRules stores entries of this class by default.
+     */
     public static class WalkerEntry implements Map.Entry<String, Object> {
 
         private final long ref;
         private final String path;
         private final Object value;
 
+        /**
+         * Creates new entry from provided context.
+         * Effectively it is simplified snapshot of the context.
+         *
+         * @param ctx ctx
+         */
         public WalkerEntry(ObjectContext<?> ctx) {
             this.ref = ctx.ref();
             this.path = ctx.namePath();

+ 8 - 0
assira.core/src/main/java/net/ranides/assira/reflection/walker/WalkerUtils.java

@@ -1,5 +1,6 @@
 package net.ranides.assira.reflection.walker;
 
+import lombok.experimental.UtilityClass;
 import net.ranides.assira.collection.lists.ReversedList;
 import net.ranides.assira.generic.TypeToken;
 import net.ranides.assira.reflection.IClass;
@@ -8,6 +9,10 @@ import net.ranides.assira.reflection.walker.WalkerContexts.ObjectContext;
 import java.util.*;
 import java.util.function.Function;
 
+/**
+ * This is internal class containing utility methods
+ */
+@UtilityClass
 class WalkerUtils {
 
     public static final Undefined UNDEFINED = new Undefined();
@@ -96,6 +101,9 @@ class WalkerUtils {
         return new ReversedList<>(names);
     }
 
+    /**
+     * Internal class used as sentinel value for innacessible fields
+     */
     public static class Undefined {
         @Override
         public String toString() {

+ 26 - 0
assira.core/src/main/java/net/ranides/assira/reflection/walker/rules/CollectRules.java

@@ -10,6 +10,12 @@ import java.util.*;
 import java.util.function.*;
 import java.util.regex.Pattern;
 
+/**
+ * CollectRules is configuration used to construct "collecting" ObjectVisitor.
+ * Collectors by default use WalkerEntry, but can use any target type.
+ *
+ * @param <T> type
+ */
 public class CollectRules<T> {
 
     protected final Map<Object, Object> tags;
@@ -25,19 +31,39 @@ public class CollectRules<T> {
         this.rules = new ArrayList<>(rules);
     }
 
+    /**
+     * Creates new visitor inserting results into target collection.
+     *
+     * @param target target
+     * @return visitor
+     */
     public ObjectVisitor visitor(Collection<T> target) {
         return new ConsumeRuleVisitor(target::add);
     }
 
+    /**
+     * Creates new visitor passing results into consumer.
+     *
+     * @param consumer consumer
+     * @return visitor
+     */
     public ObjectVisitor visitor(Consumer<T> consumer) {
         return new ConsumeRuleVisitor(consumer);
     }
 
+    /**
+     * This fluent builder allows to construct new collecting configuration
+     */
     public static class Builder<T> {
 
         private final Map<Object, Object> tags = new HashMap<>();
         private final List<RuleEntry<T>> rules = new ArrayList<>();
 
+        /**
+         * Creates immutable CollectRules
+         *
+         * @return CollectRules
+         */
         public CollectRules<T> prepare() {
             return new CollectRules<>(tags, rules);
         }

+ 24 - 0
assira.core/src/main/java/net/ranides/assira/reflection/walker/rules/PrintRules.java

@@ -15,6 +15,9 @@ import java.io.PrintWriter;
 import java.io.Writer;
 import java.util.function.*;
 
+/**
+ * PrintRules is configuration used to construct "printing" ObjectVisitor.
+ */
 public class PrintRules {
 
     private final CollectRules<String> rules;
@@ -23,18 +26,39 @@ public class PrintRules {
         this.rules = new CollectRules<>(rules);
     }
 
+    /**
+     * Creates new visitor printing results into target OutputStream.
+     * It uses UTF8 charset.
+     *
+     * @param target target
+     * @return visitor
+     */
     public ObjectVisitor visitor(OutputStream target) {
         return visitor(new OutputStreamWriter(target, Charsets.UTF8));
     }
 
+    /**
+     * Creates new visitor printing results into target Writer
+     *
+     * @param target target
+     * @return visitor
+     */
     public ObjectVisitor visitor(Writer target) {
         return rules.visitor(new PrintWriter(target)::println);
     }
 
+    /**
+     * This fluent builder allows to construct new printing configuration
+     */
     public static class Builder {
 
         private final CollectRules.Builder<String> builder = new CollectRules.Builder<>();
 
+        /**
+         * Creates immutable PrintRules
+         *
+         * @return PrintRules
+         */
         public PrintRules prepare() {
             return new PrintRules(builder.prepare());
         }