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:59 UTC

[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

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;
+        }
+    }
+}