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/06 18:45:57 UTC

[1/3] incubator-johnzon git commit: JOHNZON-61 bases for jsonb, still a lot of tests to add but allows to review more efficiently the early draft

Repository: incubator-johnzon
Updated Branches:
  refs/heads/master 6443633f7 -> b65d149a5


http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/config/PropertyOrderStrategy.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/config/PropertyOrderStrategy.java b/jsonb-api/src/main/java/javax/json/bind/config/PropertyOrderStrategy.java
new file mode 100644
index 0000000..5db8c0e
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/config/PropertyOrderStrategy.java
@@ -0,0 +1,29 @@
+/*
+ * 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 javax.json.bind.config;
+
+public final class PropertyOrderStrategy {
+    private PropertyOrderStrategy() {
+        // no-op
+    }
+
+    public static final String LEXICOGRAPHICAL = "LEXICOGRAPHICAL";
+    public static final String ANY = "ANY";
+    public static final String REVERSE = "REVERSE";
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/config/PropertyVisibilityStrategy.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/config/PropertyVisibilityStrategy.java b/jsonb-api/src/main/java/javax/json/bind/config/PropertyVisibilityStrategy.java
new file mode 100644
index 0000000..14f915e
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/config/PropertyVisibilityStrategy.java
@@ -0,0 +1,27 @@
+/*
+ * 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 javax.json.bind.config;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+public interface PropertyVisibilityStrategy {
+    boolean isVisible(Field field);
+    boolean isVisible(Method method);
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/spi/JsonbProvider.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/spi/JsonbProvider.java b/jsonb-api/src/main/java/javax/json/bind/spi/JsonbProvider.java
new file mode 100644
index 0000000..8c75a4b
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/spi/JsonbProvider.java
@@ -0,0 +1,59 @@
+/*
+ * 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 javax.json.bind.spi;
+
+import javax.json.bind.JsonbBuilder;
+import javax.json.bind.JsonbException;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+public abstract class JsonbProvider {
+    private static final String DEFAULT_PROVIDER = "org.apache.johnzon.jsonb.JohnzonProvider";
+
+    public static JsonbProvider provider() {
+        final Iterator<JsonbProvider> it = ServiceLoader.load(JsonbProvider.class).iterator();
+        if (it.hasNext()) {
+            return it.next();
+        }
+
+        try {
+            return JsonbProvider.class.cast(Thread.currentThread().getContextClassLoader().loadClass(DEFAULT_PROVIDER).newInstance());
+        } catch (final ClassNotFoundException cnfe) {
+            throw new JsonbException(DEFAULT_PROVIDER + " not found", cnfe);
+        } catch (final Exception x) {
+            throw new JsonbException(DEFAULT_PROVIDER + " couldn't be instantiated: " + x, x);
+        }
+    }
+
+    public static JsonbProvider provider(final String providerFqn) {
+        if (providerFqn == null) {
+            throw new IllegalArgumentException();
+        }
+        for (final JsonbProvider provider : ServiceLoader.load(JsonbProvider.class)) {
+            if (providerFqn.equals(provider.getClass().getName())) {
+                return provider;
+            }
+        }
+
+        final String msg = providerFqn + " not found";
+        throw new JsonbException(msg, new ClassNotFoundException(msg));
+    }
+
+    public abstract JsonbBuilder create();
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 5cb8afd..2355ab0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -47,6 +47,7 @@
     <staging.directory>${project.build.directory}/site</staging.directory>
     <felix.plugin.version>2.5.3</felix.plugin.version>
     <bnd.version.policy>[$(version;==;$(@)),$(version;+;$(@)))</bnd.version.policy>
+    <java-compile.version>1.6</java-compile.version>
   </properties>
 
   <modules>
@@ -79,8 +80,8 @@
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <configuration>
-          <source>1.6</source>
-          <target>1.6</target>
+          <source>${java-compile.version}</source>
+          <target>${java-compile.version}</target>
           <encoding>UTF-8</encoding>
           <showDeprecation>true</showDeprecation>
           <showWarnings>true</showWarnings>
@@ -102,7 +103,7 @@
             <exclude>*.iws</exclude>
             <exclude>*.iml</exclude>
             <exclude>*.ipr</exclude>
-            <exclude>**/META-INF/services/javax.json.spi.JsonProvider</exclude>
+            <exclude>**/META-INF/services/javax.*</exclude>
             <exclude>**/*.json</exclude>
             <exclude>**/*.yml</exclude>
             <exclude>**/bench/*.txt</exclude>
@@ -159,7 +160,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
-        <version>2.13</version>
+        <version>2.17</version>
         <executions>
           <execution>
             <id>verify-style</id>
@@ -302,7 +303,7 @@
             <localCheckout>true</localCheckout>
             <autoVersionSubmodules>true</autoVersionSubmodules>
           </configuration>
-       </plugin>       
+       </plugin>
        <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>cobertura-maven-plugin</artifactId>
@@ -351,7 +352,7 @@
                   <version>[3.1,)</version>
                 </requireMavenVersion>
                 <requireJavaVersion>
-                  <version>[1.6,)</version>
+                  <version>[${java-compile.version},)</version>
                 </requireJavaVersion>
               </rules>
             </configuration>
@@ -372,7 +373,7 @@
       <url>${pubsub.url}</url>
     </site>
   </distributionManagement>
-  
+
   <scm>
     <connection>scm:git:https://git-wip-us.apache.org/repos/asf/incubator-johnzon.git</connection>
     <developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/incubator-johnzon.git</developerConnection>
@@ -550,7 +551,7 @@
       </otherArchives>
     </mailingList>
   </mailingLists>
-  
+
   <ciManagement>
     <system>jenkins</system>
     <url>https://builds.apache.org/job/johnzon/</url>
@@ -647,5 +648,16 @@
                 <module>johnzon-websocket</module>
             </modules>
         </profile>
+        <profile>
+            <!-- jsonb module needs java 1.8 or higher -->
+            <id>jdk1.8+</id>
+            <activation>
+                <jdk>[1.8,)</jdk>
+            </activation>
+            <modules>
+              <module>jsonb-api</module>
+              <module>johnzon-jsonb</module>
+            </modules>
+        </profile>
     </profiles>
 </project>


[2/3] incubator-johnzon git commit: JOHNZON-61 bases for jsonb, still a lot of tests to add but allows to review more efficiently the early draft

Posted by rm...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/PropertyNamingStrategyFactoryTest.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/PropertyNamingStrategyFactoryTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/PropertyNamingStrategyFactoryTest.java
new file mode 100644
index 0000000..d9d14ed
--- /dev/null
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/PropertyNamingStrategyFactoryTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+
+import javax.json.bind.config.PropertyNamingStrategy;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Theories.class)
+public class PropertyNamingStrategyFactoryTest {
+    @DataPoints()
+    public static String[][] points() {
+        return new String[][] {
+            new String[] { PropertyNamingStrategy.IDENTITY, "a", "a" },
+            new String[] { PropertyNamingStrategy.IDENTITY, "aBEOCBDJ4397dkabqWLCd", "aBEOCBDJ4397dkabqWLCd" },
+            new String[] { PropertyNamingStrategy.CASE_INSENSITIVE, "aBEOCBDJ4397dkabqWLCd", "aBEOCBDJ4397dkabqWLCd" }, // not really testable there
+            new String[] { PropertyNamingStrategy.LOWER_CASE_WITH_DASHES, "lower-dash", "lower-dash" },
+            new String[] { PropertyNamingStrategy.LOWER_CASE_WITH_DASHES, "lower_dash", "lower_dash" },
+            new String[] { PropertyNamingStrategy.LOWER_CASE_WITH_DASHES, "lowerDash", "lower-dash" },
+            new String[] { PropertyNamingStrategy.LOWER_CASE_WITH_UNDERSCORES, "lower_under", "lower_under" },
+            new String[] { PropertyNamingStrategy.LOWER_CASE_WITH_UNDERSCORES, "lowerUnder", "lower_under" },
+            new String[] { PropertyNamingStrategy.UPPER_CAMEL_CASE, "fooBar", "FooBar" },
+            new String[] { PropertyNamingStrategy.UPPER_CAMEL_CASE_WITH_SPACES, "fooBar", "Foo Bar" },
+        };
+    }
+
+    @Theory
+    public void valid(final String[] config) {
+        assertEquals(config[2], new PropertyNamingStrategyFactory(config[0]).create().translateName(config[1]));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/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 8d94bf9..20ac31f 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
@@ -81,25 +81,25 @@ public class Mapper {
     protected final boolean skipNull;
     protected final boolean skipEmptyArray;
     protected final boolean treatByteArrayAsBase64;
+    protected final boolean treatByteArrayAsBase64URL;
     protected final Charset encoding;
 
     // CHECKSTYLE:OFF
     public Mapper(final JsonReaderFactory readerFactory, final JsonGeneratorFactory generatorFactory,
                   final boolean doClose, final Map<Type, Converter<?>> converters,
                   final int version, final Comparator<String> attributeOrder, final boolean skipNull, final boolean skipEmptyArray,
-                  final AccessMode accessMode, final boolean hiddenConstructorSupported, final boolean useConstructors,
-                  final boolean treatByteArrayAsBase64,
-                  final Charset encoding) {
+                  final AccessMode accessMode, final boolean treatByteArrayAsBase64, final boolean treatByteArrayAsBase64URL, final Charset encoding) {
     // CHECKSTYLE:ON
         this.readerFactory = readerFactory;
         this.generatorFactory = generatorFactory;
         this.close = doClose;
         this.converters = new ConcurrentHashMap<Type, Converter<?>>(converters);
         this.version = version;
-        this.mappings = new Mappings(attributeOrder, accessMode, hiddenConstructorSupported, useConstructors, version, this.converters);
+        this.mappings = new Mappings(attributeOrder, accessMode, version, this.converters);
         this.skipNull = skipNull;
         this.skipEmptyArray = skipEmptyArray;
         this.treatByteArrayAsBase64 = treatByteArrayAsBase64;
+        this.treatByteArrayAsBase64URL = treatByteArrayAsBase64URL;
         this.encoding = encoding;
     }
 
@@ -370,7 +370,7 @@ public class Mapper {
             }
 
             if (value == null) {
-                if (skipNull) {
+                if (skipNull && !getter.reader.isNillable()) {
                     continue;
                 } else {
                     gen.writeNull(getterEntry.getKey());
@@ -434,6 +434,9 @@ public class Mapper {
                 generator.write(key, base64EncodedByteArray);
                 return generator;
             }
+            if(treatByteArrayAsBase64URL && (type == byte[].class /*|| type == Byte[].class*/)) {
+                return generator.write(key, Converter.class.cast(converters.get(byte[].class)).toString(value));
+            }
 
             JsonGenerator gen = generator.writeStartArray(key);
             for (int i = 0; i < length; i++) {
@@ -619,12 +622,8 @@ public class Mapper {
             throw new MapperException("Can't map " + type);
         }
 
-        if (classMapping.constructor == null) {
-            throw new IllegalArgumentException(classMapping.clazz.getName() + " can't be instantiated by Johnzon, this is a write only class");
-        }
-
-        final Object t = !classMapping.constructorHasArguments ?
-                classMapping.constructor.newInstance() : classMapping.constructor.newInstance(createParameters(classMapping, object));
+        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()) {
             final JsonValue jsonValue = object.get(setter.getKey());
             if (jsonValue == null) {
@@ -650,11 +649,12 @@ public class Mapper {
     }
 
     private Object[] createParameters(final Mappings.ClassMapping mapping, final JsonObject object) throws Exception {
-        final Object[] objects = new Object[mapping.constructorParameters.length];
-        for (int i = 0; i < mapping.constructorParameters.length; i++) {
+        final int length = mapping.factory.getParameterTypes().length;
+        final Object[] objects = new Object[length];
+        for (int i = 0; i < length; i++) {
             objects[i] = toValue(
-                object.get(mapping.constructorParameters[i]), mapping.constructorParameterConverters[i],
-                mapping.constructorItemParameterConverters[i], mapping.constructorParameterTypes[i]);
+                object.get(mapping.factory.getParameterNames()[i]), mapping.factory.getParameterConverter()[i],
+                mapping.factory.getParameterItemConverter()[i], mapping.factory.getParameterTypes()[i]);
         }
         return objects;
     }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
index cee2841..8f4f1db 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
@@ -92,11 +92,14 @@ public class MapperBuilder {
     private boolean skipEmptyArray = false;
     private boolean supportsComments = false;
     protected boolean pretty;
-    private AccessMode accessMode = new MethodAccessMode(false);
+    private AccessMode accessMode;
     private boolean treatByteArrayAsBase64;
+    private boolean treatByteArrayAsBase64URL;
     private final Map<Type, Converter<?>> converters = new HashMap<Type, Converter<?>>(DEFAULT_CONVERTERS);
     private boolean supportConstructors;
     private Charset encoding = Charset.forName(System.getProperty("johnzon.mapper.encoding", "UTF-8"));
+    private boolean useGetterForCollections;
+    private String accessModeName;
 
     public Mapper build() {
         if (readerFactory == null || generatorFactory == null) {
@@ -128,6 +131,20 @@ public class MapperBuilder {
             }
         }
 
+        if (accessMode == null) {
+            if ("field".equalsIgnoreCase(accessModeName)) {
+                this.accessMode = new FieldAccessMode(supportConstructors, supportHiddenAccess);
+            } else if ("method".equalsIgnoreCase(accessModeName)) {
+                this.accessMode = new MethodAccessMode(supportConstructors, supportHiddenAccess, true);
+            } else if ("strict-method".equalsIgnoreCase(accessModeName)) {
+                this.accessMode = new MethodAccessMode(supportConstructors, supportHiddenAccess, false);
+            } else if ("both".equalsIgnoreCase(accessModeName)) {
+                this.accessMode = new FieldAndMethodAccessMode(supportConstructors, supportHiddenAccess);
+            } else {
+                this.accessMode = new MethodAccessMode(supportConstructors, supportHiddenAccess, useGetterForCollections);
+            }
+        }
+
         return new Mapper(
                 readerFactory, generatorFactory,
                 doCloseOnStreams,
@@ -136,9 +153,7 @@ public class MapperBuilder {
                 attributeOrder,
                 skipNull, skipEmptyArray,
                 accessMode,
-                supportHiddenAccess,
-                supportConstructors,
-                treatByteArrayAsBase64,
+                treatByteArrayAsBase64, treatByteArrayAsBase64URL,
                 encoding);
     }
 
@@ -156,7 +171,7 @@ public class MapperBuilder {
     }
 
     public MapperBuilder setSupportGetterForCollections(final boolean useGetterForCollections) {
-        accessMode = new MethodAccessMode(useGetterForCollections);
+        this.useGetterForCollections = useGetterForCollections;
         return this;
     }
 
@@ -191,17 +206,11 @@ public class MapperBuilder {
     }
 
     public MapperBuilder setAccessModeName(final String mode) {
-        if ("field".equalsIgnoreCase(mode)) {
-            this.accessMode = new FieldAccessMode();
-        } else if ("method".equalsIgnoreCase(mode)) {
-            this.accessMode = new MethodAccessMode(true);
-        } else if ("strict-method".equalsIgnoreCase(mode)) {
-            this.accessMode = new MethodAccessMode(false);
-        } else if ("both".equalsIgnoreCase(mode)) {
-            this.accessMode = new FieldAndMethodAccessMode();
-        } else {
+        if (!"field".equalsIgnoreCase(mode) && !"method".equalsIgnoreCase(mode) &&
+            !"strict-method".equalsIgnoreCase(mode) && !"both".equalsIgnoreCase(mode)) {
             throw new IllegalArgumentException("Mode " + mode + " unsupported");
         }
+        this.accessModeName = mode;
         return this;
     }
 
@@ -261,6 +270,11 @@ public class MapperBuilder {
         return this;
     }
 
+    public MapperBuilder setTreatByteArrayAsBase64URL(final boolean treatByteArrayAsBase64URL) {
+        this.treatByteArrayAsBase64URL = treatByteArrayAsBase64URL;
+        return this;
+    }
+
     public MapperBuilder setSupportConstructors(final boolean supportConstructors) {
         this.supportConstructors = supportConstructors;
         return this;

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/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 37b675b..038c9a9 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
@@ -18,6 +18,8 @@
  */
 package org.apache.johnzon.mapper.access;
 
+import org.apache.johnzon.mapper.Converter;
+
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 import java.util.Map;
@@ -26,6 +28,8 @@ public interface AccessMode {
     interface DecoratedType {
         Type getType();
         <T extends Annotation> T getAnnotation(Class<T> clazz);
+        Converter<?> findConverter();
+        boolean isNillable();
     }
 
     interface Writer extends DecoratedType {
@@ -36,6 +40,15 @@ public interface AccessMode {
         Object read(Object instance);
     }
 
+    interface Factory {
+        Object create(Object[] params);
+        Type[] getParameterTypes();
+        String[] getParameterNames();
+        Converter<?>[] getParameterConverter();
+        Converter<?>[] getParameterItemConverter();
+    }
+
+    Factory findFactory(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/b65d149a/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 2260881..94642bf 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
@@ -18,9 +18,16 @@
  */
 package org.apache.johnzon.mapper.access;
 
+import org.apache.johnzon.mapper.Converter;
+import org.apache.johnzon.mapper.JohnzonConverter;
 import org.apache.johnzon.mapper.reflection.JohnzonParameterizedType;
 
+import java.beans.ConstructorProperties;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
@@ -29,12 +36,21 @@ import java.util.HashMap;
 import java.util.Map;
 
 import static java.util.Arrays.asList;
+import static org.apache.johnzon.mapper.reflection.Converters.matches;
 
 // handle some specific types
 public abstract class BaseAccessMode implements AccessMode {
+    private static final Type[] NO_PARAMS = new Type[0];
+
     private final Map<Class<?>, String[]> fieldsToRemove = new HashMap<Class<?>, String[]>();
+    private final boolean acceptHiddenConstructor;
+    private final boolean useConstructor;
+
+    protected BaseAccessMode(final boolean useConstructor, final boolean acceptHiddenConstructor) {
+        this.useConstructor = useConstructor;
+        this.acceptHiddenConstructor = acceptHiddenConstructor;
 
-    public BaseAccessMode() { // mainly built it in the JVM types == user cant handle them
+        // mainly built it in the JVM types == user cant handle them
         fieldsToRemove.put(Throwable.class, new String[]{"suppressedExceptions", "cause"});
     }
 
@@ -56,6 +72,113 @@ public abstract class BaseAccessMode implements AccessMode {
         return fieldsToRemove;
     }
 
+    @Override
+    public Factory findFactory(final Class<?> clazz) {
+        Constructor<?> constructor = null;
+        for (final Constructor<?> c : clazz.getDeclaredConstructors()) {
+            if (c.getParameterTypes().length == 0) {
+                if (!Modifier.isPublic(c.getModifiers()) && acceptHiddenConstructor) {
+                    c.setAccessible(true);
+                }
+                constructor = c;
+                if (!useConstructor) {
+                    break;
+                }
+            } else if (c.getAnnotation(ConstructorProperties.class) != null) {
+                constructor = c;
+                break;
+            }
+        }
+        if (constructor == null) {
+            try {
+                constructor = clazz.getConstructor();
+            } catch (final NoSuchMethodException e) {
+                return null; // readOnly class
+            }
+        }
+
+        final boolean constructorHasArguments = constructor != null && constructor.getGenericParameterTypes().length > 0;
+        final Type[] factoryParameterTypes;
+        final String[] constructorParameters;
+        final Converter<?>[] constructorParameterConverters;
+        final Converter<?>[] constructorItemParameterConverters;
+        if (constructorHasArguments) {
+            factoryParameterTypes = constructor.getGenericParameterTypes();
+
+            constructorParameters = new String[constructor.getGenericParameterTypes().length];
+            final ConstructorProperties constructorProperties = constructor.getAnnotation(ConstructorProperties.class);
+            System.arraycopy(constructorProperties.value(), 0, constructorParameters, 0, constructorParameters.length);
+
+            constructorParameterConverters = new Converter<?>[constructor.getGenericParameterTypes().length];
+            constructorItemParameterConverters = new Converter<?>[constructorParameterConverters.length];
+            for (int i = 0; i < constructorParameters.length; i++) {
+                for (final Annotation a : constructor.getParameterAnnotations()[i]) {
+                    if (a.annotationType() == JohnzonConverter.class) {
+                        try {
+                            final Converter<?> converter = JohnzonConverter.class.cast(a).value().newInstance();
+                            if (matches(constructor.getParameterTypes()[i], converter)) {
+                                constructorParameterConverters[i] = converter;
+                                constructorItemParameterConverters[i] = null;
+                            } else {
+                                constructorParameterConverters[i] = null;
+                                constructorItemParameterConverters[i] = converter;
+                            }
+                        } catch (final Exception e) {
+                            throw new IllegalArgumentException(e);
+                        }
+                    }
+                }
+            }
+        } else {
+            factoryParameterTypes = NO_PARAMS;
+            constructorParameters = null;
+            constructorParameterConverters = null;
+            constructorItemParameterConverters = null;
+        }
+
+        final Constructor<?> cons = constructor;
+        if (cons != null && !cons.isAccessible()) {
+            cons.setAccessible(true);
+        }
+        return new Factory() {
+            @Override
+            public Object create(final Object[] params) {
+                if (cons == null) {
+                    throw new IllegalArgumentException(clazz.getName() + " can't be instantiated by Johnzon, this is a write only class");
+                }
+                try {
+                    return params == null ? cons.newInstance() : cons.newInstance(params);
+                } catch (final InstantiationException e) {
+                    throw new IllegalStateException(e);
+                } catch (final IllegalAccessException e) {
+                    throw new IllegalStateException(e);
+                } catch (final InvocationTargetException e) {
+                    throw new IllegalStateException(e.getCause());
+                }
+            }
+
+            @Override
+            public Type[] getParameterTypes() {
+                return factoryParameterTypes;
+            }
+
+            @Override
+            public String[] getParameterNames() {
+                return constructorParameters;
+            }
+
+            @Override
+            public Converter<?>[] getParameterConverter() {
+                return constructorParameterConverters;
+            }
+
+            @Override
+            public Converter<?>[] getParameterItemConverter() {
+                return constructorItemParameterConverters;
+            }
+        };
+    }
+
     private <T> Map<String, T> sanitize(final Class<?> type, final Map<String, T> delegate) {
         for (final Map.Entry<Class<?>, String[]> entry : fieldsToRemove.entrySet()) {
             if (entry.getKey().isAssignableFrom(type)) {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
index 3f1b54c..70c456a 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
@@ -18,6 +18,7 @@
  */
 package org.apache.johnzon.mapper.access;
 
+import org.apache.johnzon.mapper.Converter;
 import org.apache.johnzon.mapper.JohnzonProperty;
 import org.apache.johnzon.mapper.MapperException;
 
@@ -29,6 +30,10 @@ import java.util.HashMap;
 import java.util.Map;
 
 public class FieldAccessMode extends BaseAccessMode {
+    public FieldAccessMode(final boolean useConstructor, final boolean acceptHiddenConstructor) {
+        super(useConstructor, acceptHiddenConstructor);
+    }
+
     @Override
     public Map<String, Reader> doFindReaders(final Class<?> clazz) {
         final Map<String, Reader> readers = new HashMap<String, Reader>();
@@ -68,7 +73,7 @@ public class FieldAccessMode extends BaseAccessMode {
         return key.contains("$");
     }
 
-    private Map<String, Field> fields(final Class<?> clazz) {
+    protected Map<String, Field> fields(final Class<?> clazz) {
         final Map<String, Field> fields = new HashMap<String, Field>();
         Class<?> current = clazz;
         while (current != null && current != Object.class) {
@@ -87,7 +92,7 @@ public class FieldAccessMode extends BaseAccessMode {
         return fields;
     }
 
-    protected static abstract class FieldDecoratedType implements DecoratedType {
+    public static abstract class FieldDecoratedType implements DecoratedType {
         protected final Field field;
         protected final Type type;
 
@@ -100,6 +105,15 @@ public class FieldAccessMode extends BaseAccessMode {
         }
 
         @Override
+        public Converter<?> findConverter() {
+            return null;
+        }
+
+        public Field getField() {
+            return field;
+        }
+
+        @Override
         public Type getType() {
             return type;
         }
@@ -108,6 +122,11 @@ public class FieldAccessMode extends BaseAccessMode {
         public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
             return field.getAnnotation(clazz);
         }
+
+        @Override
+        public boolean isNillable() {
+            return false;
+        }
     }
 
     public static class FieldWriter extends FieldDecoratedType implements Writer {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
index 0c3a2da..1a27c52 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
@@ -18,6 +18,8 @@
  */
 package org.apache.johnzon.mapper.access;
 
+import org.apache.johnzon.mapper.Converter;
+
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 import java.util.HashMap;
@@ -25,8 +27,14 @@ import java.util.Map;
 
 // methods override fields
 public class FieldAndMethodAccessMode extends BaseAccessMode {
-    private final FieldAccessMode fields = new FieldAccessMode();
-    private final MethodAccessMode methods = new MethodAccessMode(false);
+    private final FieldAccessMode fields;
+    private final MethodAccessMode methods;
+
+    public FieldAndMethodAccessMode(final boolean useConstructor, final boolean acceptHiddenConstructor) {
+        super(useConstructor, acceptHiddenConstructor);
+        this.fields = new FieldAccessMode(useConstructor, acceptHiddenConstructor);
+        this.methods = new MethodAccessMode(useConstructor, acceptHiddenConstructor, false);
+    }
 
     @Override
     public Map<String, Reader> doFindReaders(final Class<?> clazz) {
@@ -56,7 +64,7 @@ public class FieldAndMethodAccessMode extends BaseAccessMode {
         return writers;
     }
 
-    private static abstract class CompositeDecoratedType implements DecoratedType {
+    public static abstract class CompositeDecoratedType implements DecoratedType {
         protected final DecoratedType type1;
         private final DecoratedType type2;
 
@@ -66,6 +74,12 @@ public class FieldAndMethodAccessMode extends BaseAccessMode {
         }
 
         @Override
+        public Converter<?> findConverter() {
+            final Converter<?> converter = type1.findConverter();
+            return converter != null ? converter : type2.findConverter();
+        }
+
+        @Override
         public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
             final T found = type1.getAnnotation(clazz);
             return found == null ? type2.getAnnotation(clazz) : found;
@@ -75,9 +89,22 @@ public class FieldAndMethodAccessMode extends BaseAccessMode {
         public Type getType() {
             return type1.getType();
         }
+
+        @Override
+        public boolean isNillable() {
+            return type1.isNillable() || type2.isNillable();
+        }
+
+        public DecoratedType getType1() {
+            return type1;
+        }
+
+        public DecoratedType getType2() {
+            return type2;
+        }
     }
 
-    private static final class CompositeReader extends CompositeDecoratedType implements Reader {
+    public static final class CompositeReader extends CompositeDecoratedType implements Reader {
         private final Reader reader;
 
         private CompositeReader(final Reader type1, final DecoratedType type2) {
@@ -91,7 +118,7 @@ public class FieldAndMethodAccessMode extends BaseAccessMode {
         }
     }
 
-    private static final class CompositeWriter extends CompositeDecoratedType implements Writer {
+    public static final class CompositeWriter extends CompositeDecoratedType implements Writer {
         private final Writer writer;
 
         private CompositeWriter(final Writer type1, final DecoratedType type2) {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
index 69f1af5..df17a56 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
@@ -18,6 +18,7 @@
  */
 package org.apache.johnzon.mapper.access;
 
+import org.apache.johnzon.mapper.Converter;
 import org.apache.johnzon.mapper.JohnzonProperty;
 import org.apache.johnzon.mapper.MapperException;
 
@@ -34,7 +35,8 @@ import java.util.Map;
 public class MethodAccessMode extends BaseAccessMode {
     private final boolean supportGetterAsWritter;
 
-    public MethodAccessMode(final boolean supportGetterAsWritter) {
+    public MethodAccessMode(final boolean useConstructor, final boolean acceptHiddenConstructor, final boolean supportGetterAsWritter) {
+        super(useConstructor, acceptHiddenConstructor);
         this.supportGetterAsWritter = supportGetterAsWritter;
     }
 
@@ -94,7 +96,7 @@ public class MethodAccessMode extends BaseAccessMode {
         return propertyDescriptors;
     }
 
-    protected static abstract class MethodDecoratedType implements DecoratedType {
+    public static abstract class MethodDecoratedType implements DecoratedType {
         protected final Method method;
         protected final Type type;
 
@@ -107,6 +109,15 @@ public class MethodAccessMode extends BaseAccessMode {
         }
 
         @Override
+        public Converter<?> findConverter() {
+            return null;
+        }
+
+        public Method getMethod() {
+            return method;
+        }
+
+        @Override
         public Type getType() {
             return type;
         }
@@ -115,6 +126,11 @@ public class MethodAccessMode extends BaseAccessMode {
         public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
             return method.getAnnotation(clazz);
         }
+
+        @Override
+        public boolean isNillable() {
+            return false;
+        }
     }
 
     public static class MethodWriter extends MethodDecoratedType implements Writer {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Converters.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Converters.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Converters.java
new file mode 100644
index 0000000..bfdbaa6
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/reflection/Converters.java
@@ -0,0 +1,78 @@
+/*
+ * 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.mapper.reflection;
+
+import org.apache.johnzon.mapper.Converter;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.Map;
+
+public class Converters {
+    private Converters() {
+        // no-op
+    }
+
+    // TODO: more ParameterizedType and maybe TypeClosure support
+    public static boolean matches(final Type type, final Converter<?> converter) {
+        Type convertType = null;
+        if (Converter.TypeAccess.class.isInstance(converter)) {
+            convertType = Converter.TypeAccess.class.cast(converter).type();
+        } else {
+            for (final Type pt : converter.getClass().getGenericInterfaces()) {
+                if (ParameterizedType.class.isInstance(pt) && ParameterizedType.class.cast(pt).getRawType() == Converter.class) {
+                    convertType = ParameterizedType.class.cast(pt).getActualTypeArguments()[0];
+                    break;
+                }
+            }
+        }
+
+        if (convertType == null) { // compatibility, previously nested converter were not supported
+            return true;
+        }
+
+        if (ParameterizedType.class.isInstance(type)) {
+            final ParameterizedType parameterizedType = ParameterizedType.class.cast(type);
+            final Type rawType = parameterizedType.getRawType();
+            if (Class.class.isInstance(rawType)) {
+                final Class<?> clazz = Class.class.cast(rawType);
+                if (Collection.class.isAssignableFrom(clazz) && parameterizedType.getActualTypeArguments().length == 1) {
+                    final Type argType = parameterizedType.getActualTypeArguments()[0];
+                    if (Class.class.isInstance(argType) && Class.class.isInstance(convertType)) {
+                        return !Class.class.cast(convertType).isAssignableFrom(Class.class.cast(argType));
+                    }
+                } else if (Map.class.isAssignableFrom(clazz) && parameterizedType.getActualTypeArguments().length == 2) {
+                    final Type argType = parameterizedType.getActualTypeArguments()[1];
+                    if (Class.class.isInstance(argType) && Class.class.isInstance(convertType)) {
+                        return !Class.class.cast(convertType).isAssignableFrom(Class.class.cast(argType));
+                    }
+                }
+                return true; // actually here we suppose we dont know
+            }
+        }
+        if (Class.class.isInstance(type)) {
+            final Class<?> clazz = Class.class.cast(type);
+            if (clazz.isArray()) {
+                return !Class.class.cast(convertType).isAssignableFrom(clazz.getComponentType());
+            }
+        }
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/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 b75823c..49c5d88 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
@@ -27,11 +27,8 @@ import org.apache.johnzon.mapper.access.AccessMode;
 import org.apache.johnzon.mapper.converter.DateWithCopyConverter;
 import org.apache.johnzon.mapper.converter.EnumConverter;
 
-import java.beans.ConstructorProperties;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Modifier;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.math.BigDecimal;
@@ -53,88 +50,22 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 import static java.util.Arrays.asList;
+import static org.apache.johnzon.mapper.reflection.Converters.matches;
 
 public class Mappings {
     public static class ClassMapping {
         public final Class<?> clazz;
+        public final AccessMode.Factory factory;
         public final Map<String, Getter> getters;
         public final Map<String, Setter> setters;
-        public final Constructor<?> constructor;
-        public final boolean constructorHasArguments;
-        public final String[] constructorParameters;
-        public final Converter<?>[] constructorParameterConverters;
-        public final Converter<?>[] constructorItemParameterConverters;
-        public final Type[] constructorParameterTypes;
-
-        protected ClassMapping(final Class<?> clazz,
-                               final Map<String, Getter> getters, final Map<String, Setter> setters,
-                               final boolean acceptHiddenConstructor, final boolean useConstructor) {
+
+
+        protected ClassMapping(final Class<?> clazz, final AccessMode.Factory factory,
+                               final Map<String, Getter> getters, final Map<String, Setter> setters) {
             this.clazz = clazz;
+            this.factory = factory;
             this.getters = getters;
             this.setters = setters;
-            this.constructor = findConstructor(acceptHiddenConstructor, useConstructor);
-
-            this.constructorHasArguments = this.constructor != null && this.constructor.getGenericParameterTypes().length > 0;
-            if (this.constructorHasArguments) {
-                this.constructorParameterTypes = this.constructor.getGenericParameterTypes();
-
-                // TODO: java 8 gives access to it without annotation
-                this.constructorParameters = new String[this.constructor.getGenericParameterTypes().length];
-                final ConstructorProperties constructorProperties = this.constructor.getAnnotation(ConstructorProperties.class);
-                System.arraycopy(constructorProperties.value(), 0, this.constructorParameters, 0, this.constructorParameters.length);
-
-                this.constructorParameterConverters = new Converter<?>[this.constructor.getGenericParameterTypes().length];
-                this.constructorItemParameterConverters = new Converter<?>[this.constructorParameterConverters.length];
-                for (int i = 0; i < this.constructorParameters.length; i++) {
-                    for (final Annotation a : this.constructor.getParameterAnnotations()[i]) {
-                        if (a.annotationType() == JohnzonConverter.class) {
-                            try {
-                                final Converter<?> converter = JohnzonConverter.class.cast(a).value().newInstance();
-                                if (matches(this.constructor.getParameterTypes()[i], converter)) {
-                                    this.constructorParameterConverters[i] = converter;
-                                    this.constructorItemParameterConverters[i] = null;
-                                } else {
-                                    this.constructorParameterConverters[i] = null;
-                                    this.constructorItemParameterConverters[i] = converter;
-                                }
-                            } catch (final Exception e) {
-                                throw new IllegalArgumentException(e);
-                            }
-                        }
-                    }
-                }
-            } else {
-                this.constructorParameterTypes = null;
-                this.constructorParameters = null;
-                this.constructorParameterConverters = null;
-                this.constructorItemParameterConverters = null;
-            }
-        }
-
-        private Constructor<?> findConstructor(final boolean acceptHiddenConstructor, final boolean useConstructor) {
-            Constructor<?> found = null;
-            for (final Constructor<?> c : clazz.getDeclaredConstructors()) {
-                if (c.getParameterTypes().length == 0) {
-                    if (!Modifier.isPublic(c.getModifiers()) && acceptHiddenConstructor) {
-                        c.setAccessible(true);
-                    }
-                    found = c;
-                    if (!useConstructor) {
-                        break;
-                    }
-                } else if (c.getAnnotation(ConstructorProperties.class) != null) {
-                    found = c;
-                    break;
-                }
-            }
-            if (found != null) {
-                return found;
-            }
-            try {
-                return clazz.getConstructor();
-            } catch (final NoSuchMethodException e) {
-                return null; // readOnly class
-            }
         }
     }
 
@@ -241,70 +172,19 @@ public class Mappings {
         }
     }
 
-    // TODO: more ParameterizedType and maybe TypeClosure support
-    private static boolean matches(final Type type, final Converter<?> converter) {
-        Type convertType = null;
-        if (Converter.TypeAccess.class.isInstance(converter)) {
-            convertType = Converter.TypeAccess.class.cast(converter).type();
-        } else {
-            for (final Type pt : converter.getClass().getGenericInterfaces()) {
-                if (ParameterizedType.class.isInstance(pt) && ParameterizedType.class.cast(pt).getRawType() == Converter.class) {
-                    convertType = ParameterizedType.class.cast(pt).getActualTypeArguments()[0];
-                    break;
-                }
-            }
-        }
-
-        if (convertType == null) { // compatibility, previously nested converter were not supported
-            return true;
-        }
-
-        if (ParameterizedType.class.isInstance(type)) {
-            final ParameterizedType parameterizedType = ParameterizedType.class.cast(type);
-            final Type rawType = parameterizedType.getRawType();
-            if (Class.class.isInstance(rawType)) {
-                final Class<?> clazz = Class.class.cast(rawType);
-                if (Collection.class.isAssignableFrom(clazz) && parameterizedType.getActualTypeArguments().length == 1) {
-                    final Type argType = parameterizedType.getActualTypeArguments()[0];
-                    if (Class.class.isInstance(argType) && Class.class.isInstance(convertType)) {
-                        return !Class.class.cast(convertType).isAssignableFrom(Class.class.cast(argType));
-                    }
-                } else if (Map.class.isAssignableFrom(clazz) && parameterizedType.getActualTypeArguments().length == 2) {
-                    final Type argType = parameterizedType.getActualTypeArguments()[1];
-                    if (Class.class.isInstance(argType) && Class.class.isInstance(convertType)) {
-                        return !Class.class.cast(convertType).isAssignableFrom(Class.class.cast(argType));
-                    }
-                }
-                return true; // actually here we suppose we dont know
-            }
-        }
-        if (Class.class.isInstance(type)) {
-            final Class<?> clazz = Class.class.cast(type);
-            if (clazz.isArray()) {
-                return !Class.class.cast(convertType).isAssignableFrom(clazz.getComponentType());
-            }
-        }
-        return true;
-    }
-
     private static final JohnzonParameterizedType VIRTUAL_TYPE = new JohnzonParameterizedType(Map.class, String.class, Object.class);
 
     protected final ConcurrentMap<Type, ClassMapping> classes = new ConcurrentHashMap<Type, ClassMapping>();
     protected final ConcurrentMap<Type, CollectionMapping> collections = new ConcurrentHashMap<Type, CollectionMapping>();
     protected final Comparator<String> fieldOrdering;
     protected final ConcurrentMap<Type, Converter<?>> converters;
-    private final boolean supportHiddenConstructors;
-    private final boolean supportConstructors;
     private final AccessMode accessMode;
     private final int version;
 
     public Mappings(final Comparator<String> attributeOrder, final AccessMode accessMode,
-                    final boolean supportHiddenConstructors, final boolean supportConstructors,
                     final int version, final ConcurrentMap<Type, Converter<?>> converters) {
         this.fieldOrdering = attributeOrder;
         this.accessMode = accessMode;
-        this.supportHiddenConstructors = supportHiddenConstructors;
-        this.supportConstructors = supportConstructors;
         this.version = version;
         this.converters = converters;
     }
@@ -396,7 +276,7 @@ public class Mappings {
         return classMapping;
     }
 
-    private ClassMapping createClassMapping(final Class<?> inClazz) {
+    protected ClassMapping createClassMapping(final Class<?> inClazz) {
         boolean copyDate = false;
         for (final Class<?> itf : inClazz.getInterfaces()) {
             if ("org.apache.openjpa.enhance.PersistenceCapable".equals(itf.getName())) {
@@ -442,7 +322,7 @@ public class Mappings {
             }
             addSetterIfNeeded(setters, key, writer.getValue(), copyDate);
         }
-        return new ClassMapping(clazz, getters, setters, supportHiddenConstructors, supportConstructors);
+        return new ClassMapping(clazz, accessMode.findFactory(clazz), getters, setters);
     }
 
     protected Class<?> findModelClass(final Class<?> inClazz) {
@@ -550,20 +430,23 @@ public class Mappings {
         setters.put(key, new Setter(newSetter == null ? newWriter : new CompositeWriter(newSetter.writer, newWriter), false, false, VIRTUAL_TYPE, null, -1));
     }
 
-    private Converter findConverter(final boolean copyDate, final AccessMode.DecoratedType method) {
-        Converter converter = null;
-        final JohnzonConverter annotation = method.getAnnotation(JohnzonConverter.class);
+    private Converter findConverter(final boolean copyDate, final AccessMode.DecoratedType decoratedType) {
+        Converter converter = decoratedType.findConverter();
+        if (converter != null) {
+            return converter;
+        }
 
+        final JohnzonConverter annotation = decoratedType.getAnnotation(JohnzonConverter.class);
 
-        Type typeToTest = method.getType();
+        Type typeToTest = decoratedType.getType();
         if (annotation != null) {
             try {
                 converter = annotation.value().newInstance();
             } catch (final Exception e) {
                 throw new IllegalArgumentException(e);
             }
-        } else if (ParameterizedType.class.isInstance(method.getType())) {
-            final ParameterizedType type = ParameterizedType.class.cast(method.getType());
+        } else if (ParameterizedType.class.isInstance(decoratedType.getType())) {
+            final ParameterizedType type = ParameterizedType.class.cast(decoratedType.getType());
             final Type rawType = type.getRawType();
             if (Class.class.isInstance(rawType)
                     && Collection.class.isAssignableFrom(Class.class.cast(rawType))
@@ -638,6 +521,16 @@ public class Mappings {
         public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
             throw new UnsupportedOperationException("getAnnotation shouldn't get called for virtual fields");
         }
+
+        @Override
+        public Converter<?> findConverter() {
+            return null;
+        }
+
+        @Override
+        public boolean isNillable() {
+            return false;
+        }
     }
 
     private static class MapUnwrapperWriter implements AccessMode.Writer {
@@ -697,6 +590,16 @@ public class Mappings {
         public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
             throw new UnsupportedOperationException("getAnnotation shouldn't get called for virtual fields");
         }
+
+        @Override
+        public Converter<?> findConverter() {
+            return null;
+        }
+
+        @Override
+        public boolean isNillable() {
+            return false;
+        }
     }
 
     private static class CompositeReader implements AccessMode.Reader {
@@ -742,6 +645,27 @@ public class Mappings {
         public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
             throw new UnsupportedOperationException("getAnnotation shouldn't get called for virtual fields");
         }
+
+        @Override
+        public Converter<?> findConverter() {
+            for (final AccessMode.Reader r : delegates) {
+                final Converter<?> converter = r.findConverter();
+                if (converter != null) {
+                    return converter;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public boolean isNillable() {
+            for (final AccessMode.Reader r : delegates) {
+                if (r.isNillable()) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     private static class CompositeWriter implements AccessMode.Writer {
@@ -775,5 +699,26 @@ public class Mappings {
         public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
             throw new UnsupportedOperationException("getAnnotation shouldn't get called for virtual fields");
         }
+
+        @Override
+        public Converter<?> findConverter() {
+            for (final AccessMode.Writer r : delegates) {
+                final Converter<?> converter = r.findConverter();
+                if (converter != null) {
+                    return converter;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public boolean isNillable() {
+            for (final AccessMode.Writer r : delegates) {
+                if (r.isNillable()) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/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 f5817bb..a6c3267 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
@@ -545,7 +545,7 @@ public class MapperTest {
             public int compare(final String o1, final String o2) {
                 return o1.compareTo(o2);
             }
-        }).setAccessMode(new FieldAccessMode()).build();
+        }).setAccessMode(new FieldAccessMode(true, false)).build();
 
         final String asString = mapper.writeObjectAsString(source);
         assertEquals("{\"children\":[\"5\",\"6\"],\"nested\":{\"b\":2,\"sub\":{\"a\":1,\"c\":[\"3\",\"4\"]}}}", asString);

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/pom.xml
----------------------------------------------------------------------
diff --git a/jsonb-api/pom.xml b/jsonb-api/pom.xml
new file mode 100644
index 0000000..942ec3a
--- /dev/null
+++ b/jsonb-api/pom.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="
+            http://maven.apache.org/POM/4.0.0
+            http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>johnzon</artifactId>
+    <groupId>org.apache.johnzon</groupId>
+    <version>0.9.3-incubating-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>jsonb-api</artifactId>
+  <version>1.0-early-draft</version>
+  <name>Johnzon :: JSON-B API</name>
+
+  <properties>
+    <java-compile.version>1.8</java-compile.version>
+  </properties>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/Jsonb.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/Jsonb.java b/jsonb-api/src/main/java/javax/json/bind/Jsonb.java
new file mode 100644
index 0000000..9bccc4b
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/Jsonb.java
@@ -0,0 +1,49 @@
+/*
+ * 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 javax.json.bind;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Type;
+
+public interface Jsonb {
+    <T> T fromJson(String str, Class<T> type) throws JsonbException;
+
+    <T> T fromJson(String str, Type runtimeType) throws JsonbException;
+
+    <T> T fromJson(Readable readable, Class<T> type) throws JsonbException;
+
+    <T> T fromJson(Readable readable, Type runtimeType) throws JsonbException;
+
+    <T> T fromJson(InputStream stream, Class<T> type) throws JsonbException;
+
+    <T> T fromJson(InputStream stream, Type runtimeType) throws JsonbException;
+
+    String toJson(Object object) throws JsonbException;
+
+    String toJson(Object object, Type runtimeType) throws JsonbException;
+
+    void toJson(Object object, Appendable appendable) throws JsonbException;
+
+    void toJson(Object object, Type runtimeType, Appendable appendable) throws JsonbException;
+
+    void toJson(Object object, OutputStream stream) throws JsonbException;
+
+    void toJson(Object object, Type runtimeType, OutputStream stream) throws JsonbException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/JsonbBuilder.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/JsonbBuilder.java b/jsonb-api/src/main/java/javax/json/bind/JsonbBuilder.java
new file mode 100644
index 0000000..77e4a8c
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/JsonbBuilder.java
@@ -0,0 +1,50 @@
+/*
+ * 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 javax.json.bind;
+
+import javax.json.bind.spi.JsonbProvider;
+import javax.json.spi.JsonProvider;
+
+public interface JsonbBuilder {
+    JsonbBuilder withConfig(final JsonbConfig config);
+
+    JsonbBuilder withProvider(final JsonProvider jsonpProvider);
+
+    Jsonb build();
+
+    static Jsonb create() {
+        return JsonbProvider.provider().create().build();
+    }
+
+    static Jsonb create(final JsonbConfig config) {
+        return JsonbProvider.provider().create().withConfig(config).build();
+    }
+
+    static JsonbBuilder newBuilder() {
+        return JsonbProvider.provider().create();
+    }
+
+    static JsonbBuilder newBuilder(final String providerName) {
+        return JsonbProvider.provider(providerName).create();
+    }
+
+    static JsonbBuilder newBuilder(final JsonbProvider provider) {
+        return provider.create();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java b/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java
new file mode 100644
index 0000000..7d880b3
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java
@@ -0,0 +1,94 @@
+/*
+ * 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 javax.json.bind;
+
+import javax.json.bind.adapter.JsonbAdapter;
+import javax.json.bind.config.PropertyNamingStrategy;
+import javax.json.bind.config.PropertyVisibilityStrategy;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+public class JsonbConfig {
+    private final Map<String, Object> configuration = new HashMap<>();
+
+    public static final String FORMATTING = "jsonb.formatting";
+    public static final String ENCODING = "jsonb.encoding";
+    public static final String PROPERTY_NAMING_STRATEGY = "jsonb.property-naming-strategy";
+    public static final String PROPERTY_ORDER_STRATEGY = "jsonb.property-order-strategy";
+    public static final String NULL_VALUES = "jsonb.null-values";
+    public static final String STRICT_IJSON = "jsonb.strict-ijson";
+    public static final String PROPERTY_VISIBILITY_STRATEGY = "jsonb.property-visibility-strategy";
+    public static final String ADAPTERS = "jsonb.adapters";
+    public static final String BINARY_DATA_STRATEGY = "jsonb.binary-data-strategy";
+
+    public final JsonbConfig setProperty(final String name, final Object value) {
+        configuration.put(name, value);
+        return this;
+    }
+
+    public final Optional<Object> getProperty(final String name) {
+        return Optional.ofNullable(configuration.get(name));
+    }
+
+    public final Map<String, Object> getAsMap() {
+        return Collections.unmodifiableMap(configuration);
+    }
+
+    public final JsonbConfig withFormatting(final Boolean formatted) {
+        return setProperty(FORMATTING, formatted);
+    }
+
+    public final JsonbConfig withNullValues(final Boolean serializeNullValues) {
+        return setProperty(NULL_VALUES, serializeNullValues);
+    }
+
+    public final JsonbConfig withEncoding(final String encoding) {
+        return setProperty(ENCODING, encoding);
+    }
+
+    public final JsonbConfig withStrictIJSON(final Boolean enabled) {
+        return setProperty(STRICT_IJSON, enabled);
+    }
+
+    public final JsonbConfig withPropertyNamingStrategy(final PropertyNamingStrategy propertyNamingStrategy) {
+        return setProperty(PROPERTY_NAMING_STRATEGY, propertyNamingStrategy);
+    }
+
+    public final JsonbConfig withPropertyNamingStrategy(final String propertyNamingStrategy) {
+        return setProperty(PROPERTY_NAMING_STRATEGY, propertyNamingStrategy);
+    }
+
+    public final JsonbConfig withPropertyOrderStrategy(final String propertyOrderStrategy) {
+        return setProperty(PROPERTY_ORDER_STRATEGY, propertyOrderStrategy);
+    }
+
+    public final JsonbConfig withPropertyVisibilityStrategy(final PropertyVisibilityStrategy propertyVisibilityStrategy) {
+        return setProperty(PROPERTY_VISIBILITY_STRATEGY, propertyVisibilityStrategy);
+    }
+
+    public final JsonbConfig withAdapters(final JsonbAdapter... adapters) {
+        return setProperty(ADAPTERS, adapters);
+    }
+
+    public final JsonbConfig withBinaryDataStrategy(final String binaryDataStrategy) {
+        return setProperty(BINARY_DATA_STRATEGY, binaryDataStrategy);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/JsonbException.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/JsonbException.java b/jsonb-api/src/main/java/javax/json/bind/JsonbException.java
new file mode 100644
index 0000000..6cf0cdd
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/JsonbException.java
@@ -0,0 +1,31 @@
+/*
+ * 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 javax.json.bind;
+
+public class JsonbException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public JsonbException(final String message) {
+        super(message);
+    }
+
+    public JsonbException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/adapter/JsonbAdapter.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/adapter/JsonbAdapter.java b/jsonb-api/src/main/java/javax/json/bind/adapter/JsonbAdapter.java
new file mode 100644
index 0000000..eb364fe
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/adapter/JsonbAdapter.java
@@ -0,0 +1,52 @@
+/*
+ * 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 javax.json.bind.adapter;
+
+import java.lang.reflect.Type;
+
+// under discussion
+public interface JsonbAdapter {
+    default <ValueType> ValueType adaptTo(Object obj) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    default <BoundType> BoundType adaptFrom(Object obj) throws Exception {
+        throw new UnsupportedOperationException();
+    }
+
+    default Class<?> getValueType() {
+        return null;
+    }
+
+    default Class<?> getBoundType() {
+        return null;
+    }
+
+    default Type getRuntimeValueType() {
+        return null;
+    }
+
+    default Type getRuntimeBoundType() {
+        return null;
+    }
+
+    default boolean handlesNullValue() {
+        return false;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbAnnotation.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbAnnotation.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbAnnotation.java
new file mode 100644
index 0000000..743fd07
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbAnnotation.java
@@ -0,0 +1,26 @@
+/*
+ * 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 javax.json.bind.annotation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface JsonbAnnotation {
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbCreator.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbCreator.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbCreator.java
new file mode 100644
index 0000000..9502320
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbCreator.java
@@ -0,0 +1,30 @@
+/*
+ * 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 javax.json.bind.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface JsonbCreator {
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbDateFormat.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbDateFormat.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbDateFormat.java
new file mode 100644
index 0000000..3f7c2ec
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbDateFormat.java
@@ -0,0 +1,40 @@
+/*
+ * 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 javax.json.bind.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({
+    ElementType.ANNOTATION_TYPE, ElementType.FIELD,
+    ElementType.METHOD, ElementType.TYPE,
+    ElementType.PARAMETER, ElementType.PACKAGE
+})
+public @interface JsonbDateFormat {
+    String DEFAULT_LOCALE = "##default";
+    String DEFAULT_FORMAT = "##default";
+    String TIME_IN_MILLIS = "##time-in-millis";
+
+    String value() default DEFAULT_FORMAT;
+    String locale() default DEFAULT_LOCALE;
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbNillable.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbNillable.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbNillable.java
new file mode 100644
index 0000000..a2a70c6
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbNillable.java
@@ -0,0 +1,31 @@
+/*
+ * 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 javax.json.bind.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.PACKAGE})
+public @interface JsonbNillable {
+    boolean value() default true;
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbNumberFormat.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbNumberFormat.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbNumberFormat.java
new file mode 100644
index 0000000..06bfa9a
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbNumberFormat.java
@@ -0,0 +1,40 @@
+/*
+ * 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 javax.json.bind.annotation;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({
+    ElementType.ANNOTATION_TYPE, ElementType.FIELD,
+    ElementType.METHOD, ElementType.TYPE, ElementType.PARAMETER,
+    ElementType.PACKAGE
+})
+public @interface JsonbNumberFormat {
+    String DEFAULT_LOCALE = "##default";
+
+    String value() default "";
+
+    String locale() default DEFAULT_LOCALE;
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbProperty.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbProperty.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbProperty.java
new file mode 100644
index 0000000..b8234ba
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbProperty.java
@@ -0,0 +1,35 @@
+/*
+ * 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 javax.json.bind.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({
+    ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER
+})
+public @interface JsonbProperty {
+    String value() default "";
+
+    boolean nillable() default false;
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbPropertyOrder.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbPropertyOrder.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbPropertyOrder.java
new file mode 100644
index 0000000..b06a868
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbPropertyOrder.java
@@ -0,0 +1,31 @@
+/*
+ * 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 javax.json.bind.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+public @interface JsonbPropertyOrder {
+    String[] value();
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTransient.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTransient.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTransient.java
new file mode 100644
index 0000000..9b708dd
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTransient.java
@@ -0,0 +1,32 @@
+/*
+ * 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 javax.json.bind.annotation;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
+public @interface JsonbTransient {
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeAdapter.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeAdapter.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeAdapter.java
new file mode 100644
index 0000000..6e9f281
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeAdapter.java
@@ -0,0 +1,32 @@
+/*
+ * 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 javax.json.bind.annotation;
+
+import javax.json.bind.adapter.JsonbAdapter;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD})
+public @interface JsonbTypeAdapter {
+    Class<? extends JsonbAdapter> value();
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbValue.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbValue.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbValue.java
new file mode 100644
index 0000000..7b44286
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbValue.java
@@ -0,0 +1,32 @@
+/*
+ * 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 javax.json.bind.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({
+    ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER
+})
+public @interface JsonbValue {
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbVisibility.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbVisibility.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbVisibility.java
new file mode 100644
index 0000000..69265f8
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbVisibility.java
@@ -0,0 +1,34 @@
+/*
+ * 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 javax.json.bind.annotation;
+
+import javax.json.bind.config.PropertyVisibilityStrategy;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({
+    ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.PACKAGE
+})
+public @interface JsonbVisibility {
+    Class<? extends PropertyVisibilityStrategy> value();
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/config/BinaryDataStrategy.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/config/BinaryDataStrategy.java b/jsonb-api/src/main/java/javax/json/bind/config/BinaryDataStrategy.java
new file mode 100644
index 0000000..1871826
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/config/BinaryDataStrategy.java
@@ -0,0 +1,29 @@
+/*
+ * 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 javax.json.bind.config;
+
+public final class BinaryDataStrategy {
+    private BinaryDataStrategy() {
+        // no-op
+    }
+
+    public static final String BYTE = "BYTE";
+    public static final String BASE_64 = "BASE_64";
+    public static final String BASE_64_URL = "BASE_64_URL";
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/jsonb-api/src/main/java/javax/json/bind/config/PropertyNamingStrategy.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/config/PropertyNamingStrategy.java b/jsonb-api/src/main/java/javax/json/bind/config/PropertyNamingStrategy.java
new file mode 100644
index 0000000..218e087
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/config/PropertyNamingStrategy.java
@@ -0,0 +1,30 @@
+/*
+ * 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 javax.json.bind.config;
+
+public interface PropertyNamingStrategy {
+    String IDENTITY = "IDENTITY";
+    String LOWER_CASE_WITH_DASHES = "LOWER_CASE_WITH_DASHES";
+    String LOWER_CASE_WITH_UNDERSCORES = "LOWER_CASE_WITH_UNDERSCORES";
+    String UPPER_CAMEL_CASE = "UPPER_CAMEL_CASE";
+    String UPPER_CAMEL_CASE_WITH_SPACES = "UPPER_CAMEL_CASE_WITH_SPACES";
+    String CASE_INSENSITIVE = "CASE_INSENSITIVE";
+
+    String translateName(String propertyName);
+}



[3/3] incubator-johnzon git commit: JOHNZON-61 bases for jsonb, still a lot of tests to add but allows to review more efficiently the early draft

Posted by rm...@apache.org.
JOHNZON-61 bases for jsonb, still a lot of tests to add but allows to review more efficiently the early draft


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

Branch: refs/heads/master
Commit: b65d149a50bcd16ce71f6969ae46d9311fc9ce36
Parents: 6443633
Author: Romain Manni-Bucau <rm...@gmail.com>
Authored: Sun Dec 6 18:46:31 2015 +0100
Committer: Romain Manni-Bucau <rm...@gmail.com>
Committed: Sun Dec 6 18:46:31 2015 +0100

----------------------------------------------------------------------
 .../java/org/apache/johnzon/core/HStack.java    |  34 +-
 johnzon-distribution/pom.xml                    |  18 +
 johnzon-jsonb/pom.xml                           |  52 +++
 .../org/apache/johnzon/jsonb/JohnsonJsonb.java  | 211 +++++++++
 .../apache/johnzon/jsonb/JohnzonBuilder.java    | 178 ++++++++
 .../apache/johnzon/jsonb/JohnzonProvider.java   |  29 ++
 .../apache/johnzon/jsonb/JsonbAccessMode.java   | 454 +++++++++++++++++++
 .../jsonb/PropertyNamingStrategyFactory.java    |  98 ++++
 .../johnzon/jsonb/converter/JsonbConverter.java |  51 +++
 .../jsonb/converter/JsonbDateConverter.java     |  41 ++
 .../jsonb/converter/JsonbDateConverterBase.java |  35 ++
 .../converter/JsonbLocalDateConverter.java      |  39 ++
 .../converter/JsonbLocalDateTimeConverter.java  |  40 ++
 .../JsonbLocaleParserConverterBase.java         |  35 ++
 .../jsonb/converter/JsonbNumberConverter.java   |  77 ++++
 .../jsonb/converter/JsonbValueConverter.java    |  34 ++
 .../converter/JsonbZonedDateTimeConverter.java  |  42 ++
 .../services/javax.json.bind.spi.JsonbProvider  |   1 +
 .../johnzon/jsonb/JohnzonProviderTest.java      |  37 ++
 .../org/apache/johnzon/jsonb/JsonbReadTest.java | 102 +++++
 .../apache/johnzon/jsonb/JsonbWriteTest.java    | 132 ++++++
 .../PropertyNamingStrategyFactoryTest.java      |  52 +++
 .../java/org/apache/johnzon/mapper/Mapper.java  |  30 +-
 .../apache/johnzon/mapper/MapperBuilder.java    |  42 +-
 .../johnzon/mapper/access/AccessMode.java       |  13 +
 .../johnzon/mapper/access/BaseAccessMode.java   | 125 ++++-
 .../johnzon/mapper/access/FieldAccessMode.java  |  23 +-
 .../mapper/access/FieldAndMethodAccessMode.java |  37 +-
 .../johnzon/mapper/access/MethodAccessMode.java |  20 +-
 .../johnzon/mapper/reflection/Converters.java   |  78 ++++
 .../johnzon/mapper/reflection/Mappings.java     | 215 ++++-----
 .../org/apache/johnzon/mapper/MapperTest.java   |   2 +-
 jsonb-api/pom.xml                               |  39 ++
 .../src/main/java/javax/json/bind/Jsonb.java    |  49 ++
 .../main/java/javax/json/bind/JsonbBuilder.java |  50 ++
 .../main/java/javax/json/bind/JsonbConfig.java  |  94 ++++
 .../java/javax/json/bind/JsonbException.java    |  31 ++
 .../javax/json/bind/adapter/JsonbAdapter.java   |  52 +++
 .../json/bind/annotation/JsonbAnnotation.java   |  26 ++
 .../json/bind/annotation/JsonbCreator.java      |  30 ++
 .../json/bind/annotation/JsonbDateFormat.java   |  40 ++
 .../json/bind/annotation/JsonbNillable.java     |  31 ++
 .../json/bind/annotation/JsonbNumberFormat.java |  40 ++
 .../json/bind/annotation/JsonbProperty.java     |  35 ++
 .../bind/annotation/JsonbPropertyOrder.java     |  31 ++
 .../json/bind/annotation/JsonbTransient.java    |  32 ++
 .../json/bind/annotation/JsonbTypeAdapter.java  |  32 ++
 .../javax/json/bind/annotation/JsonbValue.java  |  32 ++
 .../json/bind/annotation/JsonbVisibility.java   |  34 ++
 .../json/bind/config/BinaryDataStrategy.java    |  29 ++
 .../bind/config/PropertyNamingStrategy.java     |  30 ++
 .../json/bind/config/PropertyOrderStrategy.java |  29 ++
 .../bind/config/PropertyVisibilityStrategy.java |  27 ++
 .../java/javax/json/bind/spi/JsonbProvider.java |  59 +++
 pom.xml                                         |  28 +-
 55 files changed, 3058 insertions(+), 199 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-core/src/main/java/org/apache/johnzon/core/HStack.java
----------------------------------------------------------------------
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/HStack.java b/johnzon-core/src/main/java/org/apache/johnzon/core/HStack.java
index 94f07ae..b2d57bd 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/HStack.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/HStack.java
@@ -20,15 +20,15 @@ package org.apache.johnzon.core;
 
 import java.io.Serializable;
 
-public class HStack<T> implements Serializable{
+public class HStack<T> implements Serializable {
 
     private Node<T> topElement = null;
     private int size;
-    
-    
-    private static final class Node<T> implements Serializable{
-        final Node<T> previous;
-        final T object;
+
+
+    private static final class Node<T> implements Serializable {
+        private final Node<T> previous;
+        private final T object;
 
         private Node(final Node<T> previous, final T object) {
             super();
@@ -36,29 +36,31 @@ public class HStack<T> implements Serializable{
             this.object = object;
         }
     }
-    
-    
+
+
     void push(T object) {
         topElement = new Node<T>(topElement, object);
         size++;
     }
-    
+
     T pop() {
-        
-        if(topElement == null) { return null; }
-        
+
+        if (topElement == null) {
+            return null;
+        }
+
         T tmp = topElement.object;
         topElement = topElement.previous;
         size--;
         return tmp;
     }
-    
+
     T peek() {
-        return topElement == null?null:topElement.object;
+        return topElement == null ? null : topElement.object;
     }
-    
+
     int size() {
         return size;
     }
-    
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-distribution/pom.xml
----------------------------------------------------------------------
diff --git a/johnzon-distribution/pom.xml b/johnzon-distribution/pom.xml
index 3f2c10f..7f92fa2 100644
--- a/johnzon-distribution/pom.xml
+++ b/johnzon-distribution/pom.xml
@@ -139,6 +139,24 @@
       <version>${project.version}</version>
       <classifier>javadoc</classifier>
     </dependency>
+
+    <dependency>
+      <groupId>org.apache.johnzon</groupId>
+      <artifactId>johnzon-jsonb</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.johnzon</groupId>
+      <artifactId>johnzon-jsonb</artifactId>
+      <version>${project.version}</version>
+      <classifier>sources</classifier>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.johnzon</groupId>
+      <artifactId>johnzon-jsonb</artifactId>
+      <version>${project.version}</version>
+      <classifier>javadoc</classifier>
+    </dependency>
   </dependencies>
 
   <build>

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/pom.xml
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/pom.xml b/johnzon-jsonb/pom.xml
new file mode 100644
index 0000000..8c36b72
--- /dev/null
+++ b/johnzon-jsonb/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="
+            http://maven.apache.org/POM/4.0.0
+            http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>johnzon</artifactId>
+    <groupId>org.apache.johnzon</groupId>
+    <version>0.9.3-incubating-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>johnzon-jsonb</artifactId>
+  <name>Johnzon :: JSON-B Implementation</name>
+
+  <properties>
+    <java-compile.version>1.8</java-compile.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.johnzon</groupId>
+      <artifactId>jsonb-api</artifactId>
+      <version>1.0-early-draft</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.johnzon</groupId>
+      <artifactId>johnzon-mapper</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/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
new file mode 100644
index 0000000..85f9bd1
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnsonJsonb.java
@@ -0,0 +1,211 @@
+/*
+ * 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.apache.johnzon.mapper.Mapper;
+
+import javax.json.bind.Jsonb;
+import javax.json.bind.JsonbException;
+import java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.nio.CharBuffer;
+import java.util.Collection;
+
+public class JohnsonJsonb implements Jsonb {
+    private final Mapper delegate;
+
+    public JohnsonJsonb(final Mapper build) {
+        this.delegate = build;
+    }
+
+    @Override
+    public <T> T fromJson(final String str, final Class<T> type) throws JsonbException {
+        return delegate.readObject(str, type);
+    }
+
+    @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));
+        }
+        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);
+    }
+
+    @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());
+        } else if (isCollection(runtimeType)) {
+            return (T) delegate.readCollection(toReader(readable), ParameterizedType.class.cast(runtimeType));
+        }
+        return delegate.readObject(toReader(readable), runtimeType);
+    }
+
+    @Override
+    public <T> T fromJson(final InputStream stream, final Class<T> type) throws JsonbException {
+        return delegate.readObject(stream, type);
+    }
+
+    @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));
+        }
+        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));
+        }
+        return delegate.writeObjectAsString(object);
+    }
+
+    @Override
+    public String toJson(final Object object, final Type runtimeType) throws JsonbException {
+        if (isArray(runtimeType)) {
+            return delegate.writeArrayAsString((Object[]) object);
+        } else if (isCollection(runtimeType)) {
+            return delegate.writeArrayAsString(Collection.class.cast(object));
+        }
+        return delegate.writeObjectAsString(object);
+    }
+
+    @Override
+    public void toJson(final Object object, final Appendable appendable) throws JsonbException {
+        if (isArray(object.getClass())) {
+            delegate.writeArray((Object[]) object, toWriter(appendable));
+        } else if (Collection.class.isInstance(object)) {
+            delegate.writeArray(Collection.class.cast(object), toWriter(appendable));
+        } else {
+            delegate.writeObject(object, toWriter(appendable));
+        }
+    }
+
+    @Override
+    public void toJson(final Object object, final Type runtimeType, final Appendable appendable) throws JsonbException {
+        if (isArray(runtimeType)) {
+            delegate.writeArray((Object[]) object, toWriter(appendable));
+        } else if (isCollection(runtimeType)) {
+            delegate.writeArray(Collection.class.cast(object), toWriter(appendable));
+        } else {
+            delegate.writeObject(object, toWriter(appendable));
+        }
+    }
+
+    @Override
+    public void toJson(final Object object, final OutputStream stream) throws JsonbException {
+        if (isArray(object.getClass())) {
+            delegate.writeArray((Object[]) object, stream);
+        } else if (Collection.class.isInstance(object)) {
+            delegate.writeArray(Collection.class.cast(object), stream);
+        } else {
+            delegate.writeObject(object, stream);
+        }
+    }
+
+    @Override
+    public void toJson(final Object object, final Type runtimeType, final OutputStream stream) throws JsonbException {
+        if (isArray(runtimeType)) {
+            delegate.writeArray((Object[]) object, stream);
+        } else if (isCollection(runtimeType)) {
+            delegate.writeArray(Collection.class.cast(object), stream);
+        } else {
+            delegate.writeObject(object, stream);
+        }
+    }
+
+    private boolean isArray(final Type runtimeType) {
+        return Class.class.isInstance(runtimeType) && Class.class.cast(runtimeType).isArray();
+    }
+
+    private boolean isCollection(final Type runtimeType) {
+        if (!ParameterizedType.class.isInstance(runtimeType)) {
+            return false;
+        }
+        final Type rawType = ParameterizedType.class.cast(runtimeType).getRawType();
+        return Class.class.isInstance(rawType) && Collection.class.isAssignableFrom(Class.class.cast(rawType));
+    }
+
+    private Writer toWriter(final Appendable appendable) {
+        return Writer.class.isInstance(appendable) ? Writer.class.cast(appendable) :
+            new Writer() {
+                @Override
+                public void write(final char[] cbuf, final int off, final int len) throws IOException {
+                    appendable.append(new String(cbuf, off, len));
+                }
+
+                @Override
+                public void flush() throws IOException {
+                    if (Flushable.class.isInstance(appendable)) {
+                        Flushable.class.cast(appendable);
+                    }
+                }
+
+                @Override
+                public void close() throws IOException {
+                    if (Closeable.class.isInstance(appendable)) {
+                        Closeable.class.cast(appendable);
+                    }
+                }
+            };
+    }
+
+    private Reader toReader(final Readable readable) {
+        return Reader.class.isInstance(readable) ? Reader.class.cast(readable) :
+            new Reader() {
+                @Override
+                public int read(final char[] cbuf, final int off, final int len) throws IOException {
+                    int r;
+                    final CharBuffer cb = CharBuffer.allocate(len);
+                    while ((r = readable.read(cb)) >= 0) {
+                        System.arraycopy(cb.array(), 0, cbuf, off, r);
+                    }
+                    return readable.read(CharBuffer.allocate(len));
+                }
+
+                @Override
+                public void close() throws IOException {
+                    if (Closeable.class.isInstance(readable)) {
+                        Closeable.class.cast(readable);
+                    }
+                }
+            };
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/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
new file mode 100644
index 0000000..9b2c47d
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
@@ -0,0 +1,178 @@
+/*
+ * 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.apache.johnzon.core.AbstractJsonFactory;
+import org.apache.johnzon.core.JsonGeneratorFactoryImpl;
+import org.apache.johnzon.jsonb.converter.JsonbConverter;
+import org.apache.johnzon.mapper.Converter;
+import org.apache.johnzon.mapper.MapperBuilder;
+
+import javax.json.bind.Jsonb;
+import javax.json.bind.JsonbBuilder;
+import javax.json.bind.JsonbConfig;
+import javax.json.bind.adapter.JsonbAdapter;
+import javax.json.bind.annotation.JsonbVisibility;
+import javax.json.bind.config.BinaryDataStrategy;
+import javax.json.bind.config.PropertyNamingStrategy;
+import javax.json.bind.config.PropertyVisibilityStrategy;
+import javax.json.spi.JsonProvider;
+import javax.json.stream.JsonGenerator;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+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;
+
+public class JohnzonBuilder implements JsonbBuilder {
+    private final MapperBuilder builder = new MapperBuilder();
+    private JsonProvider jsonp;
+    private JsonbConfig config;
+
+    @Override
+    public JsonbBuilder withConfig(final JsonbConfig config) {
+        this.config = config;
+        return this;
+    }
+
+    @Override
+    public JsonbBuilder withProvider(final JsonProvider jsonpProvider) {
+        this.jsonp = jsonpProvider;
+        return this;
+    }
+
+    @Override
+    public Jsonb build() {
+        if (jsonp != null) {
+            builder.setGeneratorFactory(jsonp.createGeneratorFactory(generatorConfig()));
+            builder.setReaderFactory(jsonp.createReaderFactory(emptyMap()));
+        }
+
+        if (config == null) {
+            config = new JsonbConfig();
+        }
+
+        if (config.getProperty(JsonbConfig.FORMATTING).map(Boolean.class::cast).orElse(false)) {
+            builder.setPretty(true);
+        }
+
+        config.getProperty(JsonbConfig.ENCODING).ifPresent(encoding -> builder.setEncoding(String.valueOf(encoding)));
+        config.getProperty(JsonbConfig.NULL_VALUES).ifPresent(serNulls -> builder.setSkipNull(!Boolean.class.cast(serNulls)));
+
+        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 PropertyVisibilityStrategy visibilityStrategy = config.getProperty(JsonbConfig.PROPERTY_VISIBILITY_STRATEGY)
+            .map(PropertyVisibilityStrategy.class::cast).orElse(new PropertyVisibilityStrategy() {
+                @Override
+                public boolean isVisible(final Field field) {
+                    return true;
+                }
+
+                @Override
+                public boolean isVisible(final Method method) {
+                    return true;
+                }
+
+                private PropertyVisibilityStrategy visibilityStrategy(final Class<?> type) { // can be cached
+                    Package p = type.getPackage();
+                    while (p != null) {
+                        final JsonbVisibility visibility = p.getAnnotation(JsonbVisibility.class);
+                        if (visibility != null) {
+                            try {
+                                return visibility.value().newInstance();
+                            } catch (final InstantiationException | IllegalAccessException e) {
+                                throw new IllegalArgumentException(e);
+                            }
+                        }
+                        final String name = p.getName();
+                        final int end = name.lastIndexOf('.');
+                        if (end < 0) {
+                            break;
+                        }
+                        p = Package.getPackage(name.substring(0, end));
+                    }
+                    return this;
+                }
+            });
+
+        builder.setAccessMode(
+            new JsonbAccessMode(propertyNamingStrategy, orderValue, visibilityStrategy, !namingStrategyValue.orElse("").equals(PropertyNamingStrategy.CASE_INSENSITIVE)));
+
+        config.getProperty(JsonbConfig.ADAPTERS).ifPresent(adapters -> Stream.of(JsonbAdapter[].class.cast(adapters)).forEach(adapter ->
+            builder.addConverter(ofNullable(adapter.getRuntimeBoundType()).orElse(adapter.getBoundType()), new JsonbConverter(adapter))
+        ));
+
+        // TODO:
+        // - Converters for setter/getter
+        // - check adapters when type is not String (breaks our Converter API it seems)
+
+        config.getProperty(JsonbConfig.STRICT_IJSON).map(Boolean.class::cast).ifPresent(ijson -> {
+            // no-op: https://tools.ietf.org/html/rfc7493 the only MUST of the spec sould be fine by default
+        });
+
+        config.getProperty(JsonbConfig.BINARY_DATA_STRATEGY).map(String.class::cast).ifPresent(bin -> {
+            switch (bin) {
+                case BinaryDataStrategy.BYTE:
+                    // no-op: our default
+                    break;
+                case BinaryDataStrategy.BASE_64:
+                    builder.setTreatByteArrayAsBase64(true);
+                    break;
+                case BinaryDataStrategy.BASE_64_URL: // needs j8
+                    builder.addConverter(byte[].class, new Converter<byte[]>() {
+                        @Override
+                        public String toString(final byte[] instance) {
+                            return Base64.getUrlEncoder().encodeToString(instance);
+                        }
+
+                        @Override
+                        public byte[] fromString(final String text) {
+                            return Base64.getUrlDecoder().decode(text.getBytes(StandardCharsets.UTF_8));
+                        }
+                    });
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unsupported binary configuration: " + bin);
+            }
+        });
+
+        return new JohnsonJsonb(builder.build());
+    }
+
+    private Map<String, ?> generatorConfig() {
+        final Map<String, Object> map = new HashMap<>();
+        if (config == null) {
+            return map;
+        }
+        config.getProperty(JsonGeneratorFactoryImpl.GENERATOR_BUFFER_LENGTH).ifPresent(b -> map.put(JsonGeneratorFactoryImpl.GENERATOR_BUFFER_LENGTH, b));
+        config.getProperty(AbstractJsonFactory.BUFFER_STRATEGY).ifPresent(b -> map.put(AbstractJsonFactory.BUFFER_STRATEGY, b));
+        config.getProperty(JsonbConfig.FORMATTING).ifPresent(b -> map.put(JsonGenerator.PRETTY_PRINTING, b));
+        return map;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonProvider.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonProvider.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonProvider.java
new file mode 100644
index 0000000..d21b915
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonProvider.java
@@ -0,0 +1,29 @@
+/*
+ * 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 javax.json.bind.JsonbBuilder;
+import javax.json.bind.spi.JsonbProvider;
+
+public class JohnzonProvider extends JsonbProvider {
+    @Override
+    public JsonbBuilder create() {
+        return new JohnzonBuilder();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/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
new file mode 100644
index 0000000..0bd3443
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
@@ -0,0 +1,454 @@
+/*
+ * 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.apache.johnzon.jsonb.converter.JsonbConverter;
+import org.apache.johnzon.jsonb.converter.JsonbDateConverter;
+import org.apache.johnzon.jsonb.converter.JsonbLocalDateConverter;
+import org.apache.johnzon.jsonb.converter.JsonbLocalDateTimeConverter;
+import org.apache.johnzon.jsonb.converter.JsonbNumberConverter;
+import org.apache.johnzon.jsonb.converter.JsonbValueConverter;
+import org.apache.johnzon.jsonb.converter.JsonbZonedDateTimeConverter;
+import org.apache.johnzon.mapper.Converter;
+import org.apache.johnzon.mapper.access.AccessMode;
+import org.apache.johnzon.mapper.access.FieldAccessMode;
+import org.apache.johnzon.mapper.access.FieldAndMethodAccessMode;
+import org.apache.johnzon.mapper.access.MethodAccessMode;
+
+import javax.json.bind.JsonbException;
+import javax.json.bind.annotation.JsonbAnnotation;
+import javax.json.bind.annotation.JsonbCreator;
+import javax.json.bind.annotation.JsonbDateFormat;
+import javax.json.bind.annotation.JsonbNillable;
+import javax.json.bind.annotation.JsonbNumberFormat;
+import javax.json.bind.annotation.JsonbProperty;
+import javax.json.bind.annotation.JsonbPropertyOrder;
+import javax.json.bind.annotation.JsonbTransient;
+import javax.json.bind.annotation.JsonbTypeAdapter;
+import javax.json.bind.annotation.JsonbValue;
+import javax.json.bind.config.PropertyNamingStrategy;
+import javax.json.bind.config.PropertyOrderStrategy;
+import javax.json.bind.config.PropertyVisibilityStrategy;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Parameter;
+import java.lang.reflect.Type;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Stream;
+
+import static java.util.Arrays.asList;
+import static org.apache.johnzon.mapper.reflection.Converters.matches;
+
+public class JsonbAccessMode implements AccessMode {
+    private final PropertyNamingStrategy naming;
+    private final String order;
+    private final PropertyVisibilityStrategy visibility;
+    private final FieldAndMethodAccessMode delegate;
+    private final boolean caseSensitive;
+
+    public JsonbAccessMode(final PropertyNamingStrategy propertyNamingStrategy, final String orderValue,
+                           final PropertyVisibilityStrategy visibilityStrategy, final boolean caseSensitive) {
+        this.naming = propertyNamingStrategy;
+        this.order = orderValue;
+        this.visibility = visibilityStrategy;
+        this.caseSensitive = caseSensitive;
+        this.delegate = new FieldAndMethodAccessMode(true, false);
+    }
+
+    @Override
+    public Factory findFactory(final Class<?> clazz) {
+        Constructor<?> constructor = null;
+        Method factory = null;
+        for (final Constructor<?> c : clazz.getConstructors()) {
+            if (c.isAnnotationPresent(JsonbCreator.class)) {
+                if (constructor != null) {
+                    throw new IllegalArgumentException("Only one constructor or method can have @JsonbCreator");
+                }
+                constructor = c;
+            }
+        }
+        for (final Method m : clazz.getMethods()) {
+            final int modifiers = m.getModifiers();
+            if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) && m.isAnnotationPresent(JsonbCreator.class)) {
+                if (constructor != null || factory != null) {
+                    throw new IllegalArgumentException("Only one constructor or method can have @JsonbCreator");
+                }
+                factory = m;
+            }
+        }
+        final Constructor<?> finalConstructor = constructor;
+        final Method finalFactory = factory;
+        final Type[] types;
+        final String[] params;
+        final Converter<?>[] converters;
+        final Converter<?>[] itemConverters;
+        if (finalConstructor != null || finalFactory != null) {
+            types = finalConstructor != null ? finalConstructor.getGenericParameterTypes() : finalFactory.getGenericParameterTypes();
+            params = new String[types.length];
+            converters = new Converter[types.length];
+            itemConverters = new Converter[types.length];
+            int i = 0;
+            for (final Parameter parameter : (finalConstructor == null ? finalFactory : finalConstructor).getParameters()) {
+                final JsonbProperty property = parameter.getAnnotation(JsonbProperty.class);
+                params[i] = property != null ? property.value() : parameter.getName();
+
+                final JsonbTypeAdapter adapter = parameter.getAnnotation(JsonbTypeAdapter.class);
+                final JsonbDateFormat dateFormat = parameter.getAnnotation(JsonbDateFormat.class);
+                final JsonbNumberFormat numberFormat = parameter.getAnnotation(JsonbNumberFormat.class);
+                final JsonbValue value = parameter.getAnnotation(JsonbValue.class);
+                if (adapter == null && dateFormat == null && numberFormat == null && value == null) {
+                    converters[i] = null;
+                    itemConverters[i] = null;
+                } else {
+                    validateAnnotations(parameter, adapter, dateFormat, numberFormat, value);
+
+                    try {
+                        final Converter<?> converter = toConverter(parameter.getType(), adapter, dateFormat, numberFormat);
+                        if (matches(parameter.getParameterizedType(), converter)) {
+                            converters[i] = converter;
+                            itemConverters[i] = null;
+                        } else {
+                            converters[i] = null;
+                            itemConverters[i] = converter;
+                        }
+                    } catch (final InstantiationException | IllegalAccessException e) {
+                        throw new IllegalArgumentException(e);
+                    }
+
+                }
+                i++;
+            }
+        } else {
+            types = null;
+            params = null;
+            converters = null;
+            itemConverters = null;
+        }
+
+        return constructor == null && factory == null ? delegate.findFactory(clazz) : (
+            constructor != null ?
+                new Factory() {
+                    @Override
+                    public Object create(final Object[] params) {
+                        try {
+                            return finalConstructor.newInstance(params);
+                        } catch (final InstantiationException | IllegalAccessException e) {
+                            throw new IllegalStateException(e);
+                        } catch (final InvocationTargetException e) {
+                            throw new IllegalStateException(e.getCause());
+                        }
+                    }
+
+                    @Override
+                    public Type[] getParameterTypes() {
+                        return types;
+                    }
+
+                    @Override
+                    public String[] getParameterNames() {
+                        return params;
+                    }
+
+                    @Override
+                    public Converter<?>[] getParameterConverter() {
+                        return converters;
+                    }
+
+                    @Override
+                    public Converter<?>[] getParameterItemConverter() {
+                        return itemConverters;
+                    }
+                } :
+                new Factory() {
+                    @Override
+                    public Object create(final Object[] params) {
+                        try {
+                            final Object invoke = finalFactory.invoke(null, params);
+                            if (!clazz.isInstance(invoke)) {
+                                throw new IllegalArgumentException(invoke + " is not a " + clazz.getName());
+                            }
+                            return invoke;
+                        } catch (final IllegalAccessException e) {
+                            throw new IllegalStateException(e);
+                        } catch (final InvocationTargetException e) {
+                            throw new IllegalStateException(e.getCause());
+                        }
+                    }
+
+                    @Override
+                    public Type[] getParameterTypes() {
+                        return types;
+                    }
+
+                    @Override
+                    public String[] getParameterNames() {
+                        return params;
+                    }
+
+                    @Override
+                    public Converter<?>[] getParameterConverter() {
+                        return converters;
+                    }
+
+                    @Override
+                    public Converter<?>[] getParameterItemConverter() {
+                        return itemConverters;
+                    }
+                });
+    }
+
+    private void validateAnnotations(final Object parameter,
+                                     final JsonbTypeAdapter adapter, final JsonbDateFormat dateFormat,
+                                     final JsonbNumberFormat numberFormat, final JsonbValue value) {
+        int notNull = adapter != null ? 1 : 0;
+        notNull += dateFormat != null ? 1 : 0;
+        notNull += numberFormat != null ? 1 : 0;
+        notNull += value != null ? 1 : 0;
+        if (notNull > 1) {
+            throw new IllegalArgumentException("Conflicting @JsonbXXX on " + parameter);
+        }
+    }
+
+    private Converter<?> toConverter(final Type type,
+                                     final JsonbTypeAdapter adapter, final JsonbDateFormat dateFormat,
+                                     final JsonbNumberFormat numberFormat) throws InstantiationException, IllegalAccessException {
+        final Converter<?> converter;
+        if (adapter != null) {
+            converter = new JsonbConverter(adapter.value().newInstance());
+        } else if (dateFormat != null) { // TODO: support lists, LocalDate?
+            if (Date.class == type) {
+                converter = new JsonbDateConverter(dateFormat);
+            } else if (LocalDateTime.class == type) {
+                converter = new JsonbLocalDateTimeConverter(dateFormat);
+            } else if (LocalDate.class == type) {
+                converter = new JsonbLocalDateConverter(dateFormat);
+            } else if (ZonedDateTime.class == type) {
+                converter = new JsonbZonedDateTimeConverter(dateFormat);
+            } else {
+                throw new IllegalArgumentException(type + " not a supported date type");
+            }
+        } else if (numberFormat != null) {  // TODO: support lists?
+            converter = new JsonbNumberConverter(numberFormat);
+        } else {
+            converter = new JsonbValueConverter();
+        }
+        return converter;
+    }
+
+    @Override
+    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 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 (shouldSkip(visibility, value)) {
+                continue;
+            }
+
+            // we are visible
+            final JsonbProperty property = value.getAnnotation(JsonbProperty.class);
+            final JsonbNillable nillable = value.getAnnotation(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 Converter<?> converter;
+            try {
+                converter = adapter == null && dateFormat == null && numberFormat == null && jsonbValue == null ? null :
+                    toConverter(value.getType(), adapter, dateFormat, numberFormat);
+            } catch (final InstantiationException | IllegalAccessException e) {
+                throw new IllegalArgumentException(e);
+            }
+
+            result.put(property == null || property.value().isEmpty() ? naming.translateName(entry.getKey()) : property.value(), new Reader() {
+                @Override
+                public Object read(final Object instance) {
+                    return value.read(instance);
+                }
+
+                @Override
+                public Type getType() {
+                    return value.getType();
+                }
+
+                @Override
+                public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
+                    return value.getAnnotation(clazz);
+                }
+
+                @Override
+                public Converter<?> findConverter() {
+                    return converter;
+                }
+
+                @Override
+                public boolean isNillable() {
+                    return isNillable;
+                }
+            });
+        }
+        return result;
+    }
+
+    @Override
+    public Map<String, Writer> findWriters(final Class<?> clazz) {
+        final Map<String, Writer> writers = delegate.findWriters(clazz);
+
+        final Comparator<String> keyComparator = orderComparator(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 (shouldSkip(visibility, value)) {
+                continue;
+            }
+
+            // we are visible
+            final JsonbProperty property = value.getAnnotation(JsonbProperty.class);
+            final JsonbNillable nillable = value.getAnnotation(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 Converter<?> converter;
+            try {
+                converter = adapter == null && dateFormat == null && numberFormat == null && jsonbValue == null ? null :
+                    toConverter(value.getType(), adapter, dateFormat, numberFormat);
+            } catch (final InstantiationException | IllegalAccessException e) {
+                throw new IllegalArgumentException(e);
+            }
+
+            result.put(property == null || property.value().isEmpty() ? naming.translateName(entry.getKey()) : property.value(), new Writer() {
+                @Override
+                public void write(final Object instance, final Object val) {
+                    value.write(instance, val);
+                }
+
+                @Override
+                public Type getType() {
+                    return value.getType();
+                }
+
+                @Override
+                public <T extends Annotation> T getAnnotation(final Class<T> clazz) {
+                    return value.getAnnotation(clazz);
+                }
+
+                @Override
+                public Converter<?> findConverter() {
+                    return converter;
+                }
+
+                @Override
+                public boolean isNillable() {
+                    return isNillable;
+                }
+            });
+        }
+        return result;
+    }
+
+    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())
+                    .map(t -> shouldSkip(visibility, t))
+                    .filter(a -> a)
+                    .findAny()
+                    .isPresent());
+    }
+
+    private boolean shouldSkip(final PropertyVisibilityStrategy visibility, final DecoratedType t) {
+        return t.getAnnotation(JsonbTransient.class) != null ||
+            (FieldAccessMode.FieldDecoratedType.class.isInstance(t) && !visibility.isVisible(FieldAccessMode.FieldDecoratedType.class.cast(t).getField())) ||
+            (MethodAccessMode.MethodDecoratedType.class.isInstance(t) && !visibility.isVisible(MethodAccessMode.MethodDecoratedType.class.cast(t).getMethod()));
+    }
+
+    private boolean checkTransient(final Annotation[] annotations) {
+        boolean hasTransient = false;
+        boolean hasJsonb = false;
+        for (final Annotation a : annotations) {
+            if (a.annotationType() == JsonbTransient.class) {
+                hasTransient = true;
+            } else if (a.annotationType().isAnnotationPresent(JsonbAnnotation.class)) {
+                hasJsonb = true;
+            }
+        }
+        if (hasJsonb && hasTransient) {
+            throw new JsonbException("@JsonbTransient doesnt work with other @JsonbXXX: " + asList(annotations));
+        }
+        return hasTransient;
+    }
+
+    private Comparator<String> orderComparator(final Class<?> clazz) {
+        final Comparator<String> keyComparator;
+        final JsonbPropertyOrder orderAnnotation = clazz.getAnnotation(JsonbPropertyOrder.class);
+        if (orderAnnotation != null) {
+            final List<String> indexed = new ArrayList<>(asList(orderAnnotation.value()));
+            keyComparator = (o1, o2) -> {
+                final int i1 = indexed.indexOf(o1);
+                final int i2 = indexed.indexOf(o2);
+                if (i1 < 0) {
+                    return 1;
+                }
+                return i1 - i2;
+            };
+        } else if (order != null) {
+            switch (order) {
+                case PropertyOrderStrategy.ANY:
+                    keyComparator = null;
+                    break;
+                case PropertyOrderStrategy.LEXICOGRAPHICAL:
+                    keyComparator = String::compareTo;
+                    break;
+                case PropertyOrderStrategy.REVERSE:
+                    keyComparator = (o1, o2) -> o2.compareTo(o1);
+                    break;
+                default:
+                    keyComparator = null;
+            }
+        } else {
+            keyComparator = null;
+        }
+        return keyComparator;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/PropertyNamingStrategyFactory.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/PropertyNamingStrategyFactory.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/PropertyNamingStrategyFactory.java
new file mode 100644
index 0000000..badfc15
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/PropertyNamingStrategyFactory.java
@@ -0,0 +1,98 @@
+/*
+ * 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 javax.json.bind.config.PropertyNamingStrategy;
+import java.util.function.Function;
+
+public class PropertyNamingStrategyFactory {
+    private final Object value;
+
+    public PropertyNamingStrategyFactory(final Object value) {
+        this.value = value;
+    }
+
+    public PropertyNamingStrategy create() {
+        if (String.class.isInstance(value)) {
+            final String val = value.toString();
+            switch (val) {
+                case PropertyNamingStrategy.IDENTITY:
+                    return propertyName -> propertyName;
+                case PropertyNamingStrategy.LOWER_CASE_WITH_DASHES:
+                    return new ConfigurableNamingStrategy(Character::toLowerCase, '-');
+                case PropertyNamingStrategy.LOWER_CASE_WITH_UNDERSCORES:
+                    return new ConfigurableNamingStrategy(Character::toLowerCase, '_');
+                case PropertyNamingStrategy.UPPER_CAMEL_CASE:
+                    return camelCaseStrategy();
+                case PropertyNamingStrategy.UPPER_CAMEL_CASE_WITH_SPACES:
+                    final PropertyNamingStrategy camelCase = camelCaseStrategy();
+                    final PropertyNamingStrategy space = new ConfigurableNamingStrategy(Function.identity(), ' ');
+                    return propertyName -> camelCase.translateName(space.translateName(propertyName));
+                case PropertyNamingStrategy.CASE_INSENSITIVE:
+                    return propertyName -> propertyName;
+                default:
+                    throw new IllegalArgumentException(val + " unknown as PropertyNamingStrategy");
+            }
+        }
+        if (PropertyNamingStrategy.class.isInstance(value)) {
+            return PropertyNamingStrategy.class.cast(value);
+        }
+        throw new IllegalArgumentException(value + " not supported as PropertyNamingStrategy");
+    }
+
+    private PropertyNamingStrategy camelCaseStrategy() {
+        return propertyName -> Character.toUpperCase(propertyName.charAt(0)) + (propertyName.length() > 1 ? propertyName.substring(1) : "");
+    }
+
+    private static class ConfigurableNamingStrategy implements PropertyNamingStrategy {
+        private final Function<Character, Character> converter;
+        private final char separator;
+
+        public ConfigurableNamingStrategy(final Function<Character, Character> wordConverter, final char sep) {
+            this.converter = wordConverter;
+            this.separator = sep;
+        }
+
+        @Override
+        public String translateName(final String propertyName) {
+            final StringBuilder global = new StringBuilder();
+
+            final StringBuilder current = new StringBuilder();
+            for (int i = 0; i < propertyName.length(); i++) {
+                final char c = propertyName.charAt(i);
+                if (Character.isUpperCase(c)) {
+                    final char transformed = converter.apply(c);
+                    if (current.length() > 0) {
+                        global.append(current).append(separator);
+                        current.setLength(0);
+                    }
+                    current.append(transformed);
+                } else {
+                    current.append(c);
+                }
+            }
+            if (current.length() > 0) {
+                global.append(current);
+            } else {
+                global.setLength(global.length() - 1); // remove last sep
+            }
+            return global.toString();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbConverter.java
new file mode 100644
index 0000000..9758d6e
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbConverter.java
@@ -0,0 +1,51 @@
+/*
+ * 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.converter;
+
+import org.apache.johnzon.mapper.Converter;
+
+import javax.json.bind.JsonbException;
+import javax.json.bind.adapter.JsonbAdapter;
+
+// TODO
+public class JsonbConverter implements Converter<Object> {
+    private final JsonbAdapter adapter;
+
+    public JsonbConverter(final JsonbAdapter adapter) {
+        this.adapter = adapter;
+    }
+
+    @Override
+    public String toString(final Object instance) {
+        try {
+            return adapter.adaptTo(instance);
+        } catch (final Exception e) {
+            throw new JsonbException(e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public Object fromString(String text) {
+        try {
+            return adapter.adaptFrom(text);
+        } catch (final Exception e) {
+            throw new JsonbException(e.getMessage(), e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverter.java
new file mode 100644
index 0000000..813009c
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverter.java
@@ -0,0 +1,41 @@
+/*
+ * 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.converter;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.Date;
+
+public class JsonbDateConverter extends JsonbDateConverterBase<Date> {
+    public JsonbDateConverter(final JsonbDateFormat dateFormat) {
+        super(dateFormat);
+    }
+
+    @Override
+    public String toString(final Date instance) {
+        return formatter == null ? Long.toString(instance.getTime()) : formatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(instance.getTime()), ZoneOffset.UTC));
+    }
+
+    @Override
+    public Date fromString(final String text) {
+        return formatter == null ? new Date(Long.parseLong(text)) : Date.from(LocalDateTime.parse(text, formatter).toInstant(ZoneOffset.UTC));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverterBase.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverterBase.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverterBase.java
new file mode 100644
index 0000000..8d961c4
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbDateConverterBase.java
@@ -0,0 +1,35 @@
+/*
+ * 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.converter;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import java.time.format.DateTimeFormatter;
+
+public abstract class JsonbDateConverterBase<T> extends JsonbLocaleParserConverterBase<T> {
+    protected final DateTimeFormatter formatter;
+
+    protected JsonbDateConverterBase(final JsonbDateFormat dateFormat) {
+        final String value = dateFormat.value();
+        final String locale = dateFormat.locale();
+        final boolean ms = value.equals(JsonbDateFormat.TIME_IN_MILLIS);
+        formatter = ms ? null :
+            (!locale.equals(JsonbDateFormat.DEFAULT_LOCALE) ?
+                DateTimeFormatter.ofPattern(value).withLocale(newLocale(locale)) : DateTimeFormatter.ofPattern(value));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateConverter.java
new file mode 100644
index 0000000..fa8578d
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateConverter.java
@@ -0,0 +1,39 @@
+/*
+ * 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.converter;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import java.time.LocalDate;
+import java.util.concurrent.TimeUnit;
+
+public class JsonbLocalDateConverter extends JsonbDateConverterBase<LocalDate> {
+    public JsonbLocalDateConverter(final JsonbDateFormat dateFormat) {
+        super(dateFormat);
+    }
+
+    @Override
+    public String toString(final LocalDate instance) {
+        return formatter == null ? Long.toString(TimeUnit.DAYS.toMillis(instance.toEpochDay())) : instance.format(formatter);
+    }
+
+    @Override
+    public LocalDate fromString(final String text) {
+        return formatter == null ? LocalDate.ofEpochDay(TimeUnit.MILLISECONDS.toDays(Long.parseLong(text))) : LocalDate.parse(text, formatter);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateTimeConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateTimeConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateTimeConverter.java
new file mode 100644
index 0000000..b0c3018
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocalDateTimeConverter.java
@@ -0,0 +1,40 @@
+/*
+ * 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.converter;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+public class JsonbLocalDateTimeConverter extends JsonbDateConverterBase<LocalDateTime> {
+    public JsonbLocalDateTimeConverter(final JsonbDateFormat dateFormat) {
+        super(dateFormat);
+    }
+
+    @Override
+    public String toString(final LocalDateTime instance) {
+        return formatter == null ? Long.toString(instance.toInstant(ZoneOffset.UTC).toEpochMilli()) : instance.format(formatter);
+    }
+
+    @Override
+    public LocalDateTime fromString(final String text) {
+        return formatter == null ? LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(text)), ZoneOffset.UTC) : LocalDateTime.parse(text, formatter);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocaleParserConverterBase.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocaleParserConverterBase.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocaleParserConverterBase.java
new file mode 100644
index 0000000..414a7a5
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbLocaleParserConverterBase.java
@@ -0,0 +1,35 @@
+/*
+ * 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.converter;
+
+import org.apache.johnzon.mapper.Converter;
+
+import java.util.Locale;
+
+public abstract class JsonbLocaleParserConverterBase<T> implements Converter<T> {
+    protected Locale newLocale(final String locale) {
+        final String[] parts = locale.split("-");
+        switch (parts.length) {
+            case 1: return new Locale(locale);
+            case 2: return new Locale(parts[0], parts[1]);
+            case 3: return new Locale(parts[0], parts[1], parts[2]);
+            default: throw new IllegalArgumentException(locale);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbNumberConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbNumberConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbNumberConverter.java
new file mode 100644
index 0000000..563968e
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbNumberConverter.java
@@ -0,0 +1,77 @@
+/*
+ * 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.converter;
+
+import javax.json.bind.annotation.JsonbNumberFormat;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.Queue;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+public class JsonbNumberConverter extends JsonbLocaleParserConverterBase<Number> {
+    private final Supplier<NumberFormat> delegateFactory; // NumberFormat is not thread safe
+    private final Queue<NumberFormat> pool = new ArrayBlockingQueue<>(30); // configurable?
+
+    public JsonbNumberConverter(final JsonbNumberFormat numberFormat) {
+        final String locale = numberFormat.locale();
+        final String format = numberFormat.value();
+        final boolean customLocale = !JsonbNumberFormat.DEFAULT_LOCALE.equals(locale);
+        if (format.isEmpty() && customLocale) {
+            delegateFactory = () -> NumberFormat.getInstance(newLocale(locale));
+        } else if (format.isEmpty()) {
+            delegateFactory = NumberFormat::getInstance;
+        } else if (customLocale) {
+            delegateFactory = () -> new DecimalFormat(format, DecimalFormatSymbols.getInstance(newLocale(locale)));
+        } else {
+            delegateFactory = () -> new DecimalFormat(format);
+        }
+    }
+
+    @Override
+    public String toString(final Number instance) {
+        return execute(f -> f.format(instance));
+    }
+
+    @Override
+    public Number fromString(final String text) {
+        return execute(f -> {
+            try {
+                return f.parse(text);
+            } catch (final ParseException e) {
+                throw new IllegalArgumentException(e);
+            }
+        });
+    }
+
+    private <T> T execute(final Function<NumberFormat, T> function) {
+        NumberFormat format = pool.poll();
+        if (format == null) {
+            format = delegateFactory.get();
+        }
+        try {
+            return function.apply(format);
+        } finally {
+            pool.add(format);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbValueConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbValueConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbValueConverter.java
new file mode 100644
index 0000000..a4b6ec3
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbValueConverter.java
@@ -0,0 +1,34 @@
+/*
+ * 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.converter;
+
+import org.apache.johnzon.mapper.Converter;
+
+// TODO?
+public class JsonbValueConverter implements Converter<Object> {
+    @Override
+    public String toString(final Object instance) {
+        return String.valueOf(instance);
+    }
+
+    @Override
+    public Object fromString(final String text) {
+        return text;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbZonedDateTimeConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbZonedDateTimeConverter.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbZonedDateTimeConverter.java
new file mode 100644
index 0000000..d5ce9fc
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbZonedDateTimeConverter.java
@@ -0,0 +1,42 @@
+/*
+ * 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.converter;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+
+public class JsonbZonedDateTimeConverter extends JsonbDateConverterBase<ZonedDateTime> {
+    private static final ZoneId UTC = ZoneId.of("UTC");
+
+    public JsonbZonedDateTimeConverter(final JsonbDateFormat dateFormat) {
+        super(dateFormat);
+    }
+
+    @Override
+    public String toString(final ZonedDateTime instance) {
+        return formatter == null ? Long.toString(instance.toInstant().toEpochMilli()) : instance.format(formatter);
+    }
+
+    @Override
+    public ZonedDateTime fromString(final String text) {
+        return formatter == null ? ZonedDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(text)), UTC) : ZonedDateTime.parse(text, formatter);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/main/resources/META-INF/services/javax.json.bind.spi.JsonbProvider
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/resources/META-INF/services/javax.json.bind.spi.JsonbProvider b/johnzon-jsonb/src/main/resources/META-INF/services/javax.json.bind.spi.JsonbProvider
new file mode 100644
index 0000000..4edadc5
--- /dev/null
+++ b/johnzon-jsonb/src/main/resources/META-INF/services/javax.json.bind.spi.JsonbProvider
@@ -0,0 +1 @@
+org.apache.johnzon.jsonb.JohnzonProvider

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonProviderTest.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonProviderTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonProviderTest.java
new file mode 100644
index 0000000..b35bd2d
--- /dev/null
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonProviderTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.Test;
+
+import javax.json.bind.spi.JsonbProvider;
+
+import static org.junit.Assert.assertNotNull;
+
+public class JohnzonProviderTest {
+    @Test
+    public void provider() {
+        assertNotNull(JsonbProvider.provider());
+    }
+
+    @Test
+    public void create() {
+        assertNotNull(JsonbProvider.provider().create());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbReadTest.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbReadTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbReadTest.java
new file mode 100644
index 0000000..4b19cff
--- /dev/null
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbReadTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.Test;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import javax.json.bind.annotation.JsonbProperty;
+import javax.json.bind.spi.JsonbProvider;
+import java.io.StringReader;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+import static org.junit.Assert.assertEquals;
+
+public class JsonbReadTest {
+    @Test
+    public void simple() {
+        assertEquals("test", JsonbProvider.provider().create().build().fromJson(new StringReader("{\"value\":\"test\"}"), Simple.class).value);
+    }
+
+    @Test
+    public void propertyMapping() {
+        assertEquals("test", JsonbProvider.provider().create().build().fromJson(new StringReader("{\"simple\":\"test\"}"), SimpleProperty.class).value);
+    }
+
+    @Test
+    public void date() { // ok, can fail at midnight, acceptable risk
+        final String date = DateTimeFormatter.ofPattern("d. LLLL yyyy").format(LocalDate.now());
+        assertEquals(
+            LocalDate.now().getYear(),
+            JsonbProvider.provider().create().build().fromJson(new StringReader("{\"date\":\"" + date + "\"}"), DateFormatting.class).date.getYear());
+    }
+
+    public static class Simple {
+        private String value;
+
+        public String getValue() {
+            return value;
+        }
+
+        public void setValue(final String value) {
+            this.value = value;
+        }
+    }
+
+    public static class SimpleProperty {
+        @JsonbProperty("simple")
+        private String value;
+
+        public String getValue() {
+            return value;
+        }
+
+        public void setValue(final String value) {
+            this.value = value;
+        }
+    }
+
+    public static class SimplePropertyNillable {
+        @JsonbProperty(nillable = true)
+        private String value;
+
+        public String getValue() {
+            return value;
+        }
+
+        public void setValue(final String value) {
+            this.value = value;
+        }
+    }
+
+    public static class DateFormatting {
+        @JsonbDateFormat(value = "d. LLLL yyyy")
+        @JsonbProperty(nillable = true)
+        private LocalDate date;
+
+        public LocalDate getDate() {
+            return date;
+        }
+
+        public void setDate(final LocalDate value) {
+            this.date = value;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/b65d149a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbWriteTest.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbWriteTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbWriteTest.java
new file mode 100644
index 0000000..273c7fc
--- /dev/null
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JsonbWriteTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.Test;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import javax.json.bind.annotation.JsonbProperty;
+import javax.json.bind.spi.JsonbProvider;
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+
+public class JsonbWriteTest {
+    @Test
+    public void simple() {
+        final Simple simple = new Simple();
+        simple.setValue("test");
+        assertEquals("{\"value\":\"test\"}", JsonbProvider.provider().create().build().toJson(simple));
+    }
+
+    @Test
+    public void propertyMapping() {
+        final SimpleProperty simple = new SimpleProperty();
+        simple.setValue("test");
+        assertEquals("{\"simple\":\"test\"}", JsonbProvider.provider().create().build().toJson(simple));
+    }
+
+    @Test
+    public void map() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("a", "b");
+        assertEquals("{\"a\":\"b\"}", JsonbProvider.provider().create().build().toJson(map));
+    }
+
+    @Test
+    public void list() {
+        final Collection<String> map = asList("a", "b");
+        assertEquals("[\"a\",\"b\"]", JsonbProvider.provider().create().build().toJson(map));
+    }
+
+    @Test
+    public void propertyMappingNotNillable() {
+        final SimpleProperty simple = new SimpleProperty();
+        assertEquals("{}", JsonbProvider.provider().create().build().toJson(simple));
+    }
+
+    @Test
+    public void propertyNillable() {
+        final SimplePropertyNillable simple = new SimplePropertyNillable();
+        assertEquals("{\"value\":null}", JsonbProvider.provider().create().build().toJson(simple));
+    }
+
+    @Test
+    public void date() {
+        final DateFormatting simple = new DateFormatting();
+        simple.setDate(LocalDateTime.now());
+        assertEquals("{\"date\":\"" + LocalDateTime.now().getYear() + "\"}", JsonbProvider.provider().create().build().toJson(simple));
+    }
+
+    public static class Simple {
+        private String value;
+
+        public String getValue() {
+            return value;
+        }
+
+        public void setValue(final String value) {
+            this.value = value;
+        }
+    }
+
+    public static class SimpleProperty {
+        @JsonbProperty("simple")
+        private String value;
+
+        public String getValue() {
+            return value;
+        }
+
+        public void setValue(final String value) {
+            this.value = value;
+        }
+    }
+
+    public static class SimplePropertyNillable {
+        @JsonbProperty(nillable = true)
+        private String value;
+
+        public String getValue() {
+            return value;
+        }
+
+        public void setValue(final String value) {
+            this.value = value;
+        }
+    }
+
+    public static class DateFormatting {
+        @JsonbDateFormat(value = "yyyy")
+        @JsonbProperty(nillable = true)
+        private LocalDateTime date;
+
+        public LocalDateTime getDate() {
+            return date;
+        }
+
+        public void setDate(final LocalDateTime value) {
+            this.date = value;
+        }
+    }
+}