You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by rm...@apache.org on 2015/12/07 17:37:57 UTC

[1/2] incubator-johnzon git commit: more of jsonb - missing plain value handling

Repository: incubator-johnzon
Updated Branches:
  refs/heads/master 65564700a -> a409da7d1


http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/a409da7d/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java
index 6bb1f1f..c733f3a 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Mappings.java
@@ -36,6 +36,7 @@ import java.math.BigInteger;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Date;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -212,10 +213,12 @@ public class Mappings {
             final Class<?> collectionType;
             if (List.class.isAssignableFrom(r)) {
                 collectionType = List.class;
-            }else if (SortedSet.class.isAssignableFrom(r)) {
+            } else if (SortedSet.class.isAssignableFrom(r)) {
                 collectionType = SortedSet.class;
             } else if (Set.class.isAssignableFrom(r)) {
                 collectionType = Set.class;
+            } else if (Deque.class.isAssignableFrom(r)) {
+                collectionType = Deque.class;
             } else if (Queue.class.isAssignableFrom(r)) {
                 collectionType = Queue.class;
             } else if (Collection.class.isAssignableFrom(r)) {
@@ -286,8 +289,11 @@ public class Mappings {
         }
         final Class<?> clazz = findModelClass(inClazz);
 
-        final Map<String, Getter> getters = newOrderedMap();
-        final Map<String, Setter> setters = newOrderedMap();
+        Comparator<String> fieldComparator = accessMode.fieldComparator(inClazz);
+        fieldComparator = fieldComparator == null ? fieldOrdering : fieldComparator;
+
+        final Map<String, Getter> getters = fieldComparator == null ? newOrderedMap(Getter.class) : new TreeMap<String, Getter>(fieldComparator);
+        final Map<String, Setter> setters = fieldComparator == null ? newOrderedMap(Setter.class) : new TreeMap<String, Setter>(fieldComparator);
 
         final Map<String, AccessMode.Reader> readers = accessMode.findReaders(clazz);
         final Map<String, AccessMode.Writer> writers = accessMode.findWriters(clazz);
@@ -339,7 +345,7 @@ public class Mappings {
         return clazz;
     }
 
-    private <T> Map<String, T> newOrderedMap() {
+    private <T> Map<String, T> newOrderedMap(final Class<T> value) {
         return fieldOrdering != null ? new TreeMap<String, T>(fieldOrdering) : new HashMap<String, T>();
     }
 
@@ -400,8 +406,8 @@ public class Mappings {
         }
 
         // build "this" model
-        final Map<String, Getter> objectGetters = newOrderedMap();
-        final Map<String, Setter> objectSetters = newOrderedMap();
+        final Map<String, Getter> objectGetters = newOrderedMap(Getter.class);
+        final Map<String, Setter> objectSetters = newOrderedMap(Setter.class);
 
         for (final JohnzonVirtualObject.Field f : o.fields()) {
             final String name = f.value();

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/a409da7d/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java
index a6c3267..d992725 100644
--- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java
@@ -377,10 +377,7 @@ public class MapperTest {
 
     @Test(expected = MapperException.class)
     public void literalFail2() {
-
-        final Bool2 instance = new MapperBuilder().build().readObject(new ByteArrayInputStream("{\"map\":{\"key\":\"true\"}}".getBytes()),
-                Bool2.class);
-
+        new MapperBuilder().build().readObject(new ByteArrayInputStream("{\"map\":{\"key\":\"true\"}}".getBytes()), Bool2.class);
     }
 
     @Test


[2/2] incubator-johnzon git commit: more of jsonb - missing plain value handling

Posted by rm...@apache.org.
more of jsonb - missing plain value handling


Project: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/commit/a409da7d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/tree/a409da7d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/diff/a409da7d

Branch: refs/heads/master
Commit: a409da7d1121c3d92e09d8d2ba1f123413051f73
Parents: 6556470
Author: Romain Manni-Bucau <rm...@gmail.com>
Authored: Mon Dec 7 17:38:45 2015 +0100
Committer: Romain Manni-Bucau <rm...@gmail.com>
Committed: Mon Dec 7 17:38:45 2015 +0100

----------------------------------------------------------------------
 .../org/apache/johnzon/core/JsonLongImpl.java   |    2 +-
 .../org/apache/johnzon/core/JsonReaderImpl.java |    5 +-
 .../org/apache/johnzon/jsonb/JohnsonJsonb.java  |  135 +-
 .../apache/johnzon/jsonb/JohnzonBuilder.java    |   15 +-
 .../apache/johnzon/jsonb/JsonbAccessMode.java   |  145 +-
 .../johnzon/jsonb/DefaultMappingTest.java       | 1312 ++++++++++++++++++
 .../java/org/apache/johnzon/mapper/Mapper.java  |  107 +-
 .../johnzon/mapper/access/AccessMode.java       |    2 +
 .../johnzon/mapper/access/BaseAccessMode.java   |   11 +-
 .../johnzon/mapper/reflection/Mappings.java     |   18 +-
 .../org/apache/johnzon/mapper/MapperTest.java   |    5 +-
 11 files changed, 1648 insertions(+), 109 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/a409da7d/johnzon-core/src/main/java/org/apache/johnzon/core/JsonLongImpl.java
----------------------------------------------------------------------
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonLongImpl.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonLongImpl.java
index 2f013f7..1a85b0b 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonLongImpl.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonLongImpl.java
@@ -23,7 +23,7 @@ import java.math.BigInteger;
 
 import javax.json.JsonNumber;
 
-final class JsonLongImpl implements JsonNumber {
+public final class JsonLongImpl implements JsonNumber {
     private final long value;
 
     JsonLongImpl(final long value) {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/a409da7d/johnzon-core/src/main/java/org/apache/johnzon/core/JsonReaderImpl.java
----------------------------------------------------------------------
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonReaderImpl.java b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonReaderImpl.java
index 86d7708..bba027c 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonReaderImpl.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonReaderImpl.java
@@ -43,7 +43,8 @@ class JsonReaderImpl implements JsonReader {
         if (!parser.hasNext()) {
             throw new IllegalStateException("Nothing to read");
         }
-        switch (parser.next()) {
+        final JsonParser.Event next = parser.next();
+        switch (next) {
             case START_OBJECT:
                 final JsonObjectBuilder objectBuilder = new JsonObjectBuilderImpl();
                 parseObject(objectBuilder);
@@ -62,7 +63,7 @@ class JsonReaderImpl implements JsonReader {
                 return arrayBuilder.build();
             default:
                 close();
-                throw new JsonParsingException("Unknown structure: " + parser.next(), parser.getLocation());
+                throw new JsonParsingException("Unknown structure: " + next, parser.getLocation());
         }
 
     }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/a409da7d/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnsonJsonb.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnsonJsonb.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnsonJsonb.java
index 85f9bd1..ec5e960 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnsonJsonb.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnsonJsonb.java
@@ -19,6 +19,8 @@
 package org.apache.johnzon.jsonb;
 
 import org.apache.johnzon.mapper.Mapper;
+import org.apache.johnzon.mapper.MapperException;
+import org.apache.johnzon.mapper.reflection.JohnzonParameterizedType;
 
 import javax.json.bind.Jsonb;
 import javax.json.bind.JsonbException;
@@ -30,6 +32,7 @@ import java.io.OutputStream;
 import java.io.Reader;
 import java.io.StringReader;
 import java.io.Writer;
+import java.lang.reflect.Array;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.nio.CharBuffer;
@@ -44,28 +47,52 @@ public class JohnsonJsonb implements Jsonb {
 
     @Override
     public <T> T fromJson(final String str, final Class<T> type) throws JsonbException {
-        return delegate.readObject(str, type);
+        try {
+            if (isArray(type)) {
+                return delegate.readTypedArray(new StringReader(str), type.getComponentType(), type);
+            } else if (Collection.class.isAssignableFrom(type)) {
+                return (T) delegate.readCollection(new StringReader(str), new JohnzonParameterizedType(type, Object.class));
+            }
+            return delegate.readObject(str, type);
+        } catch (final MapperException me) {
+            throw new JsonbException(me.getMessage(), me);
+        }
     }
 
     @Override
     public <T> T fromJson(final String str, final Type runtimeType) throws JsonbException {
-        if (isArray(runtimeType)) {
-            return (T) delegate.readArray(new StringReader(str), Class.class.cast(runtimeType).getComponentType());
-        } else if (isCollection(runtimeType)) {
-            return (T) delegate.readCollection(new StringReader(str), ParameterizedType.class.cast(runtimeType));
+        try {
+            if (isArray(runtimeType)) {
+                final Class cast = Class.class.cast(runtimeType);
+                return (T) delegate.readTypedArray(new StringReader(str), cast.getComponentType(), cast);
+            } else if (isCollection(runtimeType)) {
+                return (T) delegate.readCollection(new StringReader(str), ParameterizedType.class.cast(runtimeType));
+            }
+            return delegate.readObject(str, runtimeType);
+        } catch (final MapperException me) {
+            throw new JsonbException(me.getMessage(), me);
         }
-        return delegate.readObject(str, runtimeType);
     }
 
     @Override
     public <T> T fromJson(final Readable readable, final Class<T> type) throws JsonbException {
-        return delegate.readObject(toReader(readable), type);
+        try {
+            if (isArray(type)) {
+                return delegate.readTypedArray(toReader(readable), type.getComponentType(), type);
+            } else if (Collection.class.isAssignableFrom(type)) {
+                return (T) delegate.readCollection(toReader(readable), new JohnzonParameterizedType(type, Object.class));
+            }
+            return delegate.readObject(toReader(readable), type);
+        } catch (final MapperException me) {
+            throw new JsonbException(me.getMessage(), me);
+        }
     }
 
     @Override
     public <T> T fromJson(final Readable readable, final Type runtimeType) throws JsonbException {
         if (isArray(runtimeType)) {
-            return (T) delegate.readArray(toReader(readable), Class.class.cast(runtimeType).getComponentType());
+            final Class<T> type = Class.class.cast(runtimeType);
+            return delegate.readTypedArray(toReader(readable), type.getComponentType(), type);
         } else if (isCollection(runtimeType)) {
             return (T) delegate.readCollection(toReader(readable), ParameterizedType.class.cast(runtimeType));
         }
@@ -74,27 +101,97 @@ public class JohnsonJsonb implements Jsonb {
 
     @Override
     public <T> T fromJson(final InputStream stream, final Class<T> type) throws JsonbException {
-        return delegate.readObject(stream, type);
+        try {
+            if (isArray(type)) {
+                return delegate.readTypedArray(stream, type.getComponentType(), type);
+            } else if (Collection.class.isAssignableFrom(type)) {
+                return (T) delegate.readCollection(stream, new JohnzonParameterizedType(type, Object.class));
+            }
+            return delegate.readObject(stream, type);
+        } catch (final MapperException me) {
+            throw new JsonbException(me.getMessage(), me);
+        }
     }
 
     @Override
     public <T> T fromJson(final InputStream stream, final Type runtimeType) throws JsonbException {
-        if (isArray(runtimeType)) {
-            return (T) delegate.readArray(stream, Class.class.cast(runtimeType).getComponentType());
-        } else if (isCollection(runtimeType)) {
-            return (T) delegate.readCollection(stream, ParameterizedType.class.cast(runtimeType));
+        try {
+            if (isArray(runtimeType)) {
+                final Class<T> type = Class.class.cast(runtimeType);
+                return delegate.readTypedArray(stream, type.getComponentType(), type);
+            } else if (isCollection(runtimeType)) {
+                return (T) delegate.readCollection(stream, ParameterizedType.class.cast(runtimeType));
+            }
+            return delegate.readObject(stream, runtimeType);
+        } catch (final MapperException me) {
+            throw new JsonbException(me.getMessage(), me);
         }
-        return delegate.readObject(stream, runtimeType);
     }
 
     @Override
     public String toJson(final Object object) throws JsonbException {
-        if (isArray(object.getClass())) {
-            return delegate.writeArrayAsString((Object[]) object);
-        } else if (Collection.class.isInstance(object)) {
-            return delegate.writeArrayAsString(Collection.class.cast(object));
+        try {
+            if (isArray(object.getClass())) {
+                return delegate.writeArrayAsString(toArray(object));
+            } else if (Collection.class.isInstance(object)) {
+                return delegate.writeArrayAsString(Collection.class.cast(object));
+            }
+            return delegate.writeObjectAsString(object);
+
+        } catch (final MapperException me) {
+            throw new JsonbException(me.getMessage(), me);
         }
-        return delegate.writeObjectAsString(object);
+    }
+
+    private Object[] toArray(final Object object) {
+        final Class<?> componentType = object.getClass().getComponentType();
+        Object[] array;
+        if (int.class == componentType) {
+            final int length = Array.getLength(object);
+            array = new Integer[length];
+            for (int i = 0; i < length; i++) {
+                array[i] = Array.getInt(object, i);
+            }
+        } else if (double.class == componentType) {
+            final int length = Array.getLength(object);
+            array = new Integer[length];
+            for (int i = 0; i < length; i++) {
+                array[i] = Array.getDouble(object, i);
+            }
+        } else if (byte.class == componentType) {
+            final int length = Array.getLength(object);
+            array = new Integer[length];
+            for (int i = 0; i < length; i++) {
+                array[i] = Array.getByte(object, i);
+            }
+        } else if (char.class == componentType) {
+            final int length = Array.getLength(object);
+            array = new Integer[length];
+            for (int i = 0; i < length; i++) {
+                array[i] = Array.getChar(object, i);
+            }
+        } else if (float.class == componentType) {
+            final int length = Array.getLength(object);
+            array = new Integer[length];
+            for (int i = 0; i < length; i++) {
+                array[i] = Array.getFloat(object, i);
+            }
+        } else if (long.class == componentType) {
+            final int length = Array.getLength(object);
+            array = new Integer[length];
+            for (int i = 0; i < length; i++) {
+                array[i] = Array.getLong(object, i);
+            }
+        } else if (short.class == componentType) {
+            final int length = Array.getLength(object);
+            array = new Integer[length];
+            for (int i = 0; i < length; i++) {
+                array[i] = Array.getShort(object, i);
+            }
+        } else {
+            array = (Object[]) object;
+        }
+        return array;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/a409da7d/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
index abb74b2..29a26fb 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
@@ -36,6 +36,7 @@ import javax.json.spi.JsonProvider;
 import javax.json.stream.JsonGenerator;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.nio.charset.StandardCharsets;
 import java.time.Duration;
 import java.time.Instant;
@@ -57,12 +58,14 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.SimpleTimeZone;
 import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.stream.Stream;
 
 import static java.util.Collections.emptyMap;
 import static java.util.Optional.ofNullable;
 import static javax.json.bind.config.PropertyNamingStrategy.IDENTITY;
-import static javax.json.bind.config.PropertyOrderStrategy.ANY;
+import static javax.json.bind.config.PropertyOrderStrategy.LEXICOGRAPHICAL;
 
 public class JohnzonBuilder implements JsonbBuilder {
     private final MapperBuilder builder = new MapperBuilder();
@@ -102,17 +105,21 @@ public class JohnzonBuilder implements JsonbBuilder {
         final Optional<Object> namingStrategyValue = config.getProperty(JsonbConfig.PROPERTY_NAMING_STRATEGY);
 
         final PropertyNamingStrategy propertyNamingStrategy = new PropertyNamingStrategyFactory(namingStrategyValue.orElse(IDENTITY)).create();
-        final String orderValue = config.getProperty(JsonbConfig.PROPERTY_ORDER_STRATEGY).map(String::valueOf).orElse(ANY);
+        final String orderValue = config.getProperty(JsonbConfig.PROPERTY_ORDER_STRATEGY).map(String::valueOf).orElse(LEXICOGRAPHICAL);
         final PropertyVisibilityStrategy visibilityStrategy = config.getProperty(JsonbConfig.PROPERTY_VISIBILITY_STRATEGY)
             .map(PropertyVisibilityStrategy.class::cast).orElse(new PropertyVisibilityStrategy() {
+                private final ConcurrentMap<Class<?>, PropertyVisibilityStrategy> strategies = new ConcurrentHashMap<>();
+
                 @Override
                 public boolean isVisible(final Field field) {
-                    return true;
+                    final PropertyVisibilityStrategy strategy = strategies.computeIfAbsent(field.getDeclaringClass(), this::visibilityStrategy);
+                    return strategy == this ? Modifier.isPublic(field.getModifiers()) : strategy.isVisible(field);
                 }
 
                 @Override
                 public boolean isVisible(final Method method) {
-                    return true;
+                    final PropertyVisibilityStrategy strategy = strategies.computeIfAbsent(method.getDeclaringClass(), this::visibilityStrategy);
+                    return strategy == this ? Modifier.isPublic(method.getModifiers()) : strategy.isVisible(method);
                 }
 
                 private PropertyVisibilityStrategy visibilityStrategy(final Class<?> type) { // can be cached

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/a409da7d/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
index eda5fe2..854cae2 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
@@ -71,6 +71,7 @@ import java.util.function.Function;
 import java.util.stream.Stream;
 
 import static java.util.Arrays.asList;
+import static java.util.Optional.ofNullable;
 import static org.apache.johnzon.mapper.reflection.Converters.matches;
 
 public class JsonbAccessMode implements AccessMode {
@@ -88,11 +89,17 @@ public class JsonbAccessMode implements AccessMode {
         this.order = orderValue;
         this.visibility = visibilityStrategy;
         this.caseSensitive = caseSensitive;
-        this.delegate = new FieldAndMethodAccessMode(true, false);
+        this.delegate = new FieldAndMethodAccessMode(true, true);
         this.defaultConverters = defaultConverters;
     }
 
     @Override
+    public Comparator<String> fieldComparator(final Class<?> clazz) {
+        final Comparator<String> orderComparator = orderComparator(clazz);
+        return caseSensitive ? orderComparator : ((o1, o2) -> o1.equalsIgnoreCase(o2) ? 0 : orderComparator.compare(o1, o2));
+    }
+
+    @Override
     public Factory findFactory(final Class<?> clazz) {
         Constructor<?> constructor = null;
         Method factory = null;
@@ -276,32 +283,41 @@ public class JsonbAccessMode implements AccessMode {
     public Map<String, Reader> findReaders(final Class<?> clazz) {
         final Map<String, Reader> readers = delegate.findReaders(clazz);
 
-        final Comparator<String> orderComparator = orderComparator(clazz);
-        final Comparator<String> keyComparator = caseSensitive ?
-            orderComparator :
-            (o1, o2) -> o1.equalsIgnoreCase(o2) ? 0 : orderComparator.compare(o1, o2);
-
+        final Comparator<String> keyComparator = fieldComparator(clazz);
         final Map<String, Reader> result = keyComparator == null ? new HashMap<>() : new TreeMap<>(keyComparator);
         for (final Map.Entry<String, Reader> entry : readers.entrySet()) {
-            final Reader value = entry.getValue();
-            if (isTransient(value, visibility)) {
+            final Reader initialReader = entry.getValue();
+            if (isTransient(initialReader, visibility)) {
                 continue;
             }
 
+            final Reader finalReader;
+            if (FieldAndMethodAccessMode.CompositeDecoratedType.class.isInstance(initialReader)) { // unwrap to use the right reader
+                final FieldAndMethodAccessMode.CompositeDecoratedType decoratedType = FieldAndMethodAccessMode.CompositeDecoratedType.class.cast(initialReader);
+                final DecoratedType type2 = decoratedType.getType2();
+                if (MethodAccessMode.MethodReader.class.isInstance(type2)) {
+                    finalReader = Reader.class.cast(type2);
+                } else {
+                    finalReader = initialReader;
+                }
+            } else {
+                finalReader = initialReader;
+            }
+
             // we are visible
-            final JsonbProperty property = value.getAnnotation(JsonbProperty.class);
-            final JsonbNillable nillable = value.getClassOrPackageAnnotation(JsonbNillable.class);
+            final JsonbProperty property = initialReader.getAnnotation(JsonbProperty.class);
+            final JsonbNillable nillable = initialReader.getClassOrPackageAnnotation(JsonbNillable.class);
             final boolean isNillable = nillable != null || (property != null && property.nillable());
-            final JsonbTypeAdapter adapter = value.getAnnotation(JsonbTypeAdapter.class);
-            final JsonbDateFormat dateFormat = value.getAnnotation(JsonbDateFormat.class);
-            final JsonbNumberFormat numberFormat = value.getAnnotation(JsonbNumberFormat.class);
-            final JsonbValue jsonbValue = value.getAnnotation(JsonbValue.class);
-            validateAnnotations(value, adapter, dateFormat, numberFormat, jsonbValue);
+            final JsonbTypeAdapter adapter = initialReader.getAnnotation(JsonbTypeAdapter.class);
+            final JsonbDateFormat dateFormat = initialReader.getAnnotation(JsonbDateFormat.class);
+            final JsonbNumberFormat numberFormat = initialReader.getAnnotation(JsonbNumberFormat.class);
+            final JsonbValue jsonbValue = initialReader.getAnnotation(JsonbValue.class);
+            validateAnnotations(initialReader, adapter, dateFormat, numberFormat, jsonbValue);
 
             final Converter<?> converter;
             try {
-                converter = adapter == null && dateFormat == null && numberFormat == null && jsonbValue == null ? defaultConverters.get(value.getType()) :
-                    toConverter(value.getType(), adapter, dateFormat, numberFormat);
+                converter = adapter == null && dateFormat == null && numberFormat == null && jsonbValue == null ? defaultConverters.get(initialReader.getType()) :
+                    toConverter(initialReader.getType(), adapter, dateFormat, numberFormat);
             } catch (final InstantiationException | IllegalAccessException e) {
                 throw new IllegalArgumentException(e);
             }
@@ -309,21 +325,21 @@ public class JsonbAccessMode implements AccessMode {
             // handle optionals since mapper is still only java 7
             final Type type;
             final Function<Object, Object> reader;
-            if (isOptional(value)) {
-                type = ParameterizedType.class.cast(value.getType()).getActualTypeArguments()[0];
-                reader = i -> Optional.class.cast(value.read(i)).orElse(null);
-            } else if (OptionalInt.class == value.getType()) {
+            if (isOptional(finalReader)) {
+                type = ParameterizedType.class.cast(finalReader.getType()).getActualTypeArguments()[0];
+                reader = i -> ofNullable(finalReader.read(i)).map(o -> Optional.class.cast(o).orElse(null)).orElse(null);
+            } else if (OptionalInt.class == finalReader.getType()) {
                 type = int.class;
-                reader = i -> OptionalInt.class.cast(value.read(i)).orElse(0);
-            } else if (OptionalLong.class == value.getType()) {
+                reader = i -> OptionalInt.class.cast(finalReader.read(i)).orElse(0);
+            } else if (OptionalLong.class == finalReader.getType()) {
                 type = long.class;
-                reader = i -> OptionalLong.class.cast(value.read(i)).orElse(0);
-            } else if (OptionalDouble.class == value.getType()) {
+                reader = i -> OptionalLong.class.cast(finalReader.read(i)).orElse(0);
+            } else if (OptionalDouble.class == finalReader.getType()) {
                 type = double.class;
-                reader = i -> OptionalDouble.class.cast(value.read(i)).orElse(0);
+                reader = i -> OptionalDouble.class.cast(finalReader.read(i)).orElse(0);
             } else {
-                type = value.getType();
-                reader = value::read;
+                type = finalReader.getType();
+                reader = finalReader::read;
             }
 
             final String key = property == null || property.value().isEmpty() ? naming.translateName(entry.getKey()) : property.value();
@@ -340,12 +356,12 @@ public class JsonbAccessMode implements AccessMode {
 
                 @Override
                 public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
-                    return value.getAnnotation(clazz);
+                    return finalReader.getAnnotation(clazz);
                 }
 
                 @Override
                 public <T extends Annotation> T getClassOrPackageAnnotation(final Class<T> clazz) {
-                    return value.getClassOrPackageAnnotation(clazz);
+                    return finalReader.getClassOrPackageAnnotation(clazz);
                 }
 
                 @Override
@@ -368,28 +384,41 @@ public class JsonbAccessMode implements AccessMode {
     public Map<String, Writer> findWriters(final Class<?> clazz) {
         final Map<String, Writer> writers = delegate.findWriters(clazz);
 
-        final Comparator<String> keyComparator = orderComparator(clazz);
+        final Comparator<String> keyComparator = fieldComparator(clazz);
         final Map<String, Writer> result = keyComparator == null ? new HashMap<>() : new TreeMap<>(keyComparator);
         for (final Map.Entry<String, Writer> entry : writers.entrySet()) {
-            final Writer value = entry.getValue();
-            if (isTransient(value, visibility)) {
+            Writer initialWriter = entry.getValue();
+            if (isTransient(initialWriter, visibility)) {
                 continue;
             }
 
+            final Writer finalWriter;
+            if (FieldAndMethodAccessMode.CompositeDecoratedType.class.isInstance(initialWriter)) { // unwrap to use the right reader
+                final FieldAndMethodAccessMode.CompositeDecoratedType decoratedType = FieldAndMethodAccessMode.CompositeDecoratedType.class.cast(initialWriter);
+                final DecoratedType type2 = decoratedType.getType2();
+                if (MethodAccessMode.MethodWriter.class.isInstance(type2)) {
+                    finalWriter = Writer.class.cast(type2);
+                } else {
+                    finalWriter = initialWriter;
+                }
+            } else {
+                finalWriter = initialWriter;
+            }
+
             // we are visible
-            final JsonbProperty property = value.getAnnotation(JsonbProperty.class);
-            final JsonbNillable nillable = value.getClassOrPackageAnnotation(JsonbNillable.class);
+            final JsonbProperty property = initialWriter.getAnnotation(JsonbProperty.class);
+            final JsonbNillable nillable = initialWriter.getClassOrPackageAnnotation(JsonbNillable.class);
             final boolean isNillable = nillable != null || (property != null && property.nillable());
-            final JsonbTypeAdapter adapter = value.getAnnotation(JsonbTypeAdapter.class);
-            final JsonbDateFormat dateFormat = value.getAnnotation(JsonbDateFormat.class);
-            final JsonbNumberFormat numberFormat = value.getAnnotation(JsonbNumberFormat.class);
-            final JsonbValue jsonbValue = value.getAnnotation(JsonbValue.class);
-            validateAnnotations(value, adapter, dateFormat, numberFormat, jsonbValue);
+            final JsonbTypeAdapter adapter = initialWriter.getAnnotation(JsonbTypeAdapter.class);
+            final JsonbDateFormat dateFormat = initialWriter.getAnnotation(JsonbDateFormat.class);
+            final JsonbNumberFormat numberFormat = initialWriter.getAnnotation(JsonbNumberFormat.class);
+            final JsonbValue jsonbValue = initialWriter.getAnnotation(JsonbValue.class);
+            validateAnnotations(initialWriter, adapter, dateFormat, numberFormat, jsonbValue);
 
             final Converter<?> converter;
             try {
-                converter = adapter == null && dateFormat == null && numberFormat == null && jsonbValue == null ? defaultConverters.get(value.getType())  :
-                    toConverter(value.getType(), adapter, dateFormat, numberFormat);
+                converter = adapter == null && dateFormat == null && numberFormat == null && jsonbValue == null ? defaultConverters.get(initialWriter.getType()) :
+                    toConverter(initialWriter.getType(), adapter, dateFormat, numberFormat);
             } catch (final InstantiationException | IllegalAccessException e) {
                 throw new IllegalArgumentException(e);
             }
@@ -397,21 +426,21 @@ public class JsonbAccessMode implements AccessMode {
             // handle optionals since mapper is still only java 7
             final Type type;
             final BiConsumer<Object, Object> writer;
-            if (isOptional(value)) {
-                type = ParameterizedType.class.cast(value.getType()).getActualTypeArguments()[0];
-                writer = (i, val) -> value.write(i, Optional.ofNullable(val));
-            } else if (OptionalInt.class == value.getType()) {
+            if (isOptional(initialWriter)) {
+                type = ParameterizedType.class.cast(initialWriter.getType()).getActualTypeArguments()[0];
+                writer = (i, val) -> finalWriter.write(i, Optional.ofNullable(val));
+            } else if (OptionalInt.class == initialWriter.getType()) {
                 type = int.class;
-                writer = (i, val) -> value.write(i, OptionalInt.of(Number.class.cast(val).intValue()));
-            } else if (OptionalLong.class == value.getType()) {
+                writer = (i, val) -> finalWriter.write(i, OptionalInt.of(Number.class.cast(val).intValue()));
+            } else if (OptionalLong.class == initialWriter.getType()) {
                 type = long.class;
-                writer = (i, val) -> value.write(i, OptionalLong.of(Number.class.cast(val).longValue()));
-            } else if (OptionalDouble.class == value.getType()) {
+                writer = (i, val) -> finalWriter.write(i, OptionalLong.of(Number.class.cast(val).longValue()));
+            } else if (OptionalDouble.class == initialWriter.getType()) {
                 type = double.class;
-                writer = (i, val) -> value.write(i, OptionalDouble.of(Number.class.cast(val).doubleValue()));
+                writer = (i, val) -> finalWriter.write(i, OptionalDouble.of(Number.class.cast(val).doubleValue()));
             } else {
-                type = value.getType();
-                writer = value::write;
+                type = initialWriter.getType();
+                writer = finalWriter::write;
             }
 
             final String key = property == null || property.value().isEmpty() ? naming.translateName(entry.getKey()) : property.value();
@@ -428,12 +457,12 @@ public class JsonbAccessMode implements AccessMode {
 
                 @Override
                 public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
-                    return value.getAnnotation(clazz);
+                    return initialWriter.getAnnotation(clazz);
                 }
 
                 @Override
                 public <T extends Annotation> T getClassOrPackageAnnotation(final Class<T> clazz) {
-                    return value.getClassOrPackageAnnotation(clazz);
+                    return initialWriter.getClassOrPackageAnnotation(clazz);
                 }
 
                 @Override
@@ -457,9 +486,9 @@ public class JsonbAccessMode implements AccessMode {
     }
 
     private boolean isTransient(final DecoratedType dt, final PropertyVisibilityStrategy visibility) {
-        return shouldSkip(visibility, dt) ||
-            (FieldAndMethodAccessMode.CompositeDecoratedType.class.isInstance(dt) &&
-                Stream.of(FieldAndMethodAccessMode.CompositeDecoratedType.class.cast(dt).getType1(), FieldAndMethodAccessMode.CompositeDecoratedType.class.cast(dt).getType2())
+        return shouldSkip(visibility, dt) &&
+            (!FieldAndMethodAccessMode.CompositeDecoratedType.class.isInstance(dt) ||
+                !Stream.of(FieldAndMethodAccessMode.CompositeDecoratedType.class.cast(dt).getType1(), FieldAndMethodAccessMode.CompositeDecoratedType.class.cast(dt).getType2())
                     .map(t -> shouldSkip(visibility, t))
                     .filter(a -> a)
                     .findAny()

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/a409da7d/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/DefaultMappingTest.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/DefaultMappingTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/DefaultMappingTest.java
new file mode 100644
index 0000000..518f8c8
--- /dev/null
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/DefaultMappingTest.java
@@ -0,0 +1,1312 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.jsonb;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonBuilderFactory;
+import javax.json.JsonObject;
+import javax.json.JsonStructure;
+import javax.json.JsonValue;
+import javax.json.bind.Jsonb;
+import javax.json.bind.JsonbBuilder;
+import javax.json.bind.JsonbException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+// taken from the examples of the spec
+// TODO: bunch of asserts
+//CHECKSTYLE:OFF
+public class DefaultMappingTest {
+    private static final Jsonb JSONB = JsonbBuilder.create();
+
+    @Test
+    @Ignore("should it be supported")
+    public void primitives() throws Exception {
+        fromJsonPrimitives();
+        toJsonPrimitives();
+        fromJsonURLURI();
+        toJsonURLURI();
+    }
+
+    @Test
+    public void naming() throws Exception {
+        toJsonDefaultNames();
+        fromJsonDefaultNames();
+    }
+
+    @Test
+    public void collections() {
+        fromJsonCollections();
+        toJsonCollection();
+    }
+
+    @Test
+    public void arrays() {
+        fromJsonArrays();
+        toJsonArrays();
+    }
+
+    @Test
+    public void structures() throws Exception {
+        fromJsonStructures();
+        toJsonStructures();
+    }
+
+    @Test
+    public void pojos() throws Exception {
+        fromJsonPOJOs();
+        toJsonPOJOs();
+    }
+
+    @Test
+    public void inheritance() throws Exception {
+        fromJsonInheritance();
+        toJsonInheritance();
+    }
+
+    @Test
+    public void anonymous() throws Exception {
+        toJsonAnonymousClass();
+    }
+
+    @Test
+    public void instantiation() throws Exception {
+        fromJsonInstantiation();
+    }
+
+    @Test
+    public void order() throws Exception {
+        toJsonAttributesOrdering();
+    }
+
+    @Test
+    public void nulls() throws Exception {
+        toJsonNullValues();
+        fromJsonNullValues();
+    }
+
+    @Test
+    public void modifiers() throws Exception {
+        toJsonModifiers();
+        fromJsonModifiers();
+    }
+
+    @Test
+    public void optionals() throws Exception {
+        toJsonOptional();
+        fromJsonOptional();
+    }
+
+    @Test
+    public void accessors() throws Exception {
+        toJsonAccessors();
+        fromJsonAccessors();
+    }
+
+    public static void fromJsonPrimitives() {
+        //String
+        String str = JSONB.fromJson("\"some_string\"", String.class);
+
+        //String escaping
+        String escapedString = JSONB.fromJson("\" \\\" \\\\ \\/ \\b \\f \\n \\r \\t \\u0039\"", String.class);
+        assertEquals(" \" \\ / \b \f \n \r \t 9", escapedString);
+
+        //Character
+        Character ch = JSONB.fromJson("\"\uFFFF\"", Character.class);
+
+        //Byte
+        Byte byte1 = JSONB.fromJson("1", Byte.class);
+
+        //Short
+        Short short1 = JSONB.fromJson("1", Short.class);
+
+        //Integer
+        Integer int1 = JSONB.fromJson("1", Integer.class);
+
+        //Long
+        Long long1 = JSONB.fromJson("1", Long.class);
+
+        //Float
+        Float float1 = JSONB.fromJson("1.2", Float.class);
+
+        //Double
+        Double double1 = JSONB.fromJson("1.2", Double.class);
+
+        //BigInteger
+        BigInteger bigInteger = JSONB.fromJson("1", BigInteger.class);
+
+        //BigDecimal
+        BigDecimal bigDecimal = JSONB.fromJson("1.2", BigDecimal.class);
+
+        //Number
+        Number number = JSONB.fromJson("1.2", Number.class);
+
+        //Boolean
+        Boolean trueValue = JSONB.fromJson("true", Boolean.class);
+
+        //Boolean
+        Boolean falseValue = JSONB.fromJson("false", Boolean.class);
+
+        //null
+        Object nullValue = JSONB.fromJson("null", Object.class);
+
+        assertTrue(nullValue == null);
+    }
+
+    public static void exceptions() {
+        //Exception
+        //fail fast strategy by default
+
+        //incompatible types
+        try {
+            JSONB.fromJson("not_a_number", Integer.class);
+            assertTrue(false);
+        } catch (JsonbException e) {
+        }
+
+        //incompatible types
+        try {
+            JSONB.fromJson("[null,1]", int[].class);
+            assertTrue(false);
+        } catch (JsonbException e) {
+        }
+
+        //bad structure
+        try {
+            JSONB.fromJson("[1,2", int[].class);
+            assertTrue(false);
+        } catch (JsonbException e) {
+        }
+
+        //overflow - Value out of range
+        try {
+            JSONB.fromJson("" + new Integer(Byte.MAX_VALUE + 1) + "", Byte.class);
+            assertTrue(false);
+        } catch (JsonbException e) {
+        }
+
+        //underflow - Value out of range
+        try {
+            JSONB.fromJson("" + new Integer(Byte.MIN_VALUE - 1) + "", Byte.class);
+            assertTrue(false);
+        } catch (JsonbException e) {
+        }
+    }
+
+    public static void toJsonPrimitives() {
+
+        //String
+        assertEquals("\"some_string\"", JSONB.toJson("some_string"));
+
+        //escaped String
+        assertEquals("\" \\\\ \\\" / \\b \\f \\n \\r \\t 9\"", JSONB.toJson(" \\ \" / \b \f \n \r \t \u0039"));
+
+        //Character
+        assertEquals("\"\uFFFF\"", JSONB.toJson('\uFFFF'));
+
+        //Byte
+        assertEquals("1", JSONB.toJson((byte) 1));
+
+        //Short
+        assertEquals("1", JSONB.toJson((short) 1));
+
+        //Integer
+        assertEquals("1", JSONB.toJson(1));
+
+        //Long
+        assertEquals("5", JSONB.toJson(5L));
+
+        //Float
+        assertEquals("1.2", JSONB.toJson(1.2f));
+
+        //Double
+        assertEquals("1.2", JSONB.toJson(1.2));
+
+        //BigInteger
+        assertEquals("1", JSONB.toJson(new BigInteger("1")));
+
+        //BigDecimal
+        assertEquals("1.2", JSONB.toJson(new BigDecimal("1.2")));
+
+        //Number
+        assertEquals("1.2", JSONB.toJson((java.lang.Number) 1.2));
+
+        //Boolean true
+        assertEquals("true", JSONB.toJson(true));
+
+        //Boolean false
+        assertEquals("false", JSONB.toJson(false));
+
+        //null
+        assertEquals("null", JSONB.toJson(null));
+    }
+
+    public static void fromJsonStructures() {
+
+        //Map
+        Map<String, Object> map = (Map<String, Object>) JSONB.fromJson("{\"name\":\"unknown object\"}", Object.class);
+
+        //mapping for number  -> Integer, Long, BigDecimal
+        Map<String, Object> mapWithBigDecimal = (Map<String, Object>) JSONB.fromJson("{\"intValue\":5,\"longValue\":17179869184,\"otherValue\":1.2}", Object.class);
+        assertTrue(mapWithBigDecimal.get("intValue") instanceof Integer);
+        assertTrue(mapWithBigDecimal.get("longValue") instanceof Long);
+        assertTrue(mapWithBigDecimal.get("otherValue") instanceof BigDecimal);
+
+        //Collection
+        /* why collection and not array or sthg else?
+        Collection<Object> collection = (Collection<Object>) JSONB.fromJson("[{\"value\":\"first\"}, {\"value\":\"second\"}]", Object.class);
+        */
+
+        //JsonStructure
+        assertNotNull(JSONB.fromJson("{\"name\":\"unknown object\"}", JsonStructure.class));
+
+        //JsonObject
+        assertNotNull(JSONB.fromJson("{\"name\":\"unknown object\"}", JsonObject.class));
+
+        //JsonArray
+        assertNotNull(JSONB.fromJson("[{\"value\":\"first\"},{\"value\":\"second\"}]", JsonArray.class));
+
+        //JsonValue
+        // TBD assertNotNull(JSONB.fromJson("1", JsonValue.class));
+    }
+
+    public static void toJsonStructures() {
+
+        JsonBuilderFactory factory = Json.createBuilderFactory(Collections.emptyMap());
+        JsonObject jsonObject = factory.createObjectBuilder().
+            add("name", "home").
+            add("city", "Prague")
+            .build();
+
+        //JsonObject
+        assertEquals("{\"name\":\"home\",\"city\":\"Prague\"}", JSONB.toJson(jsonObject));
+
+        JsonArray jsonArray = factory.createArrayBuilder().add(jsonObject).add(jsonObject).build();
+
+        //JsonArray
+        assertEquals("[{\"name\":\"home\",\"city\":\"Prague\"},{\"name\":\"home\",\"city\":\"Prague\"}]", JSONB.toJson(jsonArray));
+
+        //JsonStructure
+        assertEquals("[{\"name\":\"home\",\"city\":\"Prague\"},{\"name\":\"home\",\"city\":\"Prague\"}]", JSONB.toJson((JsonStructure) jsonArray));
+
+        //JsonValue
+        assertEquals("true", JSONB.toJson(JsonValue.TRUE));
+
+        //Map
+        Map<String, Object> commonMap = new LinkedHashMap<>();
+        commonMap.put("first", 1);
+        commonMap.put("second", 2);
+
+        assertEquals("{\"first\":1,\"second\":2}", JSONB.toJson(commonMap));
+
+        //Collection
+        Collection<Object> commonList = new ArrayList<>();
+        commonList.add(1);
+        commonList.add(2);
+
+        assertEquals("[1,2]", JSONB.toJson(commonList));
+    }
+
+    public static void fromJsonCollections() {
+
+        //support deserialization of java.util.Collection and java.util.Map and its subinterfaces and implementing (sub)classes
+
+        //Collection, Map
+
+        //Set, HashSet, NavigableSet, SortedSet, TreeSet, LinkedHashSet, TreeHashSet
+
+        //HashMap, NavigableMap, SortedMap, TreeMap, LinkedHashMap, TreeHashMap
+
+        //List, ArrayList, LinkedList
+
+        //Deque, ArrayDeque, Queue, PriorityQueue
+
+        Collection<Object> collection = JSONB.fromJson("[\"first\",\"second\"]", Collection.class);
+
+        Map<String, Object> map = JSONB.fromJson("{\"first\":\"second\"}", Map.class);
+
+        //concrete implementation of Map
+        HashMap<String, Object> hashMap = JSONB.fromJson("{\"first\":\"second\"}", HashMap.class);
+
+        //concrete implementation of Collection
+        ArrayList<Object> arrayList = JSONB.fromJson("[\"first\",\"second\"]", ArrayList.class);
+
+        //deque
+        Deque<String> dequeList = JSONB.fromJson("[\"first\",\"second\"]", Deque.class);
+        assertEquals(2, dequeList.size());
+        assertEquals("first", dequeList.getFirst());
+        assertEquals("second", dequeList.getLast());
+
+        //JSON Binding supports default deserialization of the following interfaces
+        //syntax: interface -> default implementation
+
+        //Collection -> ArrayList
+        //Set -> HashSet
+        //NavigableSet -> TreeSet
+        //SortedSet -> TreeSet
+        //Map -> HashMap
+        //SortedMap -> TreeMap
+        //NavigableMap -> TreeMap
+        //Deque -> ArrayDeque
+        //Queue -> ArrayDeque
+
+        //any implementation of Collection and Map with public default constructor is deserializable
+
+    }
+
+    public static void toJsonCollection() {
+        Collection<Integer> collection = Arrays.asList(1, 2, 3);
+
+        assertEquals("[1,2,3]", JSONB.toJson(collection));
+
+        Map<String, Integer> map = new LinkedHashMap<>();
+        map.put("1", 1);
+        map.put("2", 2);
+        map.put("3", 3);
+
+        assertEquals("{\"1\":1,\"2\":2,\"3\":3}", JSONB.toJson(map));
+
+        //any implementation of Collection and Map is serializable
+
+        //deque
+        Deque<String> deque = new ArrayDeque<>();
+        deque.add("first");
+        deque.add("second");
+
+        assertEquals("[\"first\",\"second\"]", JSONB.toJson(deque));
+    }
+
+    public static void fromJsonArrays() {
+
+        //support of arrays of types that JSON Binding is able to deserialize
+        //Byte[], Short[], Integer[] Long[], Float[], Double[], BigInteger[], BigDecimal[], Number[]
+        //Object[], JsonArray[], JsonObject[], JsonStructure[]
+        //String[], Character[]
+        //byte[], short[], int[], long[], float[], double[], char[], boolean[]
+        //java.net.URL[], java.net.URI[]
+        //Map[], Collection[], other collections ...
+        //enum, EnumSet, EnumMap
+        //support of multidimensional arrays
+
+
+        //Several examples
+
+        //Byte arrays
+        Byte[] byteArray = JSONB.fromJson("[1,2]", Byte[].class);
+
+        //Integer array
+        Integer[] integerArray = JSONB.fromJson("[1,2]", Integer[].class);
+
+        //int array
+        int[] intArray = JSONB.fromJson("[1,2]", int[].class);
+
+        //String arrays
+        String[] stringArray = JSONB.fromJson("[\"first\",\"second\"]", String[].class);
+
+        //multidimensional arrays
+        String[][] stringMultiArray = JSONB.fromJson("[[\"first\", \"second\"], [\"third\" , \"fourth\"]]", String[][].class);
+
+        //default mapping should handle multidimensional arrays of types supported by default mapping, e.g. Map
+        Map<String, Object>[][] mapMultiArray = JSONB.fromJson("[[{\"1\":2}, {\"3\":4}],[{\"5\":6},{\"7\":8}]]", Map[][].class);
+    }
+
+    public static void toJsonArrays() {
+
+        //support of arrays of types that JSON Binding is able to serialize
+        //Byte[], Short[], Integer[] Long[], Float[], Double[], BigInteger[], BigDecimal[], Number[]
+        //Object[], JsonArray[], JsonObject[], JsonStructure[]
+        //String[], Character[]
+        //byte[], short[], int[], long[], float[], double[], char[], boolean[]
+        //java.net.URL[], java.net.URI[]
+        //Map[], Collection[], other collections ...
+        //enum, EnumSet, EnumMap
+        //support of multidimensional arrays
+
+
+        //Several examples
+
+        Byte[] byteArray = {1, 2, 3};
+
+        assertEquals("[1,2,3]", JSONB.toJson(byteArray));
+
+        Integer[] integerArray = {1, 2, 3};
+
+        assertEquals("[1,2,3]", JSONB.toJson(integerArray));
+
+        int[] intArray = {1, 2, 3};
+
+        assertEquals("[1,2,3]", JSONB.toJson(intArray));
+
+        String[] stringArray = {"first", "second", "third"};
+
+        assertEquals("[\"first\",\"second\",\"third\"]", JSONB.toJson(stringArray));
+
+        String[][] stringMultiArray = {{"first", "second"}, {"third", "fourth"}};
+
+        assertEquals("[[\"first\",\"second\"],[\"third\",\"fourth\"]]", JSONB.toJson(stringMultiArray));
+
+        Map<String, Object>[][] mapMultiArray = new LinkedHashMap[2][2];
+
+        mapMultiArray[0][0] = new LinkedHashMap<>(1);
+        mapMultiArray[0][0].put("0", 0);
+        mapMultiArray[0][1] = new LinkedHashMap<>(1);
+        mapMultiArray[0][1].put("0", 1);
+        mapMultiArray[1][0] = new LinkedHashMap<>(1);
+        mapMultiArray[1][0].put("1", 0);
+        mapMultiArray[1][1] = new LinkedHashMap<>(1);
+        mapMultiArray[1][1].put("1", 1);
+
+        assertEquals("[[{\"0\":0},{\"0\":1}],[{\"1\":0},{\"1\":1}]]", JSONB.toJson(mapMultiArray));
+    }
+
+    public EnumSet<Language> languageEnumSet = EnumSet.of(Language.Czech);
+    public EnumMap<Language, String> languageEnumMap = new EnumMap<>(Language.class);
+
+    public static void fromJsonEnums() throws Exception {
+
+        EnumSet<Language> languageEnumSet = JSONB.fromJson("[\"Slovak\", \"English\"]", DefaultMappingTest.class.getField("languageEnumSet").getGenericType());
+
+        EnumMap<Language, String> languageEnumMap = JSONB.fromJson("[\"Slovak\" : \"sk\", \"Czech\" : \"cz\"]", DefaultMappingTest.class.getField("languageEnumMap").getGenericType());
+    }
+
+    public static void toJsonEnums() {
+
+        Language language = Language.Slovak;
+
+        assertEquals("\"Slovak\"", JSONB.toJson(language));
+
+        EnumSet<Language> languageEnumSet = EnumSet.of(Language.Czech, Language.Slovak);
+
+        assertEquals("\"Czech\",\"Slovak\"", JSONB.toJson(languageEnumSet));
+
+        EnumMap<Language, String> languageEnumMap = new EnumMap<>(Language.class);
+        languageEnumMap.put(Language.Czech, "cz");
+        languageEnumMap.put(Language.English, "en");
+
+        assertEquals("{\"Czech\":\"cz\",\"English\":\"en\"}", languageEnumMap);
+    }
+
+    private enum Language {
+        English, Slovak, Czech
+    }
+
+    public static void fromJsonPOJOs() {
+
+        POJO pojo = JSONB.fromJson("{\"id\":1, \"name\":\"pojoName\"}", POJO.class);
+
+        POJO nullPOJO = JSONB.fromJson("{\"id\":1, \"name\":null}", POJO.class);
+        assertTrue(null == nullPOJO.name);
+
+        //just public nested class
+        try {
+            POJOWithNestedClass pojoWithNestedClass = JSONB.fromJson("{\"id\":1, \"name\":\"pojo_name\", \"nestedClass\" : {\"nestedId\":2, \"nestedName\" : \"nestedPojoName\"}}", POJOWithNestedClass.class);
+            fail();
+        } catch (final JsonbException e) {
+            // ok
+        }
+
+        //just public nested class
+        try {
+            POJOWithNestedClass.NestedClass nestedClass = JSONB.fromJson("{\"nestedId\":2, \"nestedName\" : \"nestedPojoName\"}", POJOWithNestedClass.NestedClass.class);
+            fail();
+        } catch (final JsonbException e) {
+            // ok
+        }
+
+        POJOWithStaticNestedClass pojoWithStaticNestedClass = JSONB.fromJson("{\"id\":1, \"name\":\"pojoName\"}", POJOWithStaticNestedClass.class);
+
+        POJOWithStaticNestedClass.StaticNestedClass staticNestedClass = JSONB.fromJson("{\"nestedId\":2, \"nestedName\" : \"nestedPojoName\"}", POJOWithStaticNestedClass.StaticNestedClass.class);
+
+        POJOWithMixedFieldAccess pojoWithMixedFieldAccess =
+            JSONB.fromJson("{\"id\":5, \"name\":\"new_name\", \"active\":true}"/*, \"valid\":true}"*/, POJOWithMixedFieldAccess.class);
+
+        assertTrue(pojoWithMixedFieldAccess.id.intValue() == 10);
+        assertTrue(pojoWithMixedFieldAccess.name.equals("new_name"));
+        assertTrue(pojoWithMixedFieldAccess.active);
+        assertNull(pojoWithMixedFieldAccess.valid);
+
+        //composite class
+        CompositePOJO compositePOJO = JSONB.fromJson(
+            "{\"compositeId\":\"13\"," +
+                "\"stringArray\":[\"first\",\"second\"],\"stringList\":[\"one\",\"two\"]}", CompositePOJO.class);
+    }
+
+    public static void toJsonPOJOs() {
+
+        POJO pojo = new POJO();
+        pojo.setId(1);
+        pojo.setName("pojoName");
+
+        assertEquals("{\"id\":1,\"name\":\"pojoName\"}", JSONB.toJson(pojo));
+
+        //pojo with nested class
+        POJOWithNestedClass pojoWithNestedClass = new POJOWithNestedClass();
+        pojoWithNestedClass.setName("pojoName");
+        pojoWithNestedClass.setId(1);
+
+        POJOWithNestedClass.NestedClass nestedClass = pojoWithNestedClass.new NestedClass();
+        nestedClass.setNestedId(2);
+        nestedClass.setNestedName("nestedPojoName");
+
+        pojoWithNestedClass.setNestedClass(nestedClass);
+
+        assertEquals("{\"id\":1,\"name\":\"pojoName\",\"nestedClass\":{\"nestedId\":2,\"nestedName\":\"nestedPojoName\"}}", JSONB.toJson(pojoWithNestedClass));
+
+        //nested class
+        assertEquals("{\"nestedId\":2,\"nestedName\":\"nestedPojoName\"}", JSONB.toJson(nestedClass));
+
+        //pojo with static nested class
+        POJOWithStaticNestedClass pojoWithStaticNestedClass = new POJOWithStaticNestedClass();
+        pojoWithStaticNestedClass.setId(1);
+        pojoWithStaticNestedClass.setName("pojoName");
+
+        assertEquals("{\"id\":1,\"name\":\"pojoName\"}", JSONB.toJson(pojoWithStaticNestedClass));
+
+        //static nested class
+        POJOWithStaticNestedClass.StaticNestedClass staticNestedClass = new POJOWithStaticNestedClass.StaticNestedClass();
+        staticNestedClass.setNestedId(2);
+        staticNestedClass.setNestedName("nestedPojoName");
+
+        assertEquals("{\"nestedId\":2,\"nestedName\":\"nestedPojoName\"}", JSONB.toJson(staticNestedClass));
+
+        POJOWithMixedFieldAccess pojoWithMixedFieldAccess = new POJOWithMixedFieldAccess();
+
+        assertEquals("{\"active\":true,\"id\":2,\"name\":\"pojoName\"}"/*,\"valid\":false}"*/, JSONB.toJson(pojoWithMixedFieldAccess));
+
+        //composite class
+        CompositePOJO compositePOJO = new CompositePOJO();
+        compositePOJO.setCompositeId(13);
+        compositePOJO.setStringArray(new String[]{"first", "second"});
+        compositePOJO.setStringList(Arrays.asList("one", "two"));
+        POJO innerPOJO = new POJO();
+        innerPOJO.setId(4);
+        innerPOJO.setName("innerPOJO");
+        compositePOJO.setInner(innerPOJO);
+
+        assertEquals(
+            "{\"compositeId\":13,\"inner\":{\"id\":4,\"name\":\"innerPOJO\"}," +
+                "\"stringArray\":[\"first\",\"second\"],\"stringList\":[\"one\",\"two\"]}",
+            JSONB.toJson(compositePOJO));
+
+    }
+
+    static class CompositePOJO {
+        private Integer compositeId;
+        private POJO inner;
+        private List<String> stringList;
+        private String[] stringArray;
+
+        public CompositePOJO() {
+        }
+
+        public Integer getCompositeId() {
+            return compositeId;
+        }
+
+        public void setCompositeId(Integer compositeId) {
+            this.compositeId = compositeId;
+        }
+
+        public POJO getInner() {
+            return inner;
+        }
+
+        public void setInner(POJO inner) {
+            this.inner = inner;
+        }
+
+        public List<String> getStringList() {
+            return stringList;
+        }
+
+        public void setStringList(List<String> stringList) {
+            this.stringList = stringList;
+        }
+
+        public String[] getStringArray() {
+            return stringArray;
+        }
+
+        public void setStringArray(String[] stringArray) {
+            this.stringArray = stringArray;
+        }
+    }
+
+    private static class POJO {
+        private Integer id;
+        private String name;
+
+        public POJO() {
+        }
+
+        public Integer getId() {
+            return id;
+        }
+
+        public void setId(Integer id) {
+            this.id = id;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        //other supported attributes
+    }
+
+    private static class POJOWithNestedClass {
+        private Integer id;
+        private String name;
+        private NestedClass nestedClass;
+
+        public POJOWithNestedClass() {
+        }
+
+        public Integer getId() {
+            return id;
+        }
+
+        public void setId(Integer id) {
+            this.id = id;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public NestedClass getNestedClass() {
+            return nestedClass;
+        }
+
+        public void setNestedClass(NestedClass nestedClass) {
+            this.nestedClass = nestedClass;
+        }
+
+        //other supported attributes
+
+        public class NestedClass {
+            private Integer nestedId;
+            private String nestedName;
+
+            public NestedClass() {
+            }
+
+            public Integer getNestedId() {
+                return nestedId;
+            }
+
+            public void setNestedId(Integer nestedId) {
+                this.nestedId = nestedId;
+            }
+
+            public String getNestedName() {
+                return nestedName;
+            }
+
+            public void setNestedName(String nestedName) {
+                this.nestedName = nestedName;
+            }
+        }
+    }
+
+    private static class POJOWithStaticNestedClass {
+        private Integer id;
+        private String name;
+
+        public POJOWithStaticNestedClass() {
+        }
+
+        public Integer getId() {
+            return id;
+        }
+
+        public void setId(Integer id) {
+            this.id = id;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        //other supported attributes
+
+        public static class StaticNestedClass {
+            private Integer nestedId;
+            private String nestedName;
+
+            public StaticNestedClass() {
+            }
+
+            public Integer getNestedId() {
+                return nestedId;
+            }
+
+            public void setNestedId(Integer nestedId) {
+                this.nestedId = nestedId;
+            }
+
+            public String getNestedName() {
+                return nestedName;
+            }
+
+            public void setNestedName(String nestedName) {
+                this.nestedName = nestedName;
+            }
+        }
+    }
+
+    private static class POJOWithMixedFieldAccess {
+        public Integer id = 1;
+        public String name = "pojoName";
+        public Boolean active = false;
+        public Boolean valid = null;
+
+        public Integer getId() {
+            return 2;
+        }
+
+        public void setId(Integer id) {
+            this.id = id * 2;
+        }
+
+        public Boolean getActive() {
+            return true;
+        }
+
+        public void setActive(Boolean active) {
+            this.active = active;
+        }
+
+        public Boolean isValid() {
+            return false;
+        }
+
+        public void setValid(Boolean valid) {
+            this.valid = valid;
+        }
+    }
+
+    private static void fromJsonInheritance() {
+        //we need public constructor
+        Dog animal = JSONB.fromJson("{\"age\":5, \"name\":\"Rex\"}", Dog.class);
+    }
+
+    public static void toJsonInheritance() {
+
+        Dog dog = new Dog();
+        dog.setAge(5);
+        dog.setName("Rex");
+
+        assertEquals("{\"age\":5,\"name\":\"Rex\"}", JSONB.toJson(dog), JSONB.toJson(dog));
+    }
+
+    public static class Animal {
+        int age;
+
+        public Animal() {
+        }
+
+        public int getAge() {
+            return age;
+        }
+
+        public void setAge(int age) {
+            this.age = age;
+        }
+    }
+
+    public static class Dog extends Animal {
+        private String name;
+
+        public Dog() {
+            super();
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+
+    public static void toJsonAnonymousClass() {
+        assertEquals("{\"id\":1,\"name\":\"pojoName\"}", JSONB.toJson(new POJO() {
+            @Override
+            public Integer getId() {
+                return 1;
+            }
+
+            @Override
+            public String getName() {
+                return "pojoName";
+            }
+        }));
+
+    }
+
+    public static void fromJsonURLURI() {
+        java.net.URL url = JSONB.fromJson("\"https://www.jcp.org/en/jsr/detail?id=367#3\"", java.net.URL.class);
+
+        java.net.URI uri = JSONB.fromJson("\"mailto:users@JSONB-spec.java.net\"", java.net.URI.class);
+    }
+
+    public static void toJsonURLURI() throws Exception {
+
+        java.net.URL url = new java.net.URL("https://www.jcp.org/en/jsr/detail?id=367#3");
+
+        assertEquals("\"https://www.jcp.org/en/jsr/detail?id=367#3\"", JSONB.toJson(url));
+
+        java.net.URI uri = new java.net.URI("mailto:users@JSONB-spec.java.net");
+
+        assertEquals("\"mailto:users@JSONB-spec.java.net\"", JSONB.toJson(uri));
+    }
+
+    static class POJOWithoutDefaultArgConstructor {
+        public String id;
+
+        public POJOWithoutDefaultArgConstructor(String id) {
+            this.id = id;
+        }
+    }
+
+    static class POJOWithPrivateConstructor {
+        public String id;
+
+        private POJOWithPrivateConstructor() {
+        }
+    }
+
+    public static void fromJsonInstantiation() {
+
+        //public or protected constructor must be present
+
+        try {
+            POJOWithoutDefaultArgConstructor pojo = JSONB.fromJson("{\"id\":\"1\"}", POJOWithoutDefaultArgConstructor.class);
+            fail();
+        } catch (JsonbException e) {
+        }
+
+        /* TBD: protected or private is the same
+        try {
+            JSONB.fromJson("{\"id\":\"1\"}", POJOWithPrivateConstructor.class);
+            fail();
+        } catch (JsonbException e) {
+        }
+        */
+    }
+
+    public static void toJsonDefaultNames() {
+        DefaultTestNames defaultTestNames = new DefaultTestNames();
+        String result = JSONB.toJson(defaultTestNames);
+        assertEquals("{\"A\":\"A\",\"ABC\":\"ABC\",\"A_Bc\":\"A_Bc\",\"DdB_ee\":\"DdB_ee\",\"_12ac\":\"_12ac\"," +
+            "\"_23_45_a\":\"_23_45_a\",\"_AB\":\"_AB\",\"_ABc\":\"_ABc\",\"_Ab\":\"_Ab\"," +
+            "\"a\":\"a\",\"a_bC\":\"a_bC\",\"abc\":\"abc\",\"okNotOk\":\"okNotOk\"," +
+            "\"okNot_Ok\":\"okNot_Ok\",\"okNot_ok\":\"okNot_ok\"}", result);
+    }
+
+    public static void fromJsonDefaultNames() {
+        DefaultNames defaultNames = JSONB.fromJson("{\"defaultName\":\"newName\"}", DefaultNames.class);
+        assertEquals("newName", defaultNames.defaultName);
+        assertNull(JSONB.fromJson("{\"defaultNAME\":\"newName\"}", DefaultNames.class).defaultName);
+    }
+
+    static class DefaultNames {
+        public String defaultName;
+
+        public DefaultNames() {
+        }
+    }
+
+    static class DefaultTestNames {
+        public String a = "a";
+        public String A = "A";
+        public String ABC = "ABC";
+        public String abc = "abc";
+        public String a_bC = "a_bC";
+        public String A_Bc = "A_Bc";
+        public String _12ac = "_12ac";
+        public String _Ab = "_Ab";
+        public String _AB = "_AB";
+        public String _ABc = "_ABc";
+        public String okNotOk = "okNotOk";
+        public String okNot_Ok = "okNot_Ok";
+        public String okNot_ok = "okNot_ok";
+        public String DdB_ee = "DdB_ee";
+        public String _23_45_a = "_23_45_a";
+    }
+
+    public static void toJsonAttributesOrdering() {
+        //lexicographical order
+        AttributesOrderingClass attributesOrderingClass = new AttributesOrderingClass();
+        attributesOrderingClass.aField = "text";
+        attributesOrderingClass.cField = "text";
+        attributesOrderingClass.bField = "text";
+
+        assertEquals("{\"aField\":\"text\",\"bField\":\"text\",\"cField\":\"text\"}", JSONB.toJson(attributesOrderingClass));
+
+        AttributesOrderingWithInheritance attributesOrderingWithInheritance = new AttributesOrderingWithInheritance();
+        attributesOrderingWithInheritance.aField = "aField";
+        attributesOrderingWithInheritance.cField = "cField";
+        attributesOrderingWithInheritance.bField = "bField";
+        attributesOrderingWithInheritance.aa = "aa";
+        attributesOrderingWithInheritance.cc = "cc";
+        attributesOrderingWithInheritance.bb = "bb";
+
+        assertEquals("{\"aField\":\"aField\",\"aa\":\"aa\",\"bField\":\"bField\",\"bb\":\"bb\",\"cField\":\"cField\",\"cc\":\"cc\"}",
+            JSONB.toJson(attributesOrderingWithInheritance));
+
+        AttributesOrderingWithCounterClass attributesOrderingWithCounterClass = JSONB.fromJson("{\"second\":\"a\",\"third\":\"b\",\"first\":\"c\"}", AttributesOrderingWithCounterClass.class);
+        assertEquals("a1", attributesOrderingWithCounterClass.second);
+        assertEquals("b2", attributesOrderingWithCounterClass.third);
+        assertEquals("c0", attributesOrderingWithCounterClass.first);
+    }
+
+    public static void toJsonNullValues() {
+        //array
+        List<String> stringList = new ArrayList<>();
+        stringList.add("value1");
+        stringList.add(null);
+        stringList.add("value3");
+
+        assertEquals("[\"value1\",null,\"value3\"]", JSONB.toJson(stringList));
+
+        //java object
+        POJO pojo = new POJO();
+        pojo.id = 1;
+        pojo.name = null;
+
+        assertEquals("{\"id\":1}", JSONB.toJson(pojo));
+    }
+
+    public static void fromJsonNullValues() {
+        //array
+        ArrayList<Object> stringList = JSONB.fromJson("[\"value1\",null,\"value3\"]", ArrayList.class);
+        assertTrue(stringList.size() == 3);
+        Iterator<Object> iterator = stringList.iterator();
+        assertEquals("value1", iterator.next());
+        assertTrue(null == iterator.next());
+        assertEquals("value3", iterator.next());
+
+        //java object
+        POJOWithInitialValue pojoWithInitialValue = JSONB.fromJson("{\"name\":\"newName\"}", POJOWithInitialValue.class);
+        assertTrue(pojoWithInitialValue.id.intValue() == 4);
+        assertEquals("newName", pojoWithInitialValue.name);
+
+        POJOWithInitialValue pojoWithNullValue = JSONB.fromJson("{\"name\":\"newName\",\"id\":null}", POJOWithInitialValue.class);
+        assertTrue(pojoWithNullValue.id == null);
+        assertEquals("newName", pojoWithNullValue.name);
+    }
+
+    public static void toJsonModifiers() {
+        ModifiersClass modifiersClass = new ModifiersClass();
+        assertEquals("{\"finalField\":\"finalValue\",\"regularField\":\"regularValue\"}", JSONB.toJson(modifiersClass));
+    }
+
+    public static void fromJsonModifiers() {
+        //deserialization of final field is ignored
+        ModifiersClass modifiersClass = JSONB.fromJson("{\"finalField\":\"newFinalValue\",\"regularField\":\"newRegularValue\"}", ModifiersClass.class);
+        assertEquals("finalValue", modifiersClass.finalField);
+        assertEquals("newRegularValue", modifiersClass.regularField);
+
+        //deserialization of static field is ignored
+        modifiersClass = JSONB.fromJson("{\"staticField\":\"newStaticValue\",\"regularField\":\"newRegularValue\"}", ModifiersClass.class);
+        assertEquals("staticValue", modifiersClass.staticField);
+        assertEquals("newRegularValue", modifiersClass.regularField);
+
+        //deserialization of transient field is ignored
+        modifiersClass = JSONB.fromJson("{\"transientField\":\"newTransientValue\",\"regularField\":\"newRegularValue\"}", ModifiersClass.class);
+        assertEquals("transientValue", modifiersClass.transientField);
+        assertEquals("newRegularValue", modifiersClass.regularField);
+
+        //deserialization of unknown field is ignored
+        modifiersClass = JSONB.fromJson("{\"unknownField\":\"newUnknownValue\",\"regularField\":\"newRegularValue\"}", ModifiersClass.class);
+        assertEquals("newRegularValue", modifiersClass.regularField);
+    }
+
+    public static void toJsonOptional() {
+
+        //Optional
+        /* TBD: direct mapping
+        assertEquals("\"strValue\"", JSONB.toJson(Optional.of("strValue")));
+
+
+        assertEquals("null", JSONB.toJson(Optional.ofNullable(null)));
+
+        assertEquals("null", JSONB.toJson(Optional.empty()));
+
+        //OptionalInt
+        assertEquals("1", JSONB.toJson(OptionalInt.of(1)));
+        assertEquals("null", JSONB.toJson(OptionalInt.empty()));
+
+        //OptionalLong
+        assertEquals("123", JSONB.toJson(OptionalLong.of(123)));
+        assertEquals("null", JSONB.toJson(OptionalLong.empty()));
+
+        //OptionalDouble
+        assertEquals("1.2", JSONB.toJson(OptionalDouble.of(1.2)));
+        assertEquals("null", JSONB.toJson(OptionalDouble.empty()));
+        */
+
+        final OptionalClass object = new OptionalClass();
+        object.optionalField = Optional.of("test");
+        assertEquals("{\"optionalField\":\"test\"}", JSONB.toJson(object));
+
+        OptionalClass optionalClass = new OptionalClass();
+        optionalClass.optionalField = Optional.of("value");
+
+        assertEquals("{\"optionalField\":\"value\"}", JSONB.toJson(optionalClass));
+
+        OptionalClass nullOptionalField = new OptionalClass();
+        nullOptionalField.optionalField = null;
+
+        assertEquals("{}", JSONB.toJson(nullOptionalField));
+    }
+
+    public static void fromJsonOptional() {
+        /* TBD
+        //Optional
+        Optional<String> stringValue = JSONB.fromJson("\"optionalString\"", Optional.class);
+        assertTrue(stringValue.isPresent());
+        assertEquals("optionalString", stringValue.get());
+
+        Optional<String> nullStringValue = JSONB.fromJson("null", Optional.class);
+        assertTrue(!nullStringValue.isPresent());
+
+        //OptionalInt
+        OptionalInt optionalInt = JSONB.fromJson("1", OptionalInt.class);
+        assertTrue(optionalInt.isPresent());
+        assertTrue(optionalInt.getAsInt() == 1);
+
+        OptionalInt emptyOptionalInt = JSONB.fromJson("null", OptionalInt.class);
+        assertTrue(!emptyOptionalInt.isPresent());
+
+        //OptionalLong
+        OptionalLong optionalLong = JSONB.fromJson("123", OptionalLong.class);
+        assertTrue(optionalLong.isPresent());
+        assertTrue(optionalLong.getAsLong() == 123L);
+
+        OptionalLong emptyOptionalLong = JSONB.fromJson("null", OptionalLong.class);
+        assertTrue(!emptyOptionalLong.isPresent());
+
+        //OptionalDouble
+        OptionalDouble optionalDouble = JSONB.fromJson("1.2", OptionalDouble.class);
+        assertTrue(optionalDouble.isPresent());
+        assertTrue(optionalDouble.getAsDouble() == 1.2);
+
+        OptionalDouble emptyOptionalDouble = JSONB.fromJson("null", OptionalDouble.class);
+        assertTrue(!emptyOptionalDouble.isPresent());
+        */
+
+        OptionalClass optionalClass = JSONB.fromJson("{\"optionalField\":\"value\"}", OptionalClass.class);
+        assertTrue(optionalClass.optionalField.isPresent());
+        assertEquals("value", optionalClass.optionalField.get());
+
+        OptionalClass emptyOptionalClass = JSONB.fromJson("{}", OptionalClass.class);
+        assertTrue(!emptyOptionalClass.optionalField.isPresent());
+
+        OptionalClass nullOptionalClass = JSONB.fromJson("{\"optionalField\":null}", OptionalClass.class);
+        assertFalse(nullOptionalClass.optionalField.isPresent());
+    }
+
+    public static void toJsonAccessors() {
+
+        AccessorsClass accessorsClass = new AccessorsClass();
+        accessorsClass.setPrivateFieldWithPrivateAccessors(1);
+        accessorsClass.setPrivateFieldWithPublicAccessors(2);
+        accessorsClass.publicField = 3;
+
+        assertEquals("{\"privateFieldWithPublicAccessors\":2,\"publicField\":3,\"valueWithoutField\":1}", JSONB.toJson(accessorsClass));
+    }
+
+    public static void fromJsonAccessors() {
+        AccessorsClass accessorsClass = JSONB.fromJson(
+            "{\"privateFieldWithPrivateAccessors\":5,\"valueWithoutField\":7," +
+                "\"unknownValue\":11,\"transientValue\":9,\"privateFieldWithPublicAccessors\":4,\"publicField\":9," +
+                "\"protectedField\":8,\"defaultField\":13,\"privateField\":17}",
+            AccessorsClass.class);
+
+        assertEquals(7, accessorsClass.transientValue.intValue());
+        assertEquals(4, accessorsClass.privateFieldWithPublicAccessors.intValue());
+        assertEquals(9, accessorsClass.publicField.intValue());
+        assertNull(accessorsClass.privateFieldWithPrivateAccessors);
+        assertNull(accessorsClass.privateField);
+        assertNull(accessorsClass.defaultField);
+        assertNull(accessorsClass.protectedField);
+    }
+
+    static class AccessorsClass {
+        private Integer privateField;
+
+        protected Integer protectedField;
+
+        Integer defaultField;
+
+        public Integer publicField;
+
+        public transient Integer transientValue;
+
+        private Integer privateFieldWithPrivateAccessors;
+
+        private Integer privateFieldWithPublicAccessors;
+
+        private Integer getPrivateFieldWithPrivateAccessors() {
+            return privateFieldWithPrivateAccessors;
+        }
+
+        private void setPrivateFieldWithPrivateAccessors(Integer privateFieldWithPrivateAccessors) {
+            this.privateFieldWithPrivateAccessors = privateFieldWithPrivateAccessors;
+        }
+
+        public Integer getPrivateFieldWithPublicAccessors() {
+            return privateFieldWithPublicAccessors;
+        }
+
+        public void setPrivateFieldWithPublicAccessors(Integer privateFieldWithPublicAccessors) {
+            this.privateFieldWithPublicAccessors = privateFieldWithPublicAccessors;
+        }
+
+        public Integer getValueWithoutField() {
+            return 1;
+        }
+
+        public void setValueWithoutField(Integer valueWithoutField) {
+            transientValue = valueWithoutField;
+        }
+    }
+
+    static class OptionalClass {
+        public Optional<String> optionalField = Optional.empty();
+
+        public OptionalClass() {
+        }
+    }
+
+    static class ModifiersClass {
+        public final String finalField = "finalValue";
+        public static String staticField = "staticValue";
+        public transient String transientField = "transientValue";
+        public String regularField = "regularValue";
+
+        public ModifiersClass() {
+        }
+    }
+
+    static class POJOWithInitialValue {
+        public Integer id = 4;
+        public String name;
+
+        public POJOWithInitialValue() {
+        }
+    }
+
+    static class AttributesOrderingClass {
+        public String aField;
+        public String cField;
+        public String bField;
+
+        public AttributesOrderingClass() {
+        }
+    }
+
+    static class AttributesOrderingWithInheritance extends AttributesOrderingClass {
+        public String aa;
+        public String cc;
+        public String bb;
+
+        public AttributesOrderingWithInheritance() {
+        }
+    }
+
+    static class AttributesOrderingWithCounterClass {
+        private transient int counter = 0;
+
+        private String first = "first";
+
+        private String second = "second";
+
+        private String third = "third";
+
+        public AttributesOrderingWithCounterClass() {
+        }
+
+        public String getFirst() {
+            return first;
+        }
+
+        public void setFirst(String first) {
+            this.first = first + (counter++);
+        }
+
+        public String getSecond() {
+            return second;
+        }
+
+        public void setSecond(String second) {
+            this.second = second + (counter++);
+        }
+
+        public String getThird() {
+            return third;
+        }
+
+        public void setThird(String third) {
+            this.third = third + (counter++);
+        }
+    }
+//CHECKSTYLE:ON
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/a409da7d/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
index 0bc1a26..ac3e6b3 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
@@ -18,6 +18,7 @@
  */
 package org.apache.johnzon.mapper;
 
+import org.apache.johnzon.core.JsonLongImpl;
 import org.apache.johnzon.mapper.access.AccessMode;
 import org.apache.johnzon.mapper.converter.EnumConverter;
 import org.apache.johnzon.mapper.reflection.JohnzonCollectionType;
@@ -36,6 +37,7 @@ import javax.json.JsonValue.ValueType;
 import javax.json.stream.JsonGenerator;
 import javax.json.stream.JsonGeneratorFactory;
 import javax.xml.bind.DatatypeConverter;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
@@ -292,6 +294,28 @@ public class Mapper {
     }
 
     public void writeObject(final Object object, final Writer stream) {
+        if (JsonValue.class.isInstance(object)) {
+            try {
+                stream.write(object.toString());
+            } catch (final IOException e) {
+                throw new MapperException(e);
+            } finally {
+                if (close) {
+                    try {
+                        stream.close();
+                    } catch (final IOException e) {
+                        // no-op
+                    }
+                } else {
+                    try {
+                        stream.flush();
+                    } catch (final IOException e) {
+                        // no-op
+                    }
+                }
+            }
+            return;
+        }
         final JsonGenerator generator = generatorFactory.createGenerator(stream);
         doWriteHandlingNullObject(object, generator);
     }
@@ -324,6 +348,15 @@ public class Mapper {
             generator.writeStartObject().writeEnd().close();
             return;
         }
+        if (JsonObject.class.isInstance(object)) {
+            final JsonObject jsonObject = JsonObject.class.cast(object);
+            generator.writeStartObject();
+            for (final Map.Entry<String, JsonValue> value  : jsonObject.entrySet()) {
+                generator.write(value.getKey(), value.getValue());
+            }
+            generator.writeEnd().close();
+            return;
+        }
 
         //JsonGenerator gen = null;
         try {
@@ -499,6 +532,8 @@ public class Mapper {
                     }
                     newGen = newGen.writeEnd();
                 }
+            } else if (o == null) {
+                newGen = generator.writeNull();
             } else {
                 newGen = doWriteObject(generator, o);
             }
@@ -520,7 +555,11 @@ public class Mapper {
 
     private <T> T mapObject(final Type clazz, final JsonReader reader) {
         try {
-            return (T) buildObject(clazz, reader.readObject());
+            final JsonObject object = reader.readObject();
+            if (JsonStructure.class == clazz || JsonObject.class == clazz) {
+                return (T) object;
+            }
+            return (T) buildObject(clazz, object);
         } catch (final Exception e) {
             throw new MapperException(e);
         } finally {
@@ -574,17 +613,27 @@ public class Mapper {
 
     public <T> T[] readArray(final Reader stream, final Class<T> clazz) {
         final JsonReader reader = readerFactory.createReader(stream);
-        return mapArray(clazz, reader);
+        return (T[]) mapArray(clazz, reader);
+    }
+
+    public <T> T readTypedArray(final InputStream stream, final Class<?> elementType, final Class<T> arrayType) {
+        final JsonReader reader = readerFactory.createReader(stream);
+        return arrayType.cast(mapArray(elementType, reader));
+    }
+
+    public <T> T readTypedArray(final Reader stream, final Class<?> elementType, final Class<T> arrayType) {
+        final JsonReader reader = readerFactory.createReader(stream);
+        return arrayType.cast(mapArray(elementType, reader));
     }
 
     public <T> T[] readArray(final InputStream stream, final Class<T> clazz) {
         final JsonReader reader = readerFactory.createReader(stream);
-        return mapArray(clazz, reader);
+        return (T[]) mapArray(clazz, reader);
     }
 
-    private <T> T[] mapArray(final Class<T> clazz, final JsonReader reader) {
+    private Object mapArray(final Class<?> clazz, final JsonReader reader) {
         try {
-            return (T[]) buildArrayWithComponentType(reader.readArray(), clazz, null);
+            return buildArrayWithComponentType(reader.readArray(), clazz, null);
         } catch (final Exception e) {
             throw new MapperException(e);
         } finally {
@@ -633,18 +682,46 @@ public class Mapper {
                             keyType = fieldArgTypes[0];
                         }
 
+                        final boolean any = fieldArgTypes.length < 2 || fieldArgTypes[1] == Object.class;
                         for (final Map.Entry<String, JsonValue> value : object.entrySet()) {
-                            map.put(convertTo(keyType, value.getKey()), toObject(value.getValue(), fieldArgTypes[1], null));
+                            final JsonValue jsonValue = value.getValue();
+                            if (JsonLongImpl.class.isInstance(jsonValue) && any) {
+                                final JsonNumber number = JsonNumber.class.cast(jsonValue);
+                                final int integer = number.intValue();
+                                final long asLong = number.longValue();
+                                if (integer == asLong) {
+                                    map.put(value.getKey(), integer);
+                                } else {
+                                    map.put(value.getKey(), asLong);
+                                }
+                            } else if (JsonNumber.class.isInstance(jsonValue) && any) {
+                                final JsonNumber number = JsonNumber.class.cast(jsonValue);
+                                map.put(value.getKey(), !number.isIntegral() ? number.bigDecimalValue() : number.intValue());
+                            } else if (JsonString.class.isInstance(jsonValue) && any) {
+                                map.put(value.getKey(), JsonString.class.cast(jsonValue).getString());
+                            } else {
+                                map.put(convertTo(keyType, value.getKey()), toObject(jsonValue, fieldArgTypes[1], null));
+                            }
                         }
                         return map;
                     }
                 }
+            } else if (Map.class == type || HashMap.class == type || LinkedHashMap.class == type) {
+                final LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
+                for (final Map.Entry<String, JsonValue> value : object.entrySet()) {
+                    map.put(value.getKey(), toObject(value.getValue(), Object.class, null));
+                }
+                return map;
             }
         }
         if (classMapping == null) {
             throw new MapperException("Can't map " + type);
         }
 
+        if (classMapping.factory == null) {
+            throw new IllegalArgumentException(classMapping.clazz + " not instantiable");
+        }
+
         final Object t = classMapping.factory.getParameterTypes().length == 0 ?
                 classMapping.factory.create(null) : classMapping.factory.create(createParameters(classMapping, object));
         for (final Map.Entry<String, Mappings.Setter> setter : classMapping.setters.entrySet()) {
@@ -659,9 +736,13 @@ public class Mapper {
             }
 
             final AccessMode.Writer setterMethod = value.writer;
-            final Object convertedValue = toValue(jsonValue, value.converter, value.itemConverter, value.paramType);
-            if (convertedValue != null) {
-                setterMethod.write(t, convertedValue);
+            if (jsonValue == JsonValue.NULL) { // forced
+                setterMethod.write(t, null);
+            } else {
+                final Object convertedValue = toValue(jsonValue, value.converter, value.itemConverter, value.paramType);
+                if (convertedValue != null) {
+                    setterMethod.write(t, convertedValue);
+                }
             }
         }
 
@@ -687,7 +768,7 @@ public class Mapper {
     }
 
     private Object toObject(final JsonValue jsonValue, final Type type, final Converter<?> itemConverter) throws Exception {
-        if (jsonValue == null || jsonValue == JsonValue.NULL) {
+        if (jsonValue == null || JsonValue.NULL == jsonValue) {
             return null;
         }
 
@@ -773,7 +854,7 @@ public class Mapper {
             if (type == BigDecimal.class) {
                 return number.bigDecimalValue();
             }
-        } else if (JsonString.class.isInstance(jsonValue) || Object.class == type) {
+        } else if (JsonString.class.isInstance(jsonValue)) {
             if (JsonString.class == type) {
                 return jsonValue;
             }
@@ -820,7 +901,7 @@ public class Mapper {
             collection = new TreeSet<T>();
         } else if (Set.class == mapping.raw || HashSet.class == mapping.raw) {
             collection = new HashSet<T>(jsonArray.size());
-        } else if (Queue.class == mapping.raw) {
+        } else if (Queue.class == mapping.raw || ArrayBlockingQueue.class == mapping.raw) {
             collection = new ArrayBlockingQueue<T>(jsonArray.size());
         } else if (List.class == mapping.raw || Collection.class == mapping.raw || ArrayList.class == mapping.raw || EnumSet.class == mapping.raw) {
             collection = new ArrayList<T>(jsonArray.size());
@@ -835,7 +916,7 @@ public class Mapper {
         }
 
         for (final JsonValue value : jsonArray) {
-            collection.add(toObject(value, mapping.arg, itemConverter));
+            collection.add(value == JsonValue.NULL ? null : toObject(value, mapping.arg, itemConverter));
         }
 
         if (EnumSet.class == mapping.raw) {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/a409da7d/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
index 8a3a359..b89a01d 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
@@ -22,6 +22,7 @@ import org.apache.johnzon.mapper.Converter;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
+import java.util.Comparator;
 import java.util.Map;
 
 public interface AccessMode {
@@ -50,6 +51,7 @@ public interface AccessMode {
     }
 
     Factory findFactory(Class<?> clazz);
+    Comparator<String> fieldComparator(Class<?> clazz);
     Map<String, Reader> findReaders(Class<?> clazz);
     Map<String, Writer> findWriters(Class<?> clazz);
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/a409da7d/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java
index 94642bf..70ab5af 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java
@@ -32,6 +32,7 @@ import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -58,6 +59,11 @@ public abstract class BaseAccessMode implements AccessMode {
     protected abstract Map<String,Writer> doFindWriters(Class<?> clazz);
 
     @Override
+    public Comparator<String> fieldComparator(final Class<?> clazz) {
+        return null;
+    }
+
+    @Override
     public Map<String, Reader> findReaders(final Class<?> clazz) {
         return sanitize(clazz, doFindReaders(clazz));
     }
@@ -240,8 +246,9 @@ public abstract class BaseAccessMode implements AccessMode {
             return clazz;
         }
 
-        if (clazz.getSuperclass() != Object.class) {
-            return findClass(clazz.getSuperclass(), genericDeclaration);
+        final Class<?> superclass = clazz.getSuperclass();
+        if (superclass != null && superclass != Object.class) {
+            return findClass(superclass, genericDeclaration);
         }
 
         return null;