Przeglądaj źródła

#37 javadoc: generic

Ranides Atterwim 4 lat temu
rodzic
commit
a0f040083f

+ 157 - 15
assira.core/src/main/java/net/ranides/assira/generic/DynamicInvoker.java

@@ -15,7 +15,7 @@ import java.util.function.Function;
  * It should select best matching overload of method.
  * Optionally, class offers double-dispatch, basing on argument and return type.
  *
- * It can be used to implement rather sophisticated casting.
+ * It can be used for example to implement sophisticated casting.
  */
 public class DynamicInvoker {
 
@@ -26,33 +26,81 @@ public class DynamicInvoker {
     private final boolean passIdent;
 
     private DynamicInvoker(Builder src) {
-        this.list = src.list;
+        this.list = src.map.toList();
         this.passNull = src.passNull;
         this.passIdent = src.passIdent;
     }
 
+    /**
+     * Every invoker must be constructed using builder, before use.
+     * You can create new instance using "new"
+     *
+     * @return builder
+     */
     public static Builder builder() {
         return new Builder();
     }
 
+    /**
+     * Executes best matching method for provided argument.
+     * Best match means accepting most specific type compatible with value.
+     *
+     * @param value value
+     * @return result
+     */
     public Object call(Object value) {
-        Function<Object, Object> func = match(value)
-            .orElseThrow(() -> new IllegalArgumentException("No method found for: " + IClass.typefor(value)));
-        return func.apply(value);
+        return match(value)
+            .orElseThrow(() -> new IllegalArgumentException("No method found for: " + IClass.typefor(value)))
+            .apply(value);
     }
 
+    /**
+     * Executes best matching method for provided argument.
+     * Best match means accepting most specific type compatible with value
+     * and returning type compatible with expected result.
+     *
+     * Strictly speaking:
+     * argument is used to find closest match, but result is used to filter out invalid return types.
+     *
+     * @param returns returns
+     * @param value value
+     * @param <T> T
+     * @param <R> R
+     * @return result
+     */
     public <T,R> R call(Class<R> returns, T value) {
-        Function<T, R> func = match(returns, value)
-            .orElseThrow(() -> new IllegalArgumentException("No method found for: " + IClass.typefor(value) + " =>" + ClassUtils.box(returns)));
-        return func.apply(value);
+        return match(returns, value)
+            .orElseThrow(() -> new IllegalArgumentException("No method found for: " + IClass.typefor(value) + " =>" + ClassUtils.box(returns)))
+            .apply(value);
     }
 
+    /**
+     * Executes best matching method for provided argument.
+     * Best match means accepting most specific type compatible with value
+     * and returning type compatible with expected result.
+     *
+     * Strictly speaking:
+     * argument is used to find closest match, but result is used to filter out invalid return types.
+     *
+     * @param returns returns
+     * @param value value
+     * @param <T> T
+     * @param <R> R
+     * @return result
+     */
     public <T,R> R call(IClass<R> returns, T value) {
-        Function<T, R> func = match(returns, value)
-            .orElseThrow(() -> new IllegalArgumentException("No method found for: " + IClass.typefor(value) + " => " + ClassUtils.box(returns)));
-        return func.apply(value);
+        return match(returns, value)
+            .orElseThrow(() -> new IllegalArgumentException("No method found for: " + IClass.typefor(value) + " => " + ClassUtils.box(returns)))
+            .apply(value);
     }
 
+    /**
+     * Find best matching method and returns it as a "Function"
+     * Best match means accepting most specific type compatible with value.
+     *
+     * @param value value
+     * @return function
+     */
     @SuppressWarnings("unchecked")
     public Optional<Function<Object, Object>> match(Object value) {
         if(value == null && passNull) {
@@ -66,10 +114,38 @@ public class DynamicInvoker {
         return Optional.empty();
     }
 
+    /**
+     * Find best matching method and returns it as a "Function"
+     * Best match means accepting most specific type compatible with value
+     * and returning type compatible with expected result.
+     *
+     * Strictly speaking:
+     * argument is used to find closest match, but result is used to filter out invalid return types.
+     *
+     * @param returns returns
+     * @param value value
+     * @param <T> T
+     * @param <R> R
+     * @return function
+     */
     public <T, R> Optional<Function<T,R>> match(Class<R> returns, T value) {
         return match(IClass.typeinfo(returns), value);
     }
 
+    /**
+     * Find best matching method and returns it as a "Function"
+     * Best match means accepting most specific type compatible with value
+     * and returning type compatible with expected result.
+     *
+     * Strictly speaking:
+     * argument is used to find closest match, but result is used to filter out invalid return types.
+     *
+     * @param returns returns
+     * @param value value
+     * @param <T> T
+     * @param <R> R
+     * @return function
+     */
     @SuppressWarnings("unchecked")
     public <T, R> Optional<Function<T,R>> match(IClass<R> returns, T value) {
         if(value == null && passNull) {
@@ -92,38 +168,88 @@ public class DynamicInvoker {
         return Optional.empty();
     }
 
+    /**
+     * Builder pattern for DynamicInvoker
+     */
     public static final class Builder {
 
         private final TypeList<RFunction> map = new TypeList<>();
 
-        private final List<RFunction> list = new ArrayList<>();
-
         private boolean passNull = true;
 
         private boolean passIdent = true;
 
+        /**
+         * Configures invoker to return input argument without any calls, if
+         * input type and return type are the same.
+         *
+         * @param passIdent passIdent
+         * @return builder
+         */
         public Builder passIdent(boolean passIdent) {
             this.passIdent = passIdent;
             return this;
         }
 
+        /**
+         * Configures invoker to return null without any calls, if input value is "null"
+         *
+         * @param passNull passNull
+         * @return builder
+         */
         public Builder passNull(boolean passNull) {
             this.passNull = passNull;
             return this;
         }
 
+        /**
+         * Inserts provided function for specified types of input and result.
+         *
+         * @param argument argument
+         * @param returns returns
+         * @param function function
+         * @param <T> T
+         * @param <R> R
+         * @return builder
+         */
         public <T,R> Builder append(Class<T> argument, Class<R> returns, Function<T, R> function) {
             return append0(argument, IClass.typeinfo(returns), function);
         }
 
+        /**
+         * Inserts provided function for specified types of input and result.
+         *
+         * @param argument argument
+         * @param returns returns
+         * @param function function
+         * @param <T> T
+         * @param <R> R
+         * @return builder
+         */
         public <T,R> Builder append(Class<T> argument, IClass<R> returns, Function<T, R> function) {
             return append0(argument, returns, function);
         }
 
+        /**
+         * Inserts provided function for specified type of input.
+         * Type of result is assumed to be "void".
+         *
+         * @param argument argument
+         * @param consumer consumer
+         * @param <T> T
+         * @return builder
+         */
         public <T> Builder append(Class<T> argument, Consumer<T> consumer) {
             return append(argument, IClass.VOID, v -> { consumer.accept(v); return null; });
         }
 
+        /**
+         * Scans provided type for static methods annotated with "DynamicDispatch" and
+         * inserts them into invoker.
+         *
+         * @param helper helper
+         * @return builder
+         */
         public Builder appendHelper(Class<?> helper) {
             IClass.typeinfo(helper).methods()
                     .require(IAttribute.STATIC)
@@ -139,6 +265,13 @@ public class DynamicInvoker {
             return this;
         }
 
+        /**
+         * Scans provided object for non-static methods annotated with "DynamicDispatch" and
+         * inserts them into invoker. All methods will bind "this" to "delegate".
+         *
+         * @param delegate delegate
+         * @return builder
+         */
         public Builder appendDelegate(Object delegate) {
             IClass.typefor(delegate).methods()
                     .require(IAttribute.ANY)
@@ -163,8 +296,12 @@ public class DynamicInvoker {
             return this;
         }
 
+        /**
+         * Creates new configured invoker
+         *
+         * @return involer
+         */
         public DynamicInvoker build() {
-            map.toList(list);
             return new DynamicInvoker(this);
         }
 
@@ -189,8 +326,13 @@ public class DynamicInvoker {
 
         private final Node<V> root = new Node<>(null, null, null);
 
-        public void toList(List<V> target) {
+        public List<V> toList() {
+            return toList(new ArrayList<>());
+        }
+
+        public List<V> toList(List<V> target) {
             toList(target, root);
+            return target;
         }
 
         private void toList(List<V> target, Node<V> node) {

+ 85 - 14
assira.core/src/main/java/net/ranides/assira/generic/EnumUtils.java

@@ -7,9 +7,8 @@
 
 package net.ranides.assira.generic;
 
-import net.ranides.assira.collection.IntComparator;
+import lombok.experimental.UtilityClass;
 import net.ranides.assira.collection.maps.MapCollectors;
-import net.ranides.assira.collection.utils.CollectionSort;
 import net.ranides.assira.reflection.*;
 
 import java.lang.annotation.Annotation;
@@ -21,31 +20,76 @@ import java.util.function.Function;
 import java.util.function.IntFunction;
 import java.util.function.ToIntFunction;
 
-public final class EnumUtils {
-
-    private EnumUtils() {
-        // utility class
-    }
+/**
+ * Helper functions for enum values.
+ */
+@UtilityClass public class EnumUtils {
 
-    public static <K,E extends Enum<E>> Function<K, E> index(Class<E> eenum, Function<E,? extends K> function) {
+    /**
+     * Creates inverted mapping between enum valus and values assigned to each enum.
+     * Every value computed by provided "function" could be used later to quickly find "enum"
+     *
+     * Created mapping is returned as "function", not ordinary map.
+     * You could think about it as a map degenerated to "get" method.
+     *
+     * @param eenum eenum
+     * @param function function
+     * @param <K> K
+     * @param <E> E
+     * @return mapping
+     */
+    public static <K,E extends Enum<E>> Function<K, E> lookup(Class<E> eenum, Function<E,? extends K> function) {
         Map<K, E> map = Arrays.stream(eenum.getEnumConstants()).collect(MapCollectors.unique(function));
         return map::get;
     }
-    
-    public static <E extends Enum<E>> IntFunction<E> indexInt(Class<E> eenum, ToIntFunction<E> function) {
+
+    /**
+     * Creates reversed mapping between enum and value computed for each enum.
+     * Every value computed by provided "function" could be used later to quickly find "enum"
+     *
+     * Created mapping is returned as "function", not ordinary map.
+     * You could think about it as a map degenerated to "get" method.
+     *
+     * @param eenum eenum
+     * @param function function
+     * @param <E> E
+     * @return mapping
+     */
+    public static <E extends Enum<E>> IntFunction<E> lookupInt(Class<E> eenum, ToIntFunction<E> function) {
         E[] values = eenum.getEnumConstants();
         int[] keys = Arrays.stream(values).mapToInt(function).toArray();
         return key -> {
             int i = Arrays.binarySearch(keys, key);
             return i<0 ? null : values[i];
         };
+
     }
-    
-    public static <K,E extends Enum<E>> Map<E,K> apply(Class<E> eenum, Function<E,? extends K> function) {
+
+    /**
+     * Creates mapping between enum and value computed for each enum.
+     * Every value computed by provided "function" could be found later using "enum" as a key.
+     *
+     * @param eenum eenum
+     * @param function function
+     * @param <E> E
+     * @param <V> V
+     * @return immutable map
+     */
+    public static <E extends Enum<E>, V> Map<E,V> index(Class<E> eenum, Function<E,? extends V> function) {
         return Arrays.stream(eenum.getEnumConstants()).collect(MapCollectors.unique(e -> e, function::apply));
     }
-    
-    public static <K,E extends Enum<E>> Map<E,K> apply(Class<E> eenum, K[] values) {
+
+    /**
+     * Creates mapping between enum and corresponding value.
+     * Every value could be found later using "enum" as a key.
+     *
+     * @param eenum eenum
+     * @param values values
+     * @param <E> E
+     * @param <V> V
+     * @return immutable map
+     */
+    public static <E extends Enum<E>, V> Map<E,V> index(Class<E> eenum, V[] values) {
         E[] keys = eenum.getEnumConstants();
         if(keys.length != values.length) {
             throw new IllegalArgumentException("Different size of enum ("+keys.length+" and values array (" + values.length + ")");
@@ -53,10 +97,29 @@ public final class EnumUtils {
         return Arrays.stream(keys).collect(MapCollectors.unique(e -> e, e -> values[e.ordinal()]));
     }
 
+    /**
+     * Returns annotation put on provided enum value.
+     * Returns null, if enum isn't annotated.
+     *
+     * Every enum value can be annotated independently, this method allows to read those annotations.
+     *
+     * @param value value
+     * @param type type
+     * @param <A> A
+     * @return annotation
+     */
     public static <A extends Annotation> Optional<A> getAnnotation(Enum<?> value, Class<A> type) {
         return getAnnotations(value).first(type);
     }
 
+    /**
+     * Returns all annotations put on provided enum value.
+     *
+     * Every enum value can be annotated independently, this method allows to read those annotations.
+     *
+     * @param value value
+     * @return annotations
+     */
     public static IAnnotations getAnnotations(Enum<?> value) {
         return IClass.typefor(value)
             .field(value.name())
@@ -64,6 +127,14 @@ public final class EnumUtils {
             .orElse(IAnnotations.of());
     }
 
+    /**
+     * Returns all enum constants for provided type.
+     * Throws IReflectiveException if type is not enum.
+     *
+     * @param type type
+     * @param <E> enum
+     * @return list of Enum
+     */
     @SuppressWarnings("unchecked")
     public static <E extends Enum<E>> List<E> getItems(IClass<?> type) {
         if (!type.isEnum()) {

+ 43 - 6
assira.core/src/main/java/net/ranides/assira/generic/HashUtils.java

@@ -10,19 +10,22 @@ import java.math.BigInteger;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
+import java.util.List;
+
+import lombok.experimental.UtilityClass;
 import net.ranides.assira.collection.arrays.NativeArray;
 import net.ranides.assira.collection.lists.NativeArrayList;
 import net.ranides.assira.text.Charsets;
 
+/**
+ * Utility methods for calculation hashCode.
+ */
+@UtilityClass
 @SuppressWarnings({
     "PMD.AvoidReassigningParameters"
 })
-public final class HashUtils {
+public class HashUtils {
 
-    private HashUtils() {
-        // utility class
-    }
-    
     /**
      * Avalanches the bits of an integer by applying the finalisation step of
      * MurmurHash3.
@@ -69,6 +72,14 @@ public final class HashUtils {
         return x;
     }
 
+    /**
+     * Calculates hashCode for provided objects.
+     * For null values it returns 0.
+     * For arrays it uses the same algorithm as {@link List#hashCode}
+     *
+     * @param value value
+     * @return int
+     */
     public static int hash(Object value) {
         if(null == value) {
             return 0;
@@ -81,6 +92,7 @@ public final class HashUtils {
     
     /**
      * Calculates hash value compatible with code automatically generated by NetBeans IDE.
+     *
      * @param initial initial
      * @param multiplier multiplier
      * @param values values
@@ -90,6 +102,14 @@ public final class HashUtils {
         return hashIterable(initial, multiplier, Arrays.asList(values));
     }
 
+    /**
+     * It calculates hashCode for provided objects using murmurHash:
+     * for each element, ordinary hash is calculated first, then it is scrambled, then it is
+     * added to final result (using xor).
+     *
+     * @param values values
+     * @return int
+     */
     public static int murmurHashValues(Object... values) {
         int hash =0;
         for(Object v : values) {
@@ -97,7 +117,16 @@ public final class HashUtils {
         }
         return hash;
     }
-    
+
+    /**
+     * It calculates hashCode for provided pair using murmurHash:
+     * For both values, ordinary hashCode is calculated first, then it is scrambled,
+     * then values are xored to form final result
+     *
+     * @param value1 value1
+     * @param value2 value2
+     * @return int
+     */
     public static int hashPair(Object value1, Object value2) {
         int a = value1 == null ? 0 : value1.hashCode();
         int b = value2 == null ? 0 : value2.hashCode();
@@ -127,6 +156,14 @@ public final class HashUtils {
         return hash;
     }
 
+    /**
+     * It calculates hashCode for provided objects using murmurHash:
+     * for each element, ordinary hash is calculated first, then it is scrambled, then it is
+     * added to final result (using xor).
+     *
+     * @param values values
+     * @return int
+     */
     public static int murmurHashIterable(Iterable<?> values) {
         int hash =0;
         for(Object v : values) {

+ 13 - 0
assira.core/src/main/java/net/ranides/assira/generic/IdentTuple.java

@@ -6,12 +6,25 @@
  */
 package net.ranides.assira.generic;
 
+/**
+ * This class represents immutable tuple, which can be used as key in HashMap.
+ * It uses identity instead of "equals" to compare values:
+ * tuples are equal only if each corresponding object inside two tuples are identical.
+ *
+ * Because we use identity (for both equals and hashCode), tuple values could change state
+ * and it won't be noticed by IdentTuple.
+ */
 public final class IdentTuple {
 
     private final Object[] values;
 
     private final int hash;
 
+    /**
+     * Creates new tuple
+     *
+     * @param values values
+     */
     public IdentTuple(Object... values) {
         this.values = values;
         this.hash = hashCode0(values);

+ 4 - 0
assira.core/src/main/java/net/ranides/assira/generic/IntPair.java

@@ -10,6 +10,10 @@ import lombok.Data;
 
 import java.io.Serializable;
 
+/**
+ * Represents immutable pair of numbers.
+ * It implements Comparable and can be used as a key inside any Map.
+ */
 @Data(staticConstructor = "of")
 public final class IntPair implements Comparable<IntPair>, Serializable {
 

+ 94 - 3
assira.core/src/main/java/net/ranides/assira/generic/OptionalReference.java

@@ -5,26 +5,77 @@ import java.util.*;
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 
+/**
+ * It is equivalent to {@link Optional}, but implements {@link Set} interface, which means
+ * it can be used as collection with zero ore one element.
+ *
+ * It would be great to extend Optional, but unfortunatelly it is final
+ *
+ * @param <V> V
+ */
 public class OptionalReference<V> extends AbstractCollection<V> implements Set<V>, Serializable {
 
+    private static final OptionalReference<?> EMPTY = new OptionalReference<>(null);
+
     private V value;
 
     private OptionalReference(V value) {
         this.value = value;
     }
 
+    /**
+     * Returns empty optional
+     *
+     * @param <V> V
+     * @return optional
+     */
     public static <V> OptionalReference<V> empty() {
-        return new OptionalReference<>(null);
-    }
-
+        @SuppressWarnings("unchecked")
+        OptionalReference<V> ref = (OptionalReference<V>) EMPTY;
+        return ref;
+    }
+
+    /**
+     * Creates non-empty optional with provided value.
+     * Throws exception if value is null.
+     *
+     * @param value value
+     * @param <V> V
+     * @return optional
+     */
     public static <V> OptionalReference<V> of(V value) {
         return new OptionalReference<>(Objects.requireNonNull(value));
     }
 
+    /**
+     * Creates new optional with provided value.
+     * Returns empty if value is null.
+     *
+     * @param value value
+     * @param <V> V
+     * @return optional
+     */
     public static <V> OptionalReference<V> ofNullable(V value) {
         return new OptionalReference<>(value);
     }
 
+    /**
+     * Creates new optional with provided value.
+     * Returns empty if value is empty.
+     *
+     * @param value value
+     * @param <V> V
+     * @return optional
+     */
+    public static <V> OptionalReference<V> ofOptional(Optional<V> value) {
+        return new OptionalReference<>(value.orElse(null));
+    }
+
+    /**
+     * Returns value of optional or throws NoSuchElementException if empty
+     *
+     * @return value
+     */
     public V get() {
         if (value == null) {
             throw new NoSuchElementException("No value present");
@@ -32,23 +83,54 @@ public class OptionalReference<V> extends AbstractCollection<V> implements Set<V
         return value;
     }
 
+    /**
+     * Returns true if optional contains value
+     *
+     * @return boolean
+     */
     public boolean isPresent() {
         return value != null;
     }
 
+    /**
+     * Executes consumer with value stored inside optional if it is non-empty.
+     * Does nothing if optional is empty.
+     *
+     * @param consumer consumer
+     */
     public void ifPresent(Consumer<? super V> consumer) {
         if (value != null)
             consumer.accept(value);
     }
 
+    /**
+     * Returns value stored in optional or "other" if optional is empty.
+     *
+     * @param other other
+     * @return value
+     */
     public V orElse(V other) {
         return value != null ? value : other;
     }
 
+    /**
+     * Returns value stored in optional or computes "other" if optional is empty.
+     *
+     * @param other other
+     * @return value
+     */
     public V orElseGet(Supplier<? extends V> other) {
         return value != null ? value : other.get();
     }
 
+    /**
+     * Returns value stored in optional or throws computed exception if optional is empty.
+     *
+     * @param exceptionSupplier exceptionSupplier
+     * @param <X> X
+     * @return value
+     * @throws X if empty
+     */
     public <X extends Throwable> V orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
         if (value != null) {
             return value;
@@ -57,6 +139,15 @@ public class OptionalReference<V> extends AbstractCollection<V> implements Set<V
         }
     }
 
+    /**
+     * Converts this object into ordinary "Optional" class.
+     *
+     * @return optional
+     */
+    public Optional<V> asOptional() {
+        return Optional.ofNullable(value);
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (this == obj) {

+ 9 - 0
assira.core/src/main/java/net/ranides/assira/generic/Pair.java

@@ -10,6 +10,15 @@ import lombok.Data;
 
 import java.io.Serializable;
 
+/**
+ * Represents immutable pair of values.
+ * It implements Comparable and can be used as a key inside any Map.
+ *
+ * It uses {@linkplain CompareUtils#comparator() natural comparator} to compare values.
+ *
+ * @param <P> P
+ * @param <Q> Q
+ */
 @Data(staticConstructor = "of")
 public final class Pair<P,Q> implements Comparable<Pair<P,Q>>, Serializable {
 

+ 16 - 0
assira.core/src/main/java/net/ranides/assira/generic/SerializableCode.java

@@ -15,6 +15,14 @@ import java.io.ObjectStreamClass;
 import java.io.Serializable;
 import java.util.Map;
 
+/**
+ * Subclasses of this class are serialized in non-standard way:
+ * they save both their state, and bytecode.
+ *
+ * If you can't inherit from this class, you can save objects with bytecode, by serializing
+ * object created by {@link #wrap(Serializable)}. Those wrapped objects will recreate both state
+ * and code of the object during deserialization.
+ */
 public abstract class SerializableCode implements Serializable {
 
     private static final long serialVersionUID = 8L;
@@ -25,6 +33,14 @@ public abstract class SerializableCode implements Serializable {
         return writeReplace ? SerializableCode.wrap(this) : this;
     }
 
+    /**
+     * Converts provided serializable object into special type, which will store both
+     * state and bytecode inside stream, when serialized. During the deserialization "object"
+     * will be recreated, including both state and code.
+     *
+     * @param object object
+     * @return wrapper
+     */
     public static Serializable wrap(Serializable object) {
         return new ResolveWrapper(new CodeContainer(object));
     }

+ 126 - 11
assira.core/src/main/java/net/ranides/assira/generic/SerializationUtils.java

@@ -18,21 +18,21 @@ import java.nio.file.Path;
 import java.util.Collection;
 import java.util.Iterator;
 
+import lombok.experimental.UtilityClass;
 import net.ranides.assira.functional.Functions;
 import net.ranides.assira.reflection.IClass;
 
 /**
+ * Helper methods for object serialization
  *
  * @author ranides
  */
-public final class SerializationUtils {
-
-    private SerializationUtils() {
-        // utility class
-    }
+@UtilityClass
+public class SerializationUtils {
 
     /**
-     * "Klonuje" obiekt serializując i deserializując go.
+     * Clones object by serializing and deserializing it.
+     * It won't create real copy if object is correctly implemented singleton.
      *
      * @param value value
      * @param <T> T
@@ -44,6 +44,13 @@ public final class SerializationUtils {
         return read( (Class<T>)value.getClass(), write(value));
     }
 
+    /**
+     * Returns serialized object as binary data.
+     *
+     * @param value value
+     * @return binary
+     * @throws IOException on error
+     */
     public static byte[] write(Object value) throws IOException {
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         try (ObjectOutputStream ostream = new ObjectOutputStream(bos)) {
@@ -53,6 +60,13 @@ public final class SerializationUtils {
         }
     }
 
+    /**
+     * Serializes provided object into file
+     *
+     * @param target target
+     * @param value value
+     * @throws IOException on error
+     */
     public static void write(Path target, Object value) throws IOException {
         try (FileOutputStream fos = new FileOutputStream(target.toFile()) ){
             try (ObjectOutputStream ostream = new ObjectOutputStream(fos)) {
@@ -62,22 +76,65 @@ public final class SerializationUtils {
         }
     }
 
+    /**
+     * Deserializes object from provided binary data and casts it into "type"
+     *
+     * @param type type
+     * @param data data
+     * @param <T> T
+     * @return object
+     * @throws IOException on error
+     */
     public static <T> T read(Class<T> type, byte[] data) throws IOException {
         return type.cast(read(data));
     }
 
+    /**
+     * Deserializes object from provided file and casts it into "type"
+     *
+     * @param type type
+     * @param input input
+     * @param <T> T
+     * @return object
+     * @throws IOException on error
+     */
     public static <T> T read(Class<T> type, Path input) throws IOException {
         return type.cast(read(input));
     }
 
+    /**
+     * Deserializes object from provided binary data and casts it into "type"
+     *
+     * @param type type
+     * @param data data
+     * @param <T> T
+     * @return object
+     * @throws IOException on error
+     */
     public static <T> T read(IClass<T> type, byte[] data) throws IOException {
         return type.cast(read(data));
     }
 
+    /**
+     * Deserializes object from provided file and casts it into "type"
+     *
+     * @param type type
+     * @param input input
+     * @param <T> T
+     * @return object
+     * @throws IOException on error
+     */
     public static <T> T read(IClass<T> type, Path input) throws IOException {
         return type.cast(read(input));
     }
 
+    /**
+     * Deserializes object from provided binary data and returns as Object
+     *
+     * @param data data
+     * @return object
+     * @throws IOException on error
+     */
     public static Object read(byte[] data) throws IOException {
         try (ByteArrayInputStream ibs = new ByteArrayInputStream(data)) {
             try(ObjectInputStream istream = new ObjectInputStream(ibs)) {
@@ -88,6 +145,13 @@ public final class SerializationUtils {
         }
     }
 
+    /**
+     * Deserializes object from provided file and returns as Object
+     *
+     * @param input input
+     * @return object
+     * @throws IOException on error
+     */
     public static Object read(Path input) throws IOException {
         try (FileInputStream ifs = new FileInputStream(input.toFile())) {
             try(ObjectInputStream istream = new ObjectInputStream(ifs)) {
@@ -97,23 +161,55 @@ public final class SerializationUtils {
             }
         }
     }
-    
-    public static Object proxy(Object that, Object... params) {
+
+    /**
+     * This class creates serializable object which will try to recreate object during
+     * deserialization using ordinary constructor. Constructor will be called with provided
+     * arguments. Provided argument is used to find matching constructor, its state is irrelevant.
+     *
+     * Please note, that provided object does not need to be Serializable at all, altough
+     * most of the time this method will be used inside "writeReplace", so obviously you have to
+     * implement Serializable.
+     *
+     * @param that that
+     * @param params params
+     * @return serializable object
+     */
+    public static Serializable proxy(Object that, Object... params) {
         return new Proxy(that, params);
     }
 
     /**
+     * This class creates serializable object which saves into stream expression passed as argument.
+     * Provided expression will be executed at deserialization stage to recreate deserialized object.
+     *
      * Can be used inside method {@code protected Object writeReplace()}.
+     *
      * Please note, that {@code supplier} can't use {@code this} variable even implicitly.
-     * Every field must be copied into local variable and then used inside lambda.
+     * Every value used inside expression must be copied into final local variable
+     * and then used inside lambda.
      *
      * @param supplier supplier
      * @return serializable object
      */
-    public static Object proxy(Functions.Function0<Object> supplier) {
+    public static Serializable proxy(Functions.Function0<Object> supplier) {
         return new ProxyFunction(supplier);
     }
 
+    /**
+     * Returns information about size of binary data used to serialize provided values.
+     *
+     * It assumes every element has the same size;
+     * It tries to estimate average size of element and overhead introduced by writing data.
+     *
+     * For example, if all values share big object, it will be written into stream only one.
+     *
+     * It is especially true for non-static inner classes.
+     *
+     * @param values values
+     * @return size information
+     * @throws IOException on error
+     */
     public static SizeInfo sizeof(Collection<?> values) throws IOException {
         ByteArrayOutputStream orstream = new ByteArrayOutputStream();
         int s1 = values.size() / 2;
@@ -137,26 +233,45 @@ public final class SerializationUtils {
         }
     }
 
+    /**
+     * Holds information about size of serialized values.
+     * It can't be instantiated directly, it is returned by {@link #sizeof(Collection)}
+     */
     public static class SizeInfo {
         
         private final int size;
         private final int element;
         private final int overhead;
 
-        public SizeInfo(int sum, int element, int overhead) {
+        private SizeInfo(int sum, int element, int overhead) {
             this.size = sum;
             this.element = element;
             this.overhead = overhead;
         }
 
+        /**
+         * Returns overall size of all values
+         *
+         * @return int
+         */
         public int size() {
             return size;
         }
 
+        /**
+         * Returns average size of each element
+         *
+         * @return int
+         */
         public int element() {
             return element;
         }
 
+        /**
+         * Returns size of data shared between all serialized elements.
+         *
+         * @return int
+         */
         public int overhead() {
             return overhead;
         }

+ 12 - 0
assira.core/src/main/java/net/ranides/assira/generic/Tuple.java

@@ -10,12 +10,24 @@ import java.io.Serializable;
 import java.util.Arrays;
 import net.ranides.assira.collection.arrays.ArrayUtils;
 
+/**
+ * This class represents immutable tuple, which can be used as key in HashMap.
+ * It uses "equals" to compare values:
+ * tuples are equal only if each corresponding object inside two tuples are equal.
+ *
+ * Because of that, it is preffered to store immutable objects inside tuple.
+ */
 public final class Tuple implements Comparable<Tuple>, Serializable {
 
     private static final long serialVersionUID = 1L;
 
     private final Object[] values;
 
+    /**
+     * Creates new tuple.
+     *
+     * @param values values
+     */
     public Tuple(Object... values) {
         this.values = ArrayUtils.copy(values);
     }

+ 34 - 32
assira.core/src/main/java/net/ranides/assira/generic/TypeToken.java

@@ -13,27 +13,17 @@ import java.util.List;
 
 import net.ranides.assira.reflection.*;
 import net.ranides.assira.reflection.impl.AClass;
-import net.ranides.assira.reflection.util.ClassUtils;
 
 /**
- * Klasa przekazująca dalej informację o klasie w genericu. Prosty przykład problemu,
- * który rozwiązuje TypeToken:
- * <blockquote><pre>
- * List&lt;T&gt; makeList(Class&lt;T&gt; clazz, int size) {
- *     return new ArrayList&lt;T&gt;(size);
- * }
+ * Class for passing information about parameterized types.
+ * TypeToken is very specific {@link IClass} implementation, which is able
+ * to reflect at runtime its own type parameter {@code T}.
  *
- * List&lt;T&gt; copyList(List&lt;T&gt; source) {
- *     List&lt;T&gt; target = makeList( ? , source.size());
- *     for(T item : source) target.add(item);
- *     return target;
- * }
- * </pre></blockquote>
+ * In Java, you can't pass parameterized type {@code List<String>} as method argument.
+ * You can only pass {@code List.class}. TypeToken solves this problem.
  *
- * {@code makeList} pobiera instancję {@code Class<T>} bo jakoś musi dostać to nieszczęsne T.
- * Problem w tym, że copyList już takiej instancji nie dostaje - a nie da się utworzyć {@code new Class<T>()}
- * żeby jej przekazać. Oczywiście {@code new TypeToken<T>()} jest legalne. I tylko z tego
- * właśnie powodu klasa została napisana. Rozszerzony i poprawiony kod:
+ * In Java, you can't pass unknown type {@code T} as method argument.
+ * TypeToken solves this problem too.
  *
  * <blockquote><pre>
  * List&lt;T&gt; makeList(Class&lt;T&gt; clazz, int size) {
@@ -49,13 +39,19 @@ import net.ranides.assira.reflection.util.ClassUtils;
  *     for(T item : source) target.add(item);
  *     return target;
  * }
+ *
+ * List&lt;Pair&lt;String,Float&gt;&gt; makeComplexList(List&lt;?&gt; source) {
+ *     List&lt;Pair&lt;String,Float&gt;&gt; target = makeList( new TypeToken&lt;Pair&lt;String,Float&gt;&gt;(){}, source.size());
+ *     for(Object item : source) target.add(...);
+ *     return target;
+ * }
  * </pre></blockquote>
  *
  * <p>
- * Uwaga. Klasa potrafi porządnie wydedukować instancję {@code Class<T>}.
- * Rozszerzenie podpatrzone z biblioteki <a href="http://wiki.fasterxml.com/JacksonHome">Jackson JSON Processor</a>
+ * Please note this class is able to deduce instance of {@code Class<T>}.
+ * It is found inside <a href="http://wiki.fasterxml.com/JacksonHome">Jackson JSON Processor</a> library.
  * </p>
- * @param <T> typ, który chcemy przekazać dalej
+ * @param <T> type which we want to pass to other methods
  * 
  * @author Ranides Atterwim {@literal <ranides@gmail.com>}
  */
@@ -64,9 +60,8 @@ public abstract class TypeToken<T> extends AClass<T> implements Serializable {
     private final IClass<T> type;
 
     /**
-     * Tworzy nową instancję klasy TypeToken. Możliwe i sensowne tylko w formie
-     * utworzenia nowej klasy anonimowej, parametryzowanej typem, który chcemy
-     * przekazać / przechować / wydedukować:
+     * Creates new instance of TypeToken.
+     * Constructor is protected, because it is usefull only if you create new anonymous subclass.
      * <pre>
      * {@code new TypeToken<Integer>(){ } }
      * </pre>
@@ -74,27 +69,34 @@ public abstract class TypeToken<T> extends AClass<T> implements Serializable {
      */
     @SuppressWarnings("unchecked")
     protected TypeToken() {
-        this.type = getParam(this);
+        // typeinfo(class).params[0]
+        // wstawiło by nam do kontekstu parametr "T" pobrany z deklaracji TypeTokena
+        ParameterizedType ptype = (ParameterizedType)getClass().getGenericSuperclass();
+        this.type = (IClass)IClass.typeinfo(ptype.getActualTypeArguments()[0]);
     }
 
+    /**
+     * Creates new instance of TypeToken.
+     * It takes any reflected type and tries to convert it into IClass.
+     *
+     * @param type type
+     */
     @SuppressWarnings("unchecked")
 	protected TypeToken(Type type) {
 		this.type = (IClass)IClass.typeinfo(type);
 	}
 
+    /**
+     * Creates new instance of TypeToken.
+     * It stores provided IClass as a token type.
+     *
+     * @param type type
+     */
     @SuppressWarnings("unchecked")
     protected TypeToken(IClass<?> type) {
 		this.type = (IClass)type;
 	}
 
-    @SuppressWarnings("unchecked")
-    public static <R> IClass<R> getParam(Object token) {
-        // typeinfo(class).params[0]
-        // wstawiło by nam do kontekstu parametr "T" pobrany z deklaracji TypeTokena
-        ParameterizedType ptype = (ParameterizedType)token.getClass().getGenericSuperclass();
-        return (IClass)IClass.typeinfo(ptype.getActualTypeArguments()[0]);
-    }
-
     @Override
     public IContext context() {
         return type.context();

+ 29 - 3
assira.core/src/main/java/net/ranides/assira/generic/ValueUtils.java

@@ -9,6 +9,9 @@ package net.ranides.assira.generic;
 import java.util.function.Supplier;
 
 
+/**
+ * Few utility methods for working with nulls, booleans, etc
+ */
 @SuppressWarnings({
     "PMD.ShortVar", 
     "PMD.ShortMethodName"
@@ -17,10 +20,24 @@ public final class ValueUtils {
     
     private ValueUtils() { }
 
+    /**
+     * Checks if this value is exactly "true".
+     * Returns false, if this value is "null", "false", or it isn't boolean at all.
+     *
+     * @param value value
+     * @return boolean
+     */
     public static boolean isTrue(Object value) {
         return (value instanceof Boolean) && (Boolean)value;
     }
 
+    /**
+     * Checks if this value is exactly "false".
+     * Returns false, if this value is "null", "true", or it isn't boolean at all.
+     *
+     * @param value value
+     * @return boolean
+     */
     public static boolean isFalse(Object value) {
         return (value instanceof Boolean) && !(Boolean)value;
     }
@@ -47,8 +64,17 @@ public final class ValueUtils {
     public static <T> T or(T a, T b) {
         return null != a ? a : b;
     }
-	
-	public static <T> T eval(T ddefault, Supplier<? extends T> supplier) {
+
+    /**
+     * Returns value generated by provided supplier.
+     * If supplier returned "null", it returns "other"
+     *
+     * @param other other
+     * @param supplier supplier
+     * @param <T> T
+     * @return value
+     */
+	public static <T> T eval(T other, Supplier<? extends T> supplier) {
 		try {
 			T s = supplier.get();
 			if(s != null) {
@@ -57,7 +83,7 @@ public final class ValueUtils {
 		} catch(NullPointerException $0) { // NOPMD
 			// do nothing
 		}
-		return ddefault;
+		return other;
 	}
 
 }

+ 81 - 2
assira.core/src/main/java/net/ranides/assira/generic/Wrapper.java

@@ -11,8 +11,26 @@ import java.util.concurrent.atomic.AtomicReference;
 
 import net.ranides.assira.reflection.IClass;
 
+/**
+ * Simple interface of object which allows to modify stored external value.
+ *
+ * It could be simple mutable wrapper with behaviour similar to singleton collection,
+ * but it could be always binding to some field, property or map entry.
+ *
+ * In other words: it can represent anything ;-)
+ *
+ * @param <T> T
+ */
 public interface Wrapper<T> {
 
+    /**
+     * Creates simple mutable object with initial value.
+     * It is not thread-safe.
+     *
+     * @param value value
+     * @param <Q> Q
+     * @return wrapper
+     */
     static <Q> Wrapper<Q> of(Q value) {
         class SimpleWrapper<R> implements Wrapper<R>, Serializable {
 
@@ -44,6 +62,14 @@ public interface Wrapper<T> {
         return new SimpleWrapper<>(value);
     }
 
+    /**
+     * Creates simple mutable object with initial value.
+     * It is thread-safe.
+     *
+     * @param value value
+     * @param <Q> Q
+     * @return wrapper
+     */
     static <Q> Wrapper<Q> atomic(Q value) {
         class AtomicWrapper<R> implements Wrapper<R>, Serializable {
 
@@ -80,26 +106,71 @@ public interface Wrapper<T> {
         return new AtomicWrapper<>(value);
     }
 
+    /**
+     * Returns declared type of value.
+     * It must be superclass of stored value, at best it should be identical.
+     *
+     * @return type
+     */
     IClass<?> type();
 
+    /**
+     * Returns binded value.
+     * For example: simple wrapper will return stored value, EntryWrapper will read from Map.
+     *
+     * @return value value
+     */
     T get();
 
+    /**
+     * Changes binded value.
+     * For example: simple wrapper will update stored value, EntryWrapper will change value inside Map.
+     *
+     * @param value value
+     */
     void set(T value);
-    
+
+    /**
+     * Changes binded value.
+     * For example: simple wrapper will update stored value, EntryWrapper will change value inside Map.
+     *
+     * Please note: because "replace" returns previous value, it executes "get" internally.
+     *
+     * @param value value
+     * @return previously stored value
+     */
     default T replace(T value) {
         T prv = get();
         set(value);
         return prv;
     }
 
+    /**
+     * Checks if value is "null"
+     *
+     * @return boolean
+     */
     default boolean isEmpty() {
         return get() == null;
     }
 
+    /**
+     * Checks if value is not "null"
+     *
+     * @return boolean
+     */
     default boolean isPresent() {
         return !isEmpty();
     }
 
+    /**
+     * Casts this Wrapper to new type: it is safe, checked cast.
+     * It does not create new wrapper, it is only cast operation.
+     *
+     * @param type type
+     * @param <R> R
+     * @return this
+     */
     @SuppressWarnings("unchecked")
     default <R> Wrapper<R> cast(Class<R> type) {
         if( !type().isEquivalent(IClass.typeinfo(type))) {
@@ -107,7 +178,15 @@ public interface Wrapper<T> {
         }
         return (Wrapper)this;
     }
-    
+
+    /**
+     * Casts this Wrapper to new type: it is safe, checked cast.
+     * It does not create new wrapper, it is only cast operation.
+     *
+     * @param type type
+     * @param <R> R
+     * @return this
+     */
     @SuppressWarnings("unchecked")
     default <R> Wrapper<R> cast(TypeToken<R> type) {
         if( !type().isEquivalent(type)) {

+ 1 - 1
assira.core/src/main/java/net/ranides/assira/xml/XMLType.java

@@ -56,7 +56,7 @@ public enum XMLType implements Predicate<XMLContext> {
     
     ;
     
-    private static final IntFunction<XMLType> MAP = EnumUtils.indexInt(XMLType.class, n -> n.value);
+    private static final IntFunction<XMLType> MAP = EnumUtils.lookupInt(XMLType.class, n -> n.value);
     
     private final int value;
 

+ 2 - 2
assira.core/src/test/java/net/ranides/assira/generic/EnumUtilsTest.java

@@ -20,7 +20,7 @@ public class EnumUtilsTest {
 
     @Test
     public void testIntMap() {
-        IntFunction<MyEnum> map = EnumUtils.indexInt(MyEnum.class, e -> e.v);
+        IntFunction<MyEnum> map = EnumUtils.lookupInt(MyEnum.class, e -> e.v);
 
         assertEquals(MyEnum.CONST, map.apply(8));
         assertEquals(MyEnum.ITEM, map.apply(4));
@@ -29,7 +29,7 @@ public class EnumUtilsTest {
     
     @Test
     public void testMap() {
-        Function<String, MyEnum> map = EnumUtils.index(MyEnum.class, e -> e.name().toLowerCase());
+        Function<String, MyEnum> map = EnumUtils.lookup(MyEnum.class, e -> e.name().toLowerCase());
 
         assertEquals(MyEnum.CONST, map.apply("const"));
         assertEquals(MyEnum.ENTRY, map.apply("entry"));