http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-core/src/test/java/org/apache/johnzon/core/JsonNumberTest.java
----------------------------------------------------------------------
diff --git 
a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonNumberTest.java 
b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonNumberTest.java
index b610995..2a2a12d 100644
--- a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonNumberTest.java
+++ b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonNumberTest.java
@@ -18,17 +18,47 @@
  */
 package org.apache.johnzon.core;
 
-import java.math.BigInteger;
+import org.junit.Assert;
+import org.junit.Test;
 
 import javax.json.Json;
 import javax.json.JsonArray;
+import javax.json.JsonNumber;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.math.BigInteger;
 
-import org.junit.Assert;
-import org.junit.Test;
-
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
 
 
 public class JsonNumberTest {
+    @Test
+    public void nonZeroFractional() {
+        final JsonNumber number = Json.createArrayBuilder()
+                .add(12345.6489)
+                .build()
+                .getJsonNumber(0);
+        try {
+            number.intValueExact();
+            fail();
+        } catch (final ArithmeticException ae) {
+            // ok
+        }
+        try {
+            number.longValueExact();
+            fail();
+        } catch (final ArithmeticException ae) {
+            // ok
+        }
+    }
+    @Test
+    public void equals() {
+        final JsonNumber a = Json.createObjectBuilder().add("a", 
1).build().getJsonNumber("a");
+        final JsonNumber b = Json.createObjectBuilder().add("b", 
1.1).build().getJsonNumber("b");
+        assertFalse(a.equals(b));
+        assertFalse(b.equals(a));
+    }
     
     @Test(expected=ArithmeticException.class)
     public void testBigIntegerExact() {
@@ -48,4 +78,21 @@ public class JsonNumberTest {
        
     }
 
+    @Test
+    public void testBigIntegerButFromJustALongTooLong() {
+        final StringWriter writer = new StringWriter();
+        Json.createGenerator(writer).writeStartObject().write("value", new 
BigInteger("10002000000000000000")).writeEnd().close();
+        final String asJson = writer.toString();
+        final JsonNumber jsonNumber = Json.createReader(new 
StringReader(asJson)).readObject().getJsonNumber("value");
+        Assert.assertEquals(new BigInteger("10002000000000000000"), 
jsonNumber.bigIntegerValue());
+    }
+
+    @Test
+    public void testHashCode() {
+        JsonNumber a = Json.createObjectBuilder().add("a", 
1).build().getJsonNumber("a");
+        JsonNumber b = Json.createObjectBuilder().add("b", 
1.1).build().getJsonNumber("b");
+
+        Assert.assertEquals(a.hashCode(), a.bigDecimalValue().hashCode());
+        Assert.assertEquals(b.hashCode(), b.bigDecimalValue().hashCode());
+    }
 }

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-core/src/test/java/org/apache/johnzon/core/JsonObjectBuilderImplTest.java
----------------------------------------------------------------------
diff --git 
a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonObjectBuilderImplTest.java
 
b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonObjectBuilderImplTest.java
index 098967e..7ca990d 100644
--- 
a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonObjectBuilderImplTest.java
+++ 
b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonObjectBuilderImplTest.java
@@ -21,15 +21,29 @@ package org.apache.johnzon.core;
 import static org.junit.Assert.assertEquals;
 
 import javax.json.Json;
+import javax.json.JsonObject;
 import javax.json.JsonObjectBuilder;
 
 import org.junit.Test;
 
 public class JsonObjectBuilderImplTest {
     @Test
-    public void build() {
+    public void testBuild() {
         final JsonObjectBuilder builder = Json.createObjectBuilder();
         builder.add("a", "b");
-        assertEquals("{\"a\":\"b\"}", builder.build().toString());
+        JsonObject jsonObject = builder.build();
+        assertEquals("{\"a\":\"b\"}", jsonObject.toString());
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNullCheckValue() {
+        final JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("a", (Integer) null);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testNullCheckName() {
+        final JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add(null, "b");
     }
 }

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-core/src/test/java/org/apache/johnzon/core/JsonObjectImplTest.java
----------------------------------------------------------------------
diff --git 
a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonObjectImplTest.java 
b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonObjectImplTest.java
index e7b5c06..1557070 100644
--- a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonObjectImplTest.java
+++ b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonObjectImplTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import javax.json.Json;
 import javax.json.JsonObject;
@@ -32,6 +33,22 @@ import org.junit.Test;
 
 public class JsonObjectImplTest {
     @Test
+    public void boolErrors() {
+        {
+            final JsonObject val = Json.createObjectBuilder().add("a", 
true).build();
+            assertTrue(val.getBoolean("a"));
+        }
+        {
+            final JsonObject val = Json.createObjectBuilder().add("a", 
"wrong").build();
+            try {
+                val.getBoolean("a");
+                fail();
+            } catch (final ClassCastException cce) {
+                // ok
+            }
+        }
+    }
+    @Test
     public void objectToString() {
         final JsonObjectBuilder ob = Json.createObjectBuilder();
         ob.add("a", new JsonStringImpl("b"));

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-core/src/test/java/org/apache/johnzon/core/JsonParserTest.java
----------------------------------------------------------------------
diff --git 
a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonParserTest.java 
b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonParserTest.java
index e035789..2e0df04 100644
--- a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonParserTest.java
+++ b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonParserTest.java
@@ -229,7 +229,7 @@ public class JsonParserTest {
         
         ob.add("d", ab);
 
-        final JsonParser parser = 
Json.createParserFactory(Collections.<String, 
Object>emptyMap()).createParser(ob.build());
+        final JsonParser parser = 
Json.createParserFactory(Collections.EMPTY_MAP).createParser(ob.build());
         assertNotNull(parser);
         assertSimple(parser);
     }
@@ -247,18 +247,19 @@ public class JsonParserTest {
         assertNotNull(parser);
         assertSimple(parser);
     }
-    
+
     @Test
     public void simpleUTF16LE() {
         final JsonParser parser = 
Json.createParserFactory(null).createParser(Thread.currentThread()
-                
.getContextClassLoader().getResourceAsStream("json/simple_utf16le.json"),UTF_16LE);
+                
.getContextClassLoader().getResourceAsStream("json/simple_utf16le.json"), 
UTF_16LE);
         assertNotNull(parser);
         assertSimple(parser);
     }
     
     @Test
     public void simpleUTF16LEAutoDetect() {
-        final JsonParser parser = 
Json.createParserFactory(null).createParser(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/simple_utf16le.json"));
+        final JsonParser parser = 
Json.createParserFactory(null).createParser(Thread.currentThread().
+                
getContextClassLoader().getResourceAsStream("json/simple_utf16le.json"));
         assertNotNull(parser);
         assertSimple(parser);
     }

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-core/src/test/java/org/apache/johnzon/core/JsonReaderImplTest.java
----------------------------------------------------------------------
diff --git 
a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonReaderImplTest.java 
b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonReaderImplTest.java
index e9d3d74..fcb8182 100644
--- a/johnzon-core/src/test/java/org/apache/johnzon/core/JsonReaderImplTest.java
+++ b/johnzon-core/src/test/java/org/apache/johnzon/core/JsonReaderImplTest.java
@@ -42,13 +42,13 @@ import javax.json.JsonReaderFactory;
 import javax.json.JsonString;
 import javax.json.JsonStructure;
 import javax.json.JsonValue;
+import javax.json.stream.JsonParsingException;
 
 import org.junit.Test;
 
 public class JsonReaderImplTest {
 
 
-
     public JsonReaderImplTest() {
         if (!Charset.defaultCharset().equals(Charset.forName("UTF-8"))) {
             System.err.println("Default charset is " + 
Charset.defaultCharset() + ", must must be UTF-8");
@@ -63,6 +63,16 @@ public class JsonReaderImplTest {
         return Collections.EMPTY_MAP;
     }
 
+    @Test(expected = JsonParsingException.class)
+    public void badTypeObject() {
+        Json.createReaderFactory(getFactoryConfig()).createReader(new 
StringReader("[]")).readObject();
+    }
+
+    @Test(expected = JsonParsingException.class)
+    public void badTypeArray() {
+        Json.createReaderFactory(getFactoryConfig()).createReader(new 
StringReader("{}")).readArray();
+    }
+
     @Test
     public void simple() {
         final JsonReader reader = 
Json.createReaderFactory(getFactoryConfig()).createReader(
@@ -173,7 +183,7 @@ public class JsonReaderImplTest {
         assertEquals("hallo\u20acö\uffff \u08a5 
থ?ß§$%&´'`*+#\udbff\udfff", object.getString("নa"));
         reader.close();
     }
-    
+
     @Test
     public void specialKeysWithStringAsByteArrayInputStream() {
         final String s = "{\"\\\"a\":\"\u0055\",\"\u0055\":\"test2\"}";
@@ -348,7 +358,7 @@ public class JsonReaderImplTest {
         assertEquals(-2, array.getInt(1));
         reader.close();
     }
-    
+
     @Test
     public void simple2BadBufferSize8() {
         final JsonReader reader = Json.createReaderFactory(new HashMap<String, 
Object>() {
@@ -435,8 +445,8 @@ public class JsonReaderImplTest {
 
     @Test
     public void stringescapeVariousBufferSizes() {
-        final int[] buffersizes = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
-                26, 27, 28, 32, 64, 128, 1024, 8192 };
+        final int[] buffersizes = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+                26, 27, 28, 32, 64, 128, 1024, 8192};
 
         for (final int buffersize : buffersizes) {
             final String value = String.valueOf(buffersize);
@@ -474,7 +484,7 @@ public class JsonReaderImplTest {
     public void testGrowingString() throws Throwable {
         JsonReaderFactory factory = Json.createReaderFactory(null);
         StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < 40000; i++) {
+        for (int i = 0; i < 10000; i++) {
             sb.append('x');
             String growingString = sb.toString();
             String str = "[4, \"\", \"" + growingString + "\", \"\", \"" + 
growingString + "\", \"\", 400]";
@@ -507,7 +517,7 @@ public class JsonReaderImplTest {
             JsonReaderFactory factory = Json.createReaderFactory(config);
 
             StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < 1000; i++) {
+            for (int i = 0; i < 100; i++) {
                 sb.append('x');
                 String name = sb.toString();
                 String str = "[4, \"\", \"" + name + "\", \"\", \"" + name + 
"\", \"\", 400]";
@@ -558,4 +568,12 @@ public class JsonReaderImplTest {
             assertEquals(1234.5, JsonNumber.class.cast(value).doubleValue(), 
0.);
         }
     }
+
+
+    @Test(expected = JsonParsingException.class)
+    public void testInvalidNumber() {
+        String jsonWithIllegalNumber = "{\"val\":12.34-2}";
+        JsonReaderImpl.class.cast(Json.createReader(new 
StringReader(jsonWithIllegalNumber))).readObject();
+    }
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-core/src/test/java/org/apache/johnzon/core/OverflowTest.java
----------------------------------------------------------------------
diff --git 
a/johnzon-core/src/test/java/org/apache/johnzon/core/OverflowTest.java 
b/johnzon-core/src/test/java/org/apache/johnzon/core/OverflowTest.java
new file mode 100644
index 0000000..a6879cf
--- /dev/null
+++ b/johnzon-core/src/test/java/org/apache/johnzon/core/OverflowTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.core;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonWriter;
+import javax.json.JsonWriterFactory;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.HashMap;
+
+import static org.junit.Assert.assertEquals;
+
+public class OverflowTest {
+    @Test
+    public void ok() {
+        // normal content size
+        Json.createReaderFactory(new HashMap<String, Object>() {{
+            put(JsonParserFactoryImpl.MAX_STRING_LENGTH, "10");
+            put(JsonParserFactoryImpl.BUFFER_LENGTH, "2");
+        }}).createReader(new 
StringReader("{\"a\":\"b\",\n\"another\":\"value\"}")).readObject();
+
+        // oversized
+        final JsonObject object = Json.createReaderFactory(new HashMap<String, 
Object>() {{
+            put(JsonParserFactoryImpl.MAX_STRING_LENGTH, "10");
+            put(JsonParserFactoryImpl.BUFFER_LENGTH, "2");
+        }}).createReader(new StringReader("{\"a\":\"b\",\n\"another\":\"value 
very long\"}")).readObject();
+        assertEquals("value very long", object.getString("another"));
+    }
+
+    @Test(expected = ArrayIndexOutOfBoundsException.class)
+    public void ko() {
+        Json.createReaderFactory(new HashMap<String, Object>() {{
+            put(JsonParserFactoryImpl.MAX_STRING_LENGTH, "10");
+            put(JsonParserFactoryImpl.BUFFER_LENGTH, "2");
+            put(JsonParserFactoryImpl.AUTO_ADJUST_STRING_BUFFER, "false");
+        }}).createReader(new StringReader("{\"another\":\"value too 
long\"}")).readObject();
+    }
+
+    @Test
+    public void testVeryLargeJson() {
+        JsonWriterFactory writerFactory = Json.createWriterFactory(new 
HashMap<String, Object>() {{
+            put(JsonParserFactoryImpl.BUFFER_LENGTH, "256");
+        }});
+
+        int itemSize = 50000;
+
+        StringWriter sw = new StringWriter();
+        JsonWriter writer = writerFactory.createWriter(sw);
+
+        JsonArrayBuilder arrayBuilder = Json.createArrayBuilder();
+        for (int i = 0; i < itemSize; i++) {
+            arrayBuilder.add("0123456789012345-" + i);
+        }
+        writer.writeArray(arrayBuilder.build());
+
+        String json = sw.toString();
+        System.out.println("Created a JSON of size " + json.length() + " 
bytes");
+
+        // read it back in
+        JsonArray jsonArray = Json.createReader(new 
StringReader(json)).readArray();
+        Assert.assertEquals(itemSize, jsonArray.size());
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-core/src/test/resources/json/jsonPointerTest.json
----------------------------------------------------------------------
diff --git a/johnzon-core/src/test/resources/json/jsonPointerTest.json 
b/johnzon-core/src/test/resources/json/jsonPointerTest.json
new file mode 100644
index 0000000..8cdc1c9
--- /dev/null
+++ b/johnzon-core/src/test/resources/json/jsonPointerTest.json
@@ -0,0 +1,15 @@
+{
+  "foo": [
+    "bar",
+    "baz"
+  ],
+  "": 0,
+  "a/b": 1,
+  "c%d": 2,
+  "e^f": 3,
+  "g|h": 4,
+  "i\\j": 5,
+  "k\"l": 6,
+  " ": 7,
+  "m~n": 8
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-distribution/pom.xml
----------------------------------------------------------------------
diff --git a/johnzon-distribution/pom.xml b/johnzon-distribution/pom.xml
index 1240af0..ccb3d01 100644
--- a/johnzon-distribution/pom.xml
+++ b/johnzon-distribution/pom.xml
@@ -32,24 +32,23 @@
     <dependency>
       <groupId>org.apache.geronimo.specs</groupId>
       <artifactId>geronimo-json_1.0_spec</artifactId>
-      <version>${jsonspecversion}</version>
+      <version>${geronimo-jsonp.version}</version>
       <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.geronimo.specs</groupId>
       <artifactId>geronimo-json_1.0_spec</artifactId>
-      <version>${jsonspecversion}</version>
+      <version>${geronimo-jsonp.version}</version>
       <scope>compile</scope>
       <classifier>sources</classifier>
     </dependency>
     <dependency>
       <groupId>org.apache.geronimo.specs</groupId>
       <artifactId>geronimo-json_1.0_spec</artifactId>
-      <version>${jsonspecversion}</version>
+      <version>${geronimo-jsonp.version}</version>
       <scope>compile</scope>
       <classifier>javadoc</classifier>
     </dependency>
-
     <dependency>
       <groupId>org.apache.johnzon</groupId>
       <artifactId>johnzon-core</artifactId>

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java
----------------------------------------------------------------------
diff --git 
a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java
 
b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java
index dd8b79c..e543804 100644
--- 
a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java
+++ 
b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java
@@ -19,6 +19,7 @@
 package org.apache.johnzon.jaxrs;
 
 import org.apache.johnzon.mapper.MapperBuilder;
+import org.apache.johnzon.mapper.SerializeValueFilter;
 import org.apache.johnzon.mapper.access.AccessMode;
 
 import javax.json.JsonReaderFactory;
@@ -34,6 +35,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Type;
 import java.util.Comparator;
 import java.util.List;
@@ -116,6 +118,10 @@ public class ConfigurableJohnzonProvider<T> implements 
MessageBodyWriter<T>, Mes
         }
     }
 
+    public void setFailOnUnknownProperties(final boolean active) {
+        builder.setFailOnUnknownProperties(active);
+    }
+
     public void setSupportConstructors(final boolean supportConstructors) {
         builder.setSupportConstructors(supportConstructors);
     }
@@ -207,4 +213,33 @@ public class ConfigurableJohnzonProvider<T> implements 
MessageBodyWriter<T>, Mes
     public void setPrimitiveConverters(final boolean val) {
         builder.setPrimitiveConverters(val);
     }
+
+    public MapperBuilder setDeduplicateObjects(boolean deduplicateObjects) {
+        return builder.setDeduplicateObjects(deduplicateObjects);
+    }
+
+    public void setSerializeValueFilter(final String val) {
+        try {
+            builder.setSerializeValueFilter(SerializeValueFilter.class.cast(
+                    
Thread.currentThread().getContextClassLoader().loadClass(val).getConstructor().newInstance()));
+        } catch (final InstantiationException e) {
+            throw new IllegalArgumentException(e);
+        } catch (final IllegalAccessException e) {
+            throw new IllegalArgumentException(e);
+        } catch (final NoSuchMethodException e) {
+            throw new IllegalArgumentException(e);
+        } catch (final ClassNotFoundException e) {
+            throw new IllegalArgumentException(e);
+        } catch (InvocationTargetException e) {
+            throw new IllegalArgumentException(e.getCause());
+        }
+    }
+
+    public void setUseBigDecimalForFloats(final boolean 
useBigDecimalForFloats) {
+        builder.setUseBigDecimalForFloats(useBigDecimalForFloats);
+    }
+
+    public void setAutoAdjustStringBuffers(final boolean 
autoAdjustStringBuffers) {
+        builder.setAutoAdjustStringBuffers(autoAdjustStringBuffers);
+    }
 }

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JohnzonMessageBodyReader.java
----------------------------------------------------------------------
diff --git 
a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JohnzonMessageBodyReader.java
 
b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JohnzonMessageBodyReader.java
index f3d9a18..42fcbf0 100644
--- 
a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JohnzonMessageBodyReader.java
+++ 
b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JohnzonMessageBodyReader.java
@@ -58,8 +58,10 @@ public class JohnzonMessageBodyReader<T> extends 
IgnorableTypes implements Messa
     public boolean isReadable(final Class<?> rawType, final Type genericType,
                               final Annotation[] annotations, final MediaType 
mediaType) {
         return !isIgnored(rawType)
-                && InputStream.class != genericType && Reader.class != 
genericType && Response.class != genericType
-                && String.class != genericType
+                && !InputStream.class.isAssignableFrom(rawType)
+                && !Reader.class.isAssignableFrom(rawType)
+                && !Response.class.isAssignableFrom(rawType)
+                && !CharSequence.class.isAssignableFrom(rawType)
                 && !JsonStructure.class.isAssignableFrom(rawType);
     }
 

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JohnzonMessageBodyWriter.java
----------------------------------------------------------------------
diff --git 
a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JohnzonMessageBodyWriter.java
 
b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JohnzonMessageBodyWriter.java
index e6a8d36..6a3e163 100644
--- 
a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JohnzonMessageBodyWriter.java
+++ 
b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JohnzonMessageBodyWriter.java
@@ -65,12 +65,12 @@ public class JohnzonMessageBodyWriter<T> extends 
IgnorableTypes implements Messa
     public boolean isWriteable(final Class<?> rawType, final Type genericType,
                                final Annotation[] annotations, final MediaType 
mediaType) {
         return !isIgnored(rawType)
-                && InputStream.class != genericType
-                && OutputStream.class != genericType
-                && Writer.class != genericType
-                && StreamingOutput.class != genericType
-                && String.class != genericType
-                && Response.class != genericType
+                && !InputStream.class.isAssignableFrom(rawType)
+                && !OutputStream.class.isAssignableFrom(rawType)
+                && !Writer.class.isAssignableFrom(rawType)
+                && !StreamingOutput.class.isAssignableFrom(rawType)
+                && !CharSequence.class.isAssignableFrom(rawType)
+                && !Response.class.isAssignableFrom(rawType)
                 && !JsonStructure.class.isAssignableFrom(rawType);
     }
 

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java
----------------------------------------------------------------------
diff --git 
a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java
 
b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java
index 4df4a7c..a895e07 100644
--- 
a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java
+++ 
b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java
@@ -19,6 +19,7 @@
 package org.apache.johnzon.jaxrs;
 
 import org.apache.johnzon.mapper.MapperBuilder;
+import org.apache.johnzon.mapper.SerializeValueFilter;
 import org.apache.johnzon.mapper.access.AccessMode;
 
 import javax.json.JsonReaderFactory;
@@ -34,6 +35,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Type;
 import java.util.Comparator;
 import java.util.List;
@@ -43,14 +45,14 @@ import static java.util.Arrays.asList;
 
 @Provider
 @Produces({
-    "*/json",
-    "*/*+json", "*/x-json",
-    "*/javascript", "*/x-javascript"
+        "*/json",
+        "*/*+json", "*/x-json",
+        "*/javascript", "*/x-javascript"
 })
 @Consumes({
-    "*/json",
-    "*/*+json", "*/x-json",
-    "*/javascript", "*/x-javascript"
+        "*/json",
+        "*/*+json", "*/x-json",
+        "*/javascript", "*/x-javascript"
 })
 public class WildcardConfigurableJohnzonProvider<T> implements 
MessageBodyWriter<T>, MessageBodyReader<T> {
     // build/configuration
@@ -124,6 +126,10 @@ public class WildcardConfigurableJohnzonProvider<T> 
implements MessageBodyWriter
         }
     }
 
+    public void setFailOnUnknownProperties(final boolean active) {
+        builder.setFailOnUnknownProperties(active);
+    }
+
     public void setSupportConstructors(final boolean supportConstructors) {
         builder.setSupportConstructors(supportConstructors);
     }
@@ -215,4 +221,25 @@ public class WildcardConfigurableJohnzonProvider<T> 
implements MessageBodyWriter
     public void setPrimitiveConverters(final boolean val) {
         builder.setPrimitiveConverters(val);
     }
+
+    public void setUseBigDecimalForFloats(final boolean 
useBigDecimalForFloats) {
+        builder.setUseBigDecimalForFloats(useBigDecimalForFloats);
+    }
+
+    public void setSerializeValueFilter(final String val) {
+        try {
+            builder.setSerializeValueFilter(SerializeValueFilter.class.cast(
+                    
Thread.currentThread().getContextClassLoader().loadClass(val).getConstructor().newInstance()));
+        } catch (final InstantiationException e) {
+            throw new IllegalArgumentException(e);
+        } catch (final IllegalAccessException e) {
+            throw new IllegalArgumentException(e);
+        } catch (final NoSuchMethodException e) {
+            throw new IllegalArgumentException(e);
+        } catch (final ClassNotFoundException e) {
+            throw new IllegalArgumentException(e);
+        } catch (InvocationTargetException e) {
+            throw new IllegalArgumentException(e.getCause());
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/JohnzonProviderTest.java
----------------------------------------------------------------------
diff --git 
a/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/JohnzonProviderTest.java 
b/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/JohnzonProviderTest.java
index 6af6f68..a77752d 100644
--- 
a/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/JohnzonProviderTest.java
+++ 
b/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/JohnzonProviderTest.java
@@ -18,14 +18,20 @@
  */
 package org.apache.johnzon.jaxrs;
 
-import org.apache.cxf.endpoint.Server;
-import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
-import org.apache.cxf.jaxrs.client.WebClient;
-import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
-import org.apache.cxf.transport.local.LocalConduit;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
@@ -34,24 +40,25 @@ import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.client.Entity;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
 import javax.ws.rs.core.GenericType;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.StreamingOutput;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
 
-import static java.util.Arrays.asList;
-import static java.util.Collections.singletonList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.transport.local.LocalConduit;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
 
 public class JohnzonProviderTest {
+
     private final static String ENDPOINT_ADDRESS = "local://johnzon";
+
     private static Server server;
 
     @BeforeClass
@@ -72,7 +79,8 @@ public class JohnzonProviderTest {
 
     @Test
     public void asParam() {
-        final String result = 
client().path("johnzon").type(MediaType.APPLICATION_JSON_TYPE).post(new 
Johnzon("client")).readEntity(String.class);
+        final String result = 
client().path("johnzon").type(MediaType.APPLICATION_JSON_TYPE).post(new 
Johnzon("client"))
+                .readEntity(String.class);
         assertTrue(Boolean.parseBoolean(result));
     }
 
@@ -89,6 +97,19 @@ public class JohnzonProviderTest {
     }
 
     @Test
+    public void untypedStreamOutput() {
+        final StreamingOutput impl = new StreamingOutput() {
+
+            @Override
+            public void write(final OutputStream outputStream) throws 
IOException, WebApplicationException {
+                // no-op
+            }
+        };
+        assertFalse(new 
JohnzonMessageBodyWriter().isWriteable(impl.getClass(), impl.getClass(), new 
Annotation[0],
+                MediaType.APPLICATION_JSON_TYPE));
+    }
+
+    @Test
     public void primitive() {
         final String val = 
client(MediaType.TEXT_PLAIN_TYPE).path("johnzon/primitive").get(String.class);
         assertEquals("1986", val);
@@ -106,9 +127,10 @@ public class JohnzonProviderTest {
     @Test
     public void list() {
         final ParameterizedType list = new ParameterizedType() {
+
             @Override
             public Type[] getActualTypeArguments() {
-                return new Type[]{Johnzon.class};
+                return new Type[] { Johnzon.class };
             }
 
             @Override
@@ -146,12 +168,14 @@ public class JohnzonProviderTest {
     }
 
     private static WebClient client(final MediaType mediaType) {
-        final WebClient client = WebClient.create(ENDPOINT_ADDRESS, 
singletonList(new JohnzonProvider<Object>())).accept(mediaType);
+        final WebClient client = WebClient.create(ENDPOINT_ADDRESS, 
singletonList(new JohnzonProvider<Object>()))
+                .accept(mediaType);
         
WebClient.getConfig(client).getRequestContext().put(LocalConduit.DIRECT_DISPATCH,
 Boolean.TRUE);
         return client;
     }
 
     public static class Johnzon {
+
         private String name;
 
         public Johnzon(final String name) {
@@ -173,6 +197,7 @@ public class JohnzonProviderTest {
 
     @Path("johnzon")
     public static class JohnzonResource {
+
         @GET
         public Johnzon johnzon() {
             return new Johnzon("johnzon");
@@ -207,6 +232,7 @@ public class JohnzonProviderTest {
         @Path("stream")
         public StreamingOutput out() {
             return new StreamingOutput() {
+
                 @Override
                 public void write(OutputStream outputStream) throws 
IOException, WebApplicationException {
                     outputStream.write("ok".getBytes());
@@ -215,6 +241,18 @@ public class JohnzonProviderTest {
         }
 
         @GET
+        @Path("lazy_stream")
+        public void out(@Suspended final AsyncResponse response) {
+            response.resume(new StreamingOutput() {
+
+                @Override
+                public void write(OutputStream outputStream) throws 
IOException, WebApplicationException {
+                    outputStream.write("ok".getBytes());
+                }
+            });
+        }
+
+        @GET
         @Produces(MediaType.TEXT_PLAIN)
         @Path("primitive")
         public Integer primitive() {

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-jsonb/pom.xml
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/pom.xml b/johnzon-jsonb/pom.xml
index 66d49f6..9b52c33 100644
--- a/johnzon-jsonb/pom.xml
+++ b/johnzon-jsonb/pom.xml
@@ -27,6 +27,7 @@
 
   <artifactId>johnzon-jsonb</artifactId>
   <name>Johnzon :: JSON-B Implementation</name>
+  <packaging>bundle</packaging>
 
   <properties>
     <java-compile.version>1.8</java-compile.version>
@@ -35,24 +36,33 @@
 
   <dependencies>
     <dependency>
-      <groupId>javax.ws.rs</groupId>
-      <artifactId>javax.ws.rs-api</artifactId>
-      <version>2.0</version>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-annotation_1.2_spec</artifactId>
+      <version>1.0</version>
+      <scope>provided</scope>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-jaxrs_2.0_spec</artifactId>
+      <version>1.0-alpha-1</version>
       <scope>provided</scope>
+      <optional>true</optional>
     </dependency>
     <dependency>
       <groupId>org.apache.geronimo.specs</groupId>
       <artifactId>geronimo-jcdi_1.1_spec</artifactId>
       <version>1.0</version>
       <scope>provided</scope>
+      <optional>true</optional>
     </dependency>
-
     <dependency>
-      <groupId>org.apache.johnzon</groupId>
-      <artifactId>jsonb-api</artifactId>
-      <version>1.0.1-SNAPSHOT</version>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-jsonb_1.0_spec</artifactId>
+      <version>1.0</version>
       <scope>provided</scope>
     </dependency>
+
     <dependency>
       <groupId>org.apache.johnzon</groupId>
       <artifactId>johnzon-mapper</artifactId>
@@ -96,5 +106,19 @@
       <scope>test</scope>
     </dependency>
   </dependencies>
-  <packaging>bundle</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <configuration>
+          <instructions>
+            
<Require-Capability>osgi.extender;filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
+            
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=javax.json.bind.spi.JsonbProvider</Provide-Capability>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
 </project>

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-jsonb/src/main/java/org/apache/johnzon/jaxrs/jsonb/jaxrs/JsonbJaxrsProvider.java
----------------------------------------------------------------------
diff --git 
a/johnzon-jsonb/src/main/java/org/apache/johnzon/jaxrs/jsonb/jaxrs/JsonbJaxrsProvider.java
 
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jaxrs/jsonb/jaxrs/JsonbJaxrsProvider.java
index 189dce4..25cf998 100644
--- 
a/johnzon-jsonb/src/main/java/org/apache/johnzon/jaxrs/jsonb/jaxrs/JsonbJaxrsProvider.java
+++ 
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jaxrs/jsonb/jaxrs/JsonbJaxrsProvider.java
@@ -36,20 +36,34 @@ 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.annotation.Annotation;
 import java.lang.reflect.Type;
 import java.util.Collection;
-import java.util.concurrent.atomic.AtomicReference;
+import java.util.Properties;
+import java.util.function.Function;
+import java.util.logging.Logger;
+
+import javax.annotation.Priority;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.ext.ContextResolver;
+import javax.ws.rs.ext.Providers;
 
 // here while we dont compile in java 8 jaxrs module, when migrated we'll 
merge it with IgnorableTypes hierarchy at least
 @Provider
-@Produces("application/json")
-@Consumes("application/json")
-public class JsonbJaxrsProvider<T> implements MessageBodyWriter<T>, 
MessageBodyReader<T> {
-    private final Collection<String> ignores;
-    private final AtomicReference<Jsonb> delegate = new AtomicReference<>();
-    private final JsonbConfig config = new JsonbConfig();
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+@Priority(value = 4900)
+public class JsonbJaxrsProvider<T> implements MessageBodyWriter<T>, 
MessageBodyReader<T>, AutoCloseable {
+
+    protected final Collection<String> ignores;
+    protected final JsonbConfig config = new JsonbConfig();
+    protected volatile Function<Class<?>, Jsonb> delegate = null;
+    private boolean customized;
+
+    @Context
+    private Providers providers;
 
     public JsonbJaxrsProvider() {
         this(null);
@@ -59,41 +73,61 @@ public class JsonbJaxrsProvider<T> implements 
MessageBodyWriter<T>, MessageBodyR
         this.ignores = ignores;
     }
 
-    protected Jsonb createJsonb() {
-        return JsonbBuilder.create(config);
-    }
-
     private boolean isIgnored(final Class<?> type) {
         return ignores != null && ignores.contains(type.getName());
     }
 
     // config - main containers support the configuration of providers this way
+    public void setFailOnUnknownProperties(final boolean active) {
+        config.setProperty("johnzon.fail-on-unknown-properties", active);
+        customized = true;
+    }
+
+    public void setOtherProperties(final String others) {
+        final Properties properties = new Properties() {{
+            try {
+                load(new StringReader(others));
+            } catch (final IOException e) {
+                throw new IllegalArgumentException(e);
+            }
+        }};
+        properties.stringPropertyNames().forEach(k -> config.setProperty(k, 
properties.getProperty(k)));
+        customized = true;
+    }
+
     public void setIJson(final boolean active) {
         config.withStrictIJSON(active);
+        customized = true;
     }
 
     public void setEncoding(final String encoding) {
         config.withEncoding(encoding);
+        customized = true;
     }
 
     public void setBinaryDataStrategy(final String binaryDataStrategy) {
         config.withBinaryDataStrategy(binaryDataStrategy);
+        customized = true;
     }
 
     public void setPropertyNamingStrategy(final String propertyNamingStrategy) 
{
         config.withPropertyNamingStrategy(propertyNamingStrategy);
+        customized = true;
     }
 
     public void setPropertyOrderStrategy(final String propertyOrderStrategy) {
         config.withPropertyOrderStrategy(propertyOrderStrategy);
+        customized = true;
     }
 
     public void setNullValues(final boolean nulls) {
         config.withNullValues(nulls);
+        customized = true;
     }
 
     public void setPretty(final boolean pretty) {
         config.withFormatting(pretty);
+        customized = true;
     }
 
     // actual impl
@@ -101,21 +135,23 @@ public class JsonbJaxrsProvider<T> implements 
MessageBodyWriter<T>, MessageBodyR
     @Override
     public boolean isReadable(final Class<?> type, final Type genericType, 
final Annotation[] annotations, final MediaType mediaType) {
         return !isIgnored(type)
-            && InputStream.class != genericType && Reader.class != genericType 
&& Response.class != genericType
-            && String.class != genericType
-            && !JsonStructure.class.isAssignableFrom(type);
+                && !InputStream.class.isAssignableFrom(type)
+                && !Reader.class.isAssignableFrom(type)
+                && !Response.class.isAssignableFrom(type)
+                && !CharSequence.class.isAssignableFrom(type)
+                && !JsonStructure.class.isAssignableFrom(type);
     }
 
     @Override
     public boolean isWriteable(final Class<?> type, final Type genericType, 
final Annotation[] annotations, final MediaType mediaType) {
         return !isIgnored(type)
-            && InputStream.class != genericType
-            && OutputStream.class != genericType
-            && Writer.class != genericType
-            && StreamingOutput.class != genericType
-            && String.class != genericType
-            && Response.class != genericType
-            && !JsonStructure.class.isAssignableFrom(type);
+                && !InputStream.class.isAssignableFrom(type)
+                && !OutputStream.class.isAssignableFrom(type)
+                && !Writer.class.isAssignableFrom(type)
+                && !StreamingOutput.class.isAssignableFrom(type)
+                && !CharSequence.class.isAssignableFrom(type)
+                && !Response.class.isAssignableFrom(type)
+                && !JsonStructure.class.isAssignableFrom(type);
     }
 
     @Override
@@ -125,26 +161,75 @@ public class JsonbJaxrsProvider<T> implements 
MessageBodyWriter<T>, MessageBodyR
 
     @Override
     public T readFrom(final Class<T> type, final Type genericType, final 
Annotation[] annotations, final MediaType mediaType,
-                      final MultivaluedMap<String, String> httpHeaders, final 
InputStream entityStream) throws IOException, WebApplicationException {
-        return delegate().fromJson(entityStream, genericType);
+            final MultivaluedMap<String, String> httpHeaders, final 
InputStream entityStream) throws IOException, WebApplicationException {
+        return getJsonb(type).fromJson(entityStream, genericType);
     }
 
     @Override
     public void writeTo(final T t, final Class<?> type, final Type 
genericType, final Annotation[] annotations, final MediaType mediaType,
-                        final MultivaluedMap<String, Object> httpHeaders, 
final OutputStream entityStream) throws IOException, WebApplicationException {
-        delegate().toJson(t, entityStream);
-    }
-
-    private Jsonb delegate() {
-        Jsonb jsonb = delegate.get();
-        if (jsonb == null) {
-            final Jsonb newJsonb = createJsonb();
-            if (delegate.compareAndSet(null, newJsonb)) {
-                jsonb = newJsonb;
-            } else {
-                jsonb = delegate.get();
+            final MultivaluedMap<String, Object> httpHeaders, final 
OutputStream entityStream) throws IOException, WebApplicationException {
+        getJsonb(type).toJson(t, entityStream);
+    }
+
+    protected Jsonb createJsonb() {
+        return JsonbBuilder.create(config);
+    }
+
+    protected Jsonb getJsonb(final Class<?> type) {
+        if (delegate == null){
+            synchronized (this) {
+                if (delegate == null) {
+                    final ContextResolver<Jsonb> contextResolver = 
providers.getContextResolver(Jsonb.class, MediaType.APPLICATION_JSON_TYPE);
+                    if (contextResolver != null) {
+                        if (customized) {
+                            
Logger.getLogger(JsonbJaxrsProvider.class.getName())
+                                  .warning("Customizations done on the Jsonb 
instance will be ignored because a ContextResolver<Jsonb> was found");
+                        }
+                        delegate = new DynamicInstance(contextResolver); // 
faster than contextResolver::getContext
+                    } else {
+                        delegate = new ProvidedInstance(createJsonb()); // 
don't recreate it
+                    }
+                }
             }
         }
-        return jsonb;
+        return delegate.apply(type);
+    }
+
+    @Override
+    public synchronized void close() throws Exception {
+        if (AutoCloseable.class.isInstance(delegate)) {
+            AutoCloseable.class.cast(delegate).close();
+        }
+    }
+
+    private static final class DynamicInstance implements Function<Class<?>, 
Jsonb> {
+        private final ContextResolver<Jsonb> contextResolver;
+
+        private DynamicInstance(final ContextResolver<Jsonb> resolver) {
+            this.contextResolver = resolver;
+        }
+
+        @Override
+        public Jsonb apply(final Class<?> type) {
+            return contextResolver.getContext(type);
+        }
+    }
+
+    private static final class ProvidedInstance implements Function<Class<?>, 
Jsonb>, AutoCloseable {
+        private final Jsonb instance;
+
+        private ProvidedInstance(final Jsonb instance) {
+            this.instance = instance;
+        }
+
+        @Override
+        public Jsonb apply(final Class<?> aClass) {
+            return instance;
+        }
+
+        @Override
+        public void close() throws Exception {
+            instance.close();
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/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
deleted file mode 100644
index 7308374..0000000
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnsonJsonb.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * 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 org.apache.johnzon.mapper.MapperException;
-import org.apache.johnzon.mapper.reflection.JohnzonParameterizedType;
-
-import javax.json.bind.Jsonb;
-import javax.json.bind.JsonbException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.Writer;
-import java.lang.reflect.Array;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.Collection;
-import java.util.Optional;
-import java.util.OptionalDouble;
-import java.util.OptionalInt;
-import java.util.OptionalLong;
-
-// TODO: Optional handling for lists (and arrays)?
-public class JohnsonJsonb implements Jsonb, AutoCloseable {
-    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 {
-        try {
-            if (isArray(type)) {
-                return delegate.readTypedArray(new StringReader(str), 
type.getComponentType(), type);
-            } else if (Collection.class.isAssignableFrom(type)) {
-                return (T) delegate.readCollection(new StringReader(str), new 
JohnzonParameterizedType(type, Object.class));
-            }
-            final Type mappingType = unwrapPrimitiveOptional(type);
-            final Object object = delegate.readObject(str, mappingType);
-            if (mappingType != type) {
-                return wrapPrimitiveOptional(object, type);
-            }
-            return (T) object;
-        } catch (final MapperException me) {
-            throw new JsonbException(me.getMessage(), me);
-        }
-    }
-
-    private <T> T wrapPrimitiveOptional(final Object object, final Type type) {
-        if (OptionalDouble.class == type) {
-            if (object == null) {
-                return (T) OptionalDouble.empty();
-            }
-            return (T) 
OptionalDouble.of(Number.class.cast(object).doubleValue());
-        } else if (OptionalInt.class == type) {
-            if (object == null) {
-                return (T) OptionalInt.empty();
-            }
-            return (T) OptionalInt.of(Number.class.cast(object).intValue());
-        } else if (OptionalLong.class == type) {
-            if (object == null) {
-                return (T) OptionalLong.empty();
-            }
-            return (T) OptionalLong.of(Number.class.cast(object).longValue());
-        }
-        // Optional
-        return (T) Optional.ofNullable(object);
-    }
-
-    private Type unwrapPrimitiveOptional(final Type type) {
-        if (OptionalDouble.class == type) {
-            return double.class;
-        } else if (OptionalInt.class == type) {
-            return int.class;
-        } else if (OptionalLong.class == type) {
-            return long.class;
-        } else if (ParameterizedType.class.isInstance(type)) {
-            final ParameterizedType pt = ParameterizedType.class.cast(type);
-            if (Optional.class == pt.getRawType()) {
-                return pt.getActualTypeArguments()[0];
-            }
-        }
-        return type;
-    }
-
-    @Override
-    public <T> T fromJson(final String str, final Type runtimeType) throws 
JsonbException {
-        try {
-            if (isArray(runtimeType)) {
-                final Class cast = Class.class.cast(runtimeType);
-                return (T) delegate.readTypedArray(new StringReader(str), 
cast.getComponentType(), cast);
-            } else if (isCollection(runtimeType)) {
-                return (T) delegate.readCollection(new StringReader(str), 
ParameterizedType.class.cast(runtimeType));
-            }
-            final Type mappingType = unwrapPrimitiveOptional(runtimeType);
-            final Object object = delegate.readObject(str, mappingType);
-            if (mappingType != runtimeType) {
-                return wrapPrimitiveOptional(object, runtimeType);
-            }
-            return (T) object;
-        } catch (final MapperException me) {
-            throw new JsonbException(me.getMessage(), me);
-        }
-    }
-
-    @Override
-    public <T> T fromJson(final Reader reader, final Class<T> type) throws 
JsonbException {
-        try {
-            if (isArray(type)) {
-                return delegate.readTypedArray(reader, 
type.getComponentType(), type);
-            } else if (Collection.class.isAssignableFrom(type)) {
-                return (T) delegate.readCollection(reader, new 
JohnzonParameterizedType(type, Object.class));
-            }
-            final Type mappingType = unwrapPrimitiveOptional(type);
-            final Object object = delegate.readObject(reader, mappingType);
-            if (mappingType != type) {
-                return wrapPrimitiveOptional(object, type);
-            }
-            return (T) object;
-        } catch (final MapperException me) {
-            throw new JsonbException(me.getMessage(), me);
-        }
-    }
-
-    @Override
-    public <T> T fromJson(final Reader reader, final Type runtimeType) throws 
JsonbException {
-        try {
-            if (isArray(runtimeType)) {
-                final Class<T> type = Class.class.cast(runtimeType);
-                return delegate.readTypedArray(reader, 
type.getComponentType(), type);
-            } else if (isCollection(runtimeType)) {
-                return (T) delegate.readCollection(reader, 
ParameterizedType.class.cast(runtimeType));
-            }
-            final Type mappingType = unwrapPrimitiveOptional(runtimeType);
-            final Object object = delegate.readObject(reader, mappingType);
-            if (mappingType != runtimeType) {
-                return wrapPrimitiveOptional(object, runtimeType);
-            }
-            return (T) object;
-        } catch (final MapperException me) {
-            throw new JsonbException(me.getMessage(), me);
-        }
-    }
-
-    @Override
-    public <T> T fromJson(final InputStream stream, final Class<T> type) 
throws JsonbException {
-        try {
-            if (isArray(type)) {
-                return delegate.readTypedArray(stream, 
type.getComponentType(), type);
-            } else if (Collection.class.isAssignableFrom(type)) {
-                return (T) delegate.readCollection(stream, new 
JohnzonParameterizedType(type, Object.class));
-            }
-            final Type mappingType = unwrapPrimitiveOptional(type);
-            final Object object = delegate.readObject(stream, mappingType);
-            if (mappingType != type) {
-                return wrapPrimitiveOptional(object, type);
-            }
-            return (T) object;
-        } catch (final MapperException me) {
-            throw new JsonbException(me.getMessage(), me);
-        }
-    }
-
-    @Override
-    public <T> T fromJson(final InputStream stream, final Type runtimeType) 
throws JsonbException {
-        try {
-            if (isArray(runtimeType)) {
-                final Class<T> type = Class.class.cast(runtimeType);
-                return delegate.readTypedArray(stream, 
type.getComponentType(), type);
-            } else if (isCollection(runtimeType)) {
-                return (T) delegate.readCollection(stream, 
ParameterizedType.class.cast(runtimeType));
-            }
-
-            final Type mappingType = unwrapPrimitiveOptional(runtimeType);
-            final Object object = delegate.readObject(stream, mappingType);
-            if (mappingType != runtimeType) {
-                return wrapPrimitiveOptional(object, runtimeType);
-            }
-            return (T) object;
-        } catch (final MapperException me) {
-            throw new JsonbException(me.getMessage(), me);
-        }
-    }
-
-    @Override
-    public String toJson(final Object inObject) throws JsonbException {
-        try {
-            final Object object = unwrapOptional(inObject);
-            if (object == null) {
-                return "null";
-            }
-            if (isArray(object.getClass())) {
-                return delegate.writeArrayAsString(toArray(object));
-            } else if (Collection.class.isInstance(object)) {
-                return 
delegate.writeArrayAsString(Collection.class.cast(object));
-            }
-            return delegate.writeObjectAsString(object);
-
-        } catch (final MapperException me) {
-            throw new JsonbException(me.getMessage(), me);
-        }
-    }
-
-    private Object[] toArray(final Object object) {
-        final Class<?> componentType = object.getClass().getComponentType();
-        Object[] array;
-        if (int.class == componentType) {
-            final int length = Array.getLength(object);
-            array = new Integer[length];
-            for (int i = 0; i < length; i++) {
-                array[i] = Array.getInt(object, i);
-            }
-        } else if (double.class == componentType) {
-            final int length = Array.getLength(object);
-            array = new Integer[length];
-            for (int i = 0; i < length; i++) {
-                array[i] = Array.getDouble(object, i);
-            }
-        } else if (byte.class == componentType) {
-            final int length = Array.getLength(object);
-            array = new Integer[length];
-            for (int i = 0; i < length; i++) {
-                array[i] = Array.getByte(object, i);
-            }
-        } else if (char.class == componentType) {
-            final int length = Array.getLength(object);
-            array = new Integer[length];
-            for (int i = 0; i < length; i++) {
-                array[i] = Array.getChar(object, i);
-            }
-        } else if (float.class == componentType) {
-            final int length = Array.getLength(object);
-            array = new Integer[length];
-            for (int i = 0; i < length; i++) {
-                array[i] = Array.getFloat(object, i);
-            }
-        } else if (long.class == componentType) {
-            final int length = Array.getLength(object);
-            array = new Integer[length];
-            for (int i = 0; i < length; i++) {
-                array[i] = Array.getLong(object, i);
-            }
-        } else if (short.class == componentType) {
-            final int length = Array.getLength(object);
-            array = new Integer[length];
-            for (int i = 0; i < length; i++) {
-                array[i] = Array.getShort(object, i);
-            }
-        } else {
-            array = (Object[]) object;
-        }
-        return array;
-    }
-
-    @Override
-    public String toJson(final Object inObject, final Type runtimeType) throws 
JsonbException {
-        final Object object = unwrapOptional(inObject);
-        if (object != null && 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 inObject, final Writer writer) throws 
JsonbException {
-        final Object object = unwrapOptional(inObject);
-        if (object != null && isArray(object.getClass())) {
-            delegate.writeArray((Object[]) object, writer);
-        } else if (Collection.class.isInstance(object)) {
-            delegate.writeArray(Collection.class.cast(object), writer);
-        } else {
-            delegate.writeObject(object, writer);
-        }
-    }
-
-    @Override
-    public void toJson(final Object inObject, final Type runtimeType, final 
Writer writer) throws JsonbException {
-        final Object object = unwrapOptional(inObject);
-        if (object != null && isArray(runtimeType)) {
-            delegate.writeArray((Object[]) object, writer);
-        } else if (isCollection(runtimeType)) {
-            delegate.writeArray(Collection.class.cast(object), writer);
-        } else {
-            delegate.writeObject(object, writer);
-        }
-    }
-
-    @Override
-    public void toJson(final Object inObject, final OutputStream stream) 
throws JsonbException {
-        final Object object = unwrapOptional(inObject);
-        if (object != null && 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 inObject, final Type runtimeType, final 
OutputStream stream) throws JsonbException {
-        final Object object = unwrapOptional(inObject);
-        if (object != null && isArray(runtimeType)) {
-            delegate.writeArray((Object[]) object, stream);
-        } else if (isCollection(runtimeType)) {
-            delegate.writeArray(Collection.class.cast(object), stream);
-        } else {
-            delegate.writeObject(object, stream);
-        }
-    }
-
-    private Object unwrapOptional(final Object inObject) {
-        if (Optional.class.isInstance(inObject)) {
-            return Optional.class.cast(inObject).orElse(null);
-        }
-        if (OptionalInt.class.isInstance(inObject)) {
-            final OptionalInt optionalInt = OptionalInt.class.cast(inObject);
-            return optionalInt.isPresent() ? optionalInt.getAsInt() : null;
-        }
-        if (OptionalLong.class.isInstance(inObject)) {
-            final OptionalLong optionalLong = 
OptionalLong.class.cast(inObject);
-            return optionalLong.isPresent() ? optionalLong.getAsLong() : null;
-        }
-        if (OptionalDouble.class.isInstance(inObject)) {
-            final OptionalDouble optionalDouble = 
OptionalDouble.class.cast(inObject);
-            return optionalDouble.isPresent() ? optionalDouble.getAsDouble() : 
null;
-        }
-        return inObject;
-    }
-
-    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));
-    }
-
-    @Override
-    public void close() {
-        delegate.close();
-    }
-}

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
----------------------------------------------------------------------
diff --git 
a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java 
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
index 137cf4c..40ec155 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JohnzonBuilder.java
@@ -20,6 +20,7 @@ package org.apache.johnzon.jsonb;
 
 import org.apache.johnzon.core.AbstractJsonFactory;
 import org.apache.johnzon.core.JsonGeneratorFactoryImpl;
+import org.apache.johnzon.core.JsonParserFactoryImpl;
 import org.apache.johnzon.jsonb.cdi.CDIs;
 import org.apache.johnzon.jsonb.converter.JohnzonJsonbAdapter;
 import org.apache.johnzon.jsonb.factory.SimpleJohnzonAdapterFactory;
@@ -31,6 +32,9 @@ import org.apache.johnzon.mapper.Converter;
 import org.apache.johnzon.mapper.Mapper;
 import org.apache.johnzon.mapper.MapperBuilder;
 import org.apache.johnzon.mapper.ObjectConverter;
+import org.apache.johnzon.mapper.SerializeValueFilter;
+import org.apache.johnzon.mapper.access.AccessMode;
+import org.apache.johnzon.mapper.access.FieldAndMethodAccessMode;
 import org.apache.johnzon.mapper.internal.AdapterKey;
 import org.apache.johnzon.mapper.internal.ConverterAdapter;
 
@@ -48,7 +52,9 @@ import javax.json.bind.serializer.JsonbSerializer;
 import javax.json.spi.JsonProvider;
 import javax.json.stream.JsonGenerator;
 import javax.json.stream.JsonParserFactory;
+import java.io.Closeable;
 import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.ParameterizedType;
@@ -84,8 +90,19 @@ import java.util.function.Supplier;
 import java.util.stream.Stream;
 
 import static java.time.format.DateTimeFormatter.ofPattern;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoField.YEAR;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQueries;
 import static java.util.Collections.emptyMap;
+import java.util.Objects;
 import static java.util.Optional.ofNullable;
+import java.util.concurrent.TimeUnit;
 import static javax.json.bind.config.PropertyNamingStrategy.IDENTITY;
 import static javax.json.bind.config.PropertyOrderStrategy.LEXICOGRAPHICAL;
 
@@ -114,27 +131,9 @@ public class JohnzonBuilder implements JsonbBuilder {
     public Jsonb build() {
         if (jsonp != null) {
             
builder.setGeneratorFactory(jsonp.createGeneratorFactory(generatorConfig()));
-            builder.setReaderFactory(jsonp.createReaderFactory(emptyMap()));
+            
builder.setReaderFactory(jsonp.createReaderFactory(readerConfig()));
         }
-        final Supplier<JsonParserFactory> parserFactoryProvider = new 
Supplier<JsonParserFactory>() { // thread safety is not mandatory
-            private final AtomicReference<JsonParserFactory> ref = new 
AtomicReference<>();
-
-            @Override
-            public JsonParserFactory get() {
-                JsonParserFactory factory = ref.get();
-                if (factory == null) {
-                    factory = doCreate();
-                    if (!ref.compareAndSet(null, factory)) {
-                        factory = ref.get();
-                    }
-                }
-                return factory;
-            }
-
-            private JsonParserFactory doCreate() {
-                return (jsonp == null ? JsonProvider.provider() : 
jsonp).createParserFactory(emptyMap());
-            }
-        };
+        final Supplier<JsonParserFactory> parserFactoryProvider = 
createJsonParserFactory();
 
         if (config == null) {
             config = new JsonbConfig();
@@ -207,6 +206,12 @@ public class JohnzonBuilder implements JsonbBuilder {
         config.getProperty("johnzon.primitiveConverters")
                 .map(v -> !Boolean.class.isInstance(v) ? 
Boolean.parseBoolean(v.toString()) : Boolean.class.cast(v))
                 .ifPresent(builder::setPrimitiveConverters);
+        config.getProperty("johnzon.useBigDecimalForFloats")
+                .map(v -> !Boolean.class.isInstance(v) ? 
Boolean.parseBoolean(v.toString()) : Boolean.class.cast(v))
+                .ifPresent(builder::setUseBigDecimalForFloats);
+        config.getProperty("johnzon.deduplicateObjects")
+                .map(v -> !Boolean.class.isInstance(v) ? 
Boolean.parseBoolean(v.toString()) : Boolean.class.cast(v))
+                .ifPresent(builder::setDeduplicateObjects);
 
         final Map<AdapterKey, Adapter<?, ?>> defaultConverters = 
createJava8Converters(builder);
 
@@ -230,11 +235,16 @@ public class JohnzonBuilder implements JsonbBuilder {
             }
             throw new IllegalArgumentException("Unsupported factory: " + val);
         }).orElseGet(this::findFactory);
-        final JsonbAccessMode accessMode = new JsonbAccessMode(
-                propertyNamingStrategy, orderValue, visibilityStrategy,
-                
!namingStrategyValue.orElse("").equals(PropertyNamingStrategy.CASE_INSENSITIVE),
-                defaultConverters,
-                factory, parserFactoryProvider);
+        final AccessMode accessMode = config.getProperty("johnzon.accessMode")
+                .map(this::toAccessMode)
+                .orElseGet(() -> new JsonbAccessMode(
+                        propertyNamingStrategy, orderValue, visibilityStrategy,
+                        
!namingStrategyValue.orElse("").equals(PropertyNamingStrategy.CASE_INSENSITIVE),
+                        defaultConverters,
+                        factory, parserFactoryProvider,
+                        config.getProperty("johnzon.accessModeDelegate")
+                                .map(this::toAccessMode)
+                                .orElseGet(() -> new 
FieldAndMethodAccessMode(true, true, false))));
         builder.setAccessMode(accessMode);
 
 
@@ -253,6 +263,9 @@ public class JohnzonBuilder implements JsonbBuilder {
         
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 should be fine by default
         });
+        config.getProperty("johnzon.fail-on-unknown-properties")
+                .map(v -> Boolean.class.isInstance(v) ? Boolean.class.cast(v) 
: Boolean.parseBoolean(String.valueOf(v)))
+                .ifPresent(builder::setFailOnUnknownProperties);
 
         
config.getProperty(JsonbConfig.BINARY_DATA_STRATEGY).map(String.class::cast).ifPresent(bin
 -> {
             switch (bin) {
@@ -284,6 +297,23 @@ public class JohnzonBuilder implements JsonbBuilder {
 
         builder.setReadAttributeBeforeWrite(
                 
config.getProperty("johnzon.readAttributeBeforeWrite").map(Boolean.class::cast).orElse(false));
+        builder.setAutoAdjustStringBuffers(
+                
config.getProperty("johnzon.autoAdjustBuffer").map(Boolean.class::cast).orElse(true));
+        config.getProperty("johnzon.serialize-value-filter")
+                .map(s -> {
+                    if (String.class.isInstance(s)) {
+                        try {
+                            return SerializeValueFilter.class.cast(
+                                    
Thread.currentThread().getContextClassLoader().loadClass(s.toString()).getConstructor().newInstance());
+                        } catch (final InstantiationException | 
IllegalAccessException | NoSuchMethodException | ClassNotFoundException e) {
+                            throw new IllegalArgumentException(e);
+                        } catch (InvocationTargetException e) {
+                            throw new IllegalArgumentException(e.getCause());
+                        }
+                    }
+                    return s;
+                })
+                .ifPresent(s -> 
builder.setSerializeValueFilter(SerializeValueFilter.class.cast(s)));
 
         
config.getProperty(JsonbConfig.SERIALIZERS).map(JsonbSerializer[].class::cast).ifPresent(serializers
 -> {
             Stream.of(serializers).forEach(s -> {
@@ -298,7 +328,7 @@ public class JohnzonBuilder implements JsonbBuilder {
                 }
                 builder.addObjectConverter(
                         Class.class.cast(args[0]), (ObjectConverter.Writer)
-                        (instance, jsonbGenerator) -> s.serialize(instance, 
jsonbGenerator.getJsonGenerator(), new 
JohnzonSerializationContext(jsonbGenerator)));
+                                (instance, jsonbGenerator) -> 
s.serialize(instance, jsonbGenerator.getJsonGenerator(), new 
JohnzonSerializationContext(jsonbGenerator)));
             });
         });
         
config.getProperty(JsonbConfig.DESERIALIZERS).map(JsonbDeserializer[].class::cast).ifPresent(deserializers
 -> {
@@ -314,15 +344,18 @@ public class JohnzonBuilder implements JsonbBuilder {
                 // TODO: support PT in ObjectConverter (list)
                 builder.addObjectConverter(
                         Class.class.cast(args[0]), (ObjectConverter.Reader)
-                        (jsonObject, targetType, parser) -> d.deserialize(
-                                
parserFactoryProvider.get().createParser(jsonObject), new 
JohnzonDeserializationContext(parser), targetType));
+                                (jsonObject, targetType, parser) -> 
d.deserialize(
+                                        
parserFactoryProvider.get().createParser(jsonObject), new 
JohnzonDeserializationContext(parser), targetType));
             });
         });
 
         final boolean useCdi = cdiIntegration != null && 
cdiIntegration.isCanWrite() && 
config.getProperty("johnzon.cdi.activated").map(Boolean.class::cast).orElse(Boolean.TRUE);
-        final Mapper mapper = builder.addCloseable(accessMode).build();
+        if (Closeable.class.isInstance(accessMode)) {
+            builder.addCloseable(Closeable.class.cast(accessMode));
+        }
+        final Mapper mapper = builder.build();
 
-        return useCdi ? new JohnsonJsonb(mapper) {
+        return useCdi ? new JohnzonJsonb(mapper) {
             {
                 cdiIntegration.track(this);
             }
@@ -337,14 +370,50 @@ public class JohnzonBuilder implements JsonbBuilder {
                     }
                 }
             }
-        } : new JohnsonJsonb(mapper);
+        } : new JohnzonJsonb(mapper);
+    }
+
+    private AccessMode toAccessMode(final Object s) {
+        if (String.class.isInstance(s)) {
+            try {
+                return AccessMode.class.cast(
+                        
Thread.currentThread().getContextClassLoader().loadClass(s.toString()).getConstructor().newInstance());
+            } catch (final InstantiationException | IllegalAccessException | 
NoSuchMethodException | ClassNotFoundException e) {
+                throw new IllegalArgumentException(e);
+            } catch (InvocationTargetException e) {
+                throw new IllegalArgumentException(e.getCause());
+            }
+        }
+        return AccessMode.class.cast(s);
+    }
+
+    private Supplier<JsonParserFactory> createJsonParserFactory() {
+        return new Supplier<JsonParserFactory>() { // thread safety is not 
mandatory
+            private final AtomicReference<JsonParserFactory> ref = new 
AtomicReference<>();
+
+            @Override
+            public JsonParserFactory get() {
+                JsonParserFactory factory = ref.get();
+                if (factory == null) {
+                    factory = doCreate();
+                    if (!ref.compareAndSet(null, factory)) {
+                        factory = ref.get();
+                    }
+                }
+                return factory;
+            }
+
+            private JsonParserFactory doCreate() {
+                return (jsonp == null ? JsonProvider.provider() : 
jsonp).createParserFactory(emptyMap());
+            }
+        };
     }
 
     private ParameterizedType findPT(final Object s, final Class<?> type) {
         return ParameterizedType.class.cast(
-                            Stream.of(s.getClass().getGenericInterfaces())
-                                    .filter(i -> 
ParameterizedType.class.isInstance(i) && 
ParameterizedType.class.cast(i).getRawType() == type)
-                                    .findFirst().orElse(null));
+                Stream.of(s.getClass().getGenericInterfaces())
+                        .filter(i -> ParameterizedType.class.isInstance(i) && 
ParameterizedType.class.cast(i).getRawType() == type)
+                        .findFirst().orElse(null));
     }
 
     private Object getBeanManager() {
@@ -572,98 +641,151 @@ public class JohnzonBuilder implements JsonbBuilder {
             final Optional<Locale> locale = 
config.getProperty(JsonbConfig.LOCALE).map(Locale.class::cast);
             final DateTimeFormatter formatter = locale.isPresent() ? 
ofPattern(dateFormat, locale.get()) : ofPattern(dateFormat);
 
-            // Note: we try and fallback in the parsing cause we don't know if 
the date format provided is
-            // for date, datetime, time
-
             converters.put(new AdapterKey(Date.class, String.class), new 
ConverterAdapter<>(new Converter<Date>() {
-                private volatile boolean useFormatter = true;
 
                 @Override
                 public String toString(final Date instance) {
-                    return LocalDateTime.ofInstant(instance.toInstant(), 
zoneIDUTC).toString();
+                    return 
formatter.format(ZonedDateTime.ofInstant(instance.toInstant(), zoneIDUTC));
                 }
 
                 @Override
                 public Date fromString(final String text) {
-                    if (useFormatter) {
-                        try {
-                            return Date.from(LocalDateTime.parse(text, 
formatter).toInstant(ZoneOffset.UTC));
-                        } catch (final DateTimeParseException dpe) {
-                            useFormatter = false;
-                        }
+                    try {
+                        return Date.from(parseZonedDateTime(text, formatter, 
zoneIDUTC).toInstant());
+                    } catch (final DateTimeParseException dpe) {
+                        return 
Date.from(LocalDateTime.parse(text).toInstant(ZoneOffset.UTC));
                     }
-                    return 
Date.from(LocalDateTime.parse(text).toInstant(ZoneOffset.UTC));
                 }
             }));
             converters.put(new AdapterKey(LocalDateTime.class, String.class), 
new ConverterAdapter<>(new Converter<LocalDateTime>() {
-                private volatile boolean useFormatter = true;
 
                 @Override
                 public String toString(final LocalDateTime instance) {
-                    return instance.toString();
+                    return 
formatter.format(ZonedDateTime.ofInstant(instance.toInstant(ZoneOffset.UTC), 
zoneIDUTC));
                 }
 
                 @Override
                 public LocalDateTime fromString(final String text) {
-                    if (useFormatter) {
-                        try {
-                            return LocalDateTime.parse(text, formatter);
-                        } catch (final DateTimeParseException dpe) {
-                            useFormatter = false;
-                        }
+                    try {
+                        return parseZonedDateTime(text, formatter, 
zoneIDUTC).toLocalDateTime();
+                    } catch (final DateTimeParseException dpe) {
+                        return LocalDateTime.parse(text);
                     }
-                    return LocalDateTime.parse(text);
                 }
             }));
             converters.put(new AdapterKey(LocalDate.class, String.class), new 
ConverterAdapter<>(new Converter<LocalDate>() {
-                private volatile boolean useFormatter = true;
 
                 @Override
                 public String toString(final LocalDate instance) {
-                    return instance.toString();
+                    return 
formatter.format(ZonedDateTime.ofInstant(Instant.ofEpochMilli(TimeUnit.DAYS.toMillis(instance.toEpochDay())),
 zoneIDUTC));
                 }
 
                 @Override
                 public LocalDate fromString(final String text) {
-                    if (useFormatter) {
-                        try {
-                            return LocalDate.parse(text, formatter);
-                        } catch (final DateTimeParseException dpe) {
-                            useFormatter = false;
-                        }
+                    try {
+                        return parseZonedDateTime(text, formatter, 
zoneIDUTC).toLocalDate();
+                    } catch (final DateTimeParseException dpe) {
+                        return LocalDate.parse(text);
+                    }
+                }
+            }));
+            converters.put(new AdapterKey(OffsetDateTime.class, String.class), 
new ConverterAdapter<>(new Converter<OffsetDateTime>() {
+
+                @Override
+                public String toString(final OffsetDateTime instance) {
+                    return 
formatter.format(ZonedDateTime.ofInstant(instance.toInstant(), zoneIDUTC));
+                }
+
+                @Override
+                public OffsetDateTime fromString(final String text) {
+                    try {
+                        return parseZonedDateTime(text, formatter, 
zoneIDUTC).toOffsetDateTime();
+                    } catch (final DateTimeParseException dpe) {
+                        return OffsetDateTime.parse(text);
                     }
-                    return LocalDate.parse(text);
                 }
             }));
             converters.put(new AdapterKey(ZonedDateTime.class, String.class), 
new ConverterAdapter<>(new Converter<ZonedDateTime>() {
-                private volatile boolean useFormatter = true;
 
                 @Override
                 public String toString(final ZonedDateTime instance) {
-                    return instance.toString();
+                    return 
formatter.format(ZonedDateTime.ofInstant(instance.toInstant(), zoneIDUTC));
                 }
 
                 @Override
                 public ZonedDateTime fromString(final String text) {
-                    if (useFormatter) {
-                        try {
-                            return ZonedDateTime.parse(text, formatter);
-                        } catch (final DateTimeParseException dpe) {
-                            useFormatter = false;
-                        }
+                    try {
+                        return parseZonedDateTime(text, formatter, zoneIDUTC);
+                    } catch (final DateTimeParseException dpe) {
+                        return ZonedDateTime.parse(text);
                     }
-                    return ZonedDateTime.parse(text);
+                }
+            }));
+            converters.put(new AdapterKey(Calendar.class, String.class), new 
ConverterAdapter<>(new Converter<Calendar>() {
+
+                @Override
+                public String toString(final Calendar instance) {
+                    return 
formatter.format(ZonedDateTime.ofInstant(instance.toInstant(), zoneIDUTC));
+                }
+
+                @Override
+                public Calendar fromString(final String text) {
+                    Calendar instance = Calendar.getInstance();
+                    instance.setTime(Date.from(parseZonedDateTime(text, 
formatter, zoneIDUTC).toInstant()));
+                    return instance;
+                }
+            }));
+            converters.put(new AdapterKey(GregorianCalendar.class, 
String.class), new ConverterAdapter<>(new Converter<GregorianCalendar>() {
+
+                @Override
+                public String toString(final GregorianCalendar instance) {
+                    return 
formatter.format(ZonedDateTime.ofInstant(instance.toInstant(), zoneIDUTC));
+                }
+
+                @Override
+                public GregorianCalendar fromString(final String text) {
+                    Calendar instance = GregorianCalendar.getInstance();
+                    instance.setTime(Date.from(parseZonedDateTime(text, 
formatter, zoneIDUTC).toInstant()));
+                    return GregorianCalendar.class.cast(instance);
+                }
+            }));
+            converters.put(new AdapterKey(Instant.class, String.class), new 
ConverterAdapter<>(new Converter<Instant>() {
+
+                @Override
+                public String toString(final Instant instance) {
+                    return formatter.format(ZonedDateTime.ofInstant(instance, 
zoneIDUTC));
+                }
+
+                @Override
+                public Instant fromString(final String text) {
+                    return parseZonedDateTime(text, formatter, 
zoneIDUTC).toInstant();
                 }
             }));
         });
     }
+    
+    private static ZonedDateTime parseZonedDateTime(final String text, final 
DateTimeFormatter formatter, final ZoneId defaultZone){
+        TemporalAccessor parse = formatter.parse(text);
+        ZoneId zone = parse.query(TemporalQueries.zone());
+        if (Objects.isNull(zone)) {
+            zone = defaultZone;
+        }
+        int year = parse.isSupported(YEAR) ? parse.get(YEAR) : 0;
+        int month = parse.isSupported(MONTH_OF_YEAR) ? 
parse.get(MONTH_OF_YEAR) : 0;
+        int day = parse.isSupported(DAY_OF_MONTH) ? parse.get(DAY_OF_MONTH) : 
0;
+        int hour = parse.isSupported(HOUR_OF_DAY) ? parse.get(HOUR_OF_DAY) : 0;
+        int minute = parse.isSupported(MINUTE_OF_HOUR) ? 
parse.get(MINUTE_OF_HOUR) : 0;
+        int second = parse.isSupported(SECOND_OF_MINUTE) ? 
parse.get(SECOND_OF_MINUTE) : 0;
+        int millisecond = parse.isSupported(MILLI_OF_SECOND) ? 
parse.get(MILLI_OF_SECOND) : 0;
+        return ZonedDateTime.of(year, month, day, hour, minute, second, 
millisecond, zone);
+    }
 
     private static void logIfDeprecatedTimeZone(final String text) {
         /* TODO: get the list, UTC is clearly not deprecated but uses 3 letters
         if (text.length() == 3) { // don't fail but log it
             
Logger.getLogger(JohnzonBuilder.class.getName()).severe("Deprecated timezone: " 
+ text);
         }
-        */
+         */
     }
 
     private Map<String, ?> generatorConfig() {
@@ -676,4 +798,16 @@ public class JohnzonBuilder implements JsonbBuilder {
         config.getProperty(JsonbConfig.FORMATTING).ifPresent(b -> 
map.put(JsonGenerator.PRETTY_PRINTING, b));
         return map;
     }
+
+    private Map<String, ?> readerConfig() {
+        final Map<String, Object> map = new HashMap<>();
+        if (config == null) {
+            return map;
+        }
+        config.getProperty(JsonParserFactoryImpl.BUFFER_LENGTH).ifPresent(b -> 
map.put(JsonParserFactoryImpl.BUFFER_LENGTH, b));
+        
config.getProperty(JsonParserFactoryImpl.MAX_STRING_LENGTH).ifPresent(b -> 
map.put(JsonParserFactoryImpl.MAX_STRING_LENGTH, b));
+        
config.getProperty(JsonParserFactoryImpl.SUPPORTS_COMMENTS).ifPresent(b -> 
map.put(JsonParserFactoryImpl.SUPPORTS_COMMENTS, b));
+        config.getProperty(AbstractJsonFactory.BUFFER_STRATEGY).ifPresent(b -> 
map.put(AbstractJsonFactory.BUFFER_STRATEGY, b));
+        return map;
+    }
 }

Reply via email to