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 2016/05/10 18:21:20 UTC

incubator-johnzon git commit: upgrading jsonb-api + filling some TODO but not complete + splitting ObjectConverter in two (read/write)

Repository: incubator-johnzon
Updated Branches:
  refs/heads/master 04fbc250a -> 745668a81


upgrading jsonb-api + filling some TODO but not complete + splitting ObjectConverter in two (read/write)


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

Branch: refs/heads/master
Commit: 745668a81818ec37aed31dc6db868740191a9806
Parents: 04fbc25
Author: Romain manni-Bucau <rm...@gmail.com>
Authored: Tue May 10 20:21:03 2016 +0200
Committer: Romain manni-Bucau <rm...@gmail.com>
Committed: Tue May 10 20:21:03 2016 +0200

----------------------------------------------------------------------
 .../apache/johnzon/jsonb/JohnzonBuilder.java    |  70 ++++++++++++-
 .../apache/johnzon/jsonb/JsonbAccessMode.java   |  70 +++++++++++--
 .../JohnzonDeserializationContext.java          |  48 +++++++++
 .../serializer/JohnzonSerializationContext.java |  48 +++++++++
 .../apache/johnzon/jsonb/SerializerTest.java    | 105 +++++++++++++++++++
 .../java/org/apache/johnzon/mapper/Mapper.java  |   2 +-
 .../apache/johnzon/mapper/MapperBuilder.java    |  14 ++-
 .../org/apache/johnzon/mapper/MapperConfig.java |  50 ++++++---
 .../apache/johnzon/mapper/MappingGenerator.java |   5 +-
 .../johnzon/mapper/MappingGeneratorImpl.java    |  33 +++---
 .../apache/johnzon/mapper/MappingParser.java    |   2 +
 .../johnzon/mapper/MappingParserImpl.java       |  13 ++-
 .../org/apache/johnzon/mapper/Mappings.java     |  68 +++++++++---
 .../apache/johnzon/mapper/ObjectConverter.java  |  18 +++-
 .../johnzon/mapper/access/AccessMode.java       |   3 +
 .../johnzon/mapper/access/FieldAccessMode.java  |  11 ++
 .../mapper/access/FieldAndMethodAccessMode.java |  13 +++
 .../johnzon/mapper/access/MethodAccessMode.java |  16 +++
 .../apache/johnzon/mapper/MapperConfigTest.java |  82 ++++++++-------
 .../ObjectConverterWithAnnotationTest.java      |   2 +-
 .../apache/johnzon/mapper/ObjectTypeTest.java   |   6 +-
 .../main/java/javax/json/bind/JsonbConfig.java  |  12 +++
 .../bind/annotation/JsonbTypeDeserializer.java  |  35 +++++++
 .../bind/annotation/JsonbTypeSerializer.java    |  35 +++++++
 .../bind/serializer/DeserializationContext.java |  33 ++++++
 .../json/bind/serializer/JsonbDeserializer.java |  30 ++++++
 .../json/bind/serializer/JsonbSerializer.java   |  25 +++++
 .../bind/serializer/SerializationContext.java   |  29 +++++
 28 files changed, 771 insertions(+), 107 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/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 13661c2..390c2bc 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
@@ -23,11 +23,14 @@ import org.apache.johnzon.core.JsonGeneratorFactoryImpl;
 import org.apache.johnzon.jsonb.cdi.CDIs;
 import org.apache.johnzon.jsonb.converter.JohnzonJsonbAdapter;
 import org.apache.johnzon.jsonb.factory.SimpleJohnzonAdapterFactory;
+import org.apache.johnzon.jsonb.serializer.JohnzonDeserializationContext;
+import org.apache.johnzon.jsonb.serializer.JohnzonSerializationContext;
 import org.apache.johnzon.jsonb.spi.JohnzonAdapterFactory;
 import org.apache.johnzon.mapper.Adapter;
 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.internal.AdapterKey;
 import org.apache.johnzon.mapper.internal.ConverterAdapter;
 
@@ -39,8 +42,11 @@ 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.bind.serializer.JsonbDeserializer;
+import javax.json.bind.serializer.JsonbSerializer;
 import javax.json.spi.JsonProvider;
 import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonParserFactory;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -72,6 +78,8 @@ import java.util.SimpleTimeZone;
 import java.util.TimeZone;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
 import java.util.stream.Stream;
 
 import static java.time.format.DateTimeFormatter.ofPattern;
@@ -107,6 +115,25 @@ public class JohnzonBuilder implements JsonbBuilder {
             builder.setGeneratorFactory(jsonp.createGeneratorFactory(generatorConfig()));
             builder.setReaderFactory(jsonp.createReaderFactory(emptyMap()));
         }
+        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());
+            }
+        };
 
         if (config == null) {
             config = new JsonbConfig();
@@ -189,7 +216,7 @@ public class JohnzonBuilder implements JsonbBuilder {
                 propertyNamingStrategy, orderValue, visibilityStrategy,
                 !namingStrategyValue.orElse("").equals(PropertyNamingStrategy.CASE_INSENSITIVE),
                 defaultConverters,
-                factory);
+                factory, parserFactoryProvider);
         builder.setAccessMode(accessMode);
 
 
@@ -240,6 +267,40 @@ public class JohnzonBuilder implements JsonbBuilder {
         builder.setReadAttributeBeforeWrite(
                 config.getProperty("johnzon.readAttributeBeforeWrite").map(Boolean.class::cast).orElse(false));
 
+        config.getProperty(JsonbConfig.SERIALIZERS).map(JsonbSerializer[].class::cast).ifPresent(serializers -> {
+            Stream.of(serializers).forEach(s -> {
+                final ParameterizedType pt = findPT(s, JsonbSerializer.class);
+                if (pt == null) {
+                    throw new IllegalArgumentException(s + " doesn't implement JsonbSerializer");
+                }
+                final Type[] args = pt.getActualTypeArguments();
+                // TODO: support PT in ObjectConverter (list)
+                if (args.length != 1 || !Class.class.isInstance(args[0])) {
+                    throw new IllegalArgumentException("We only support serializer on Class for now");
+                }
+                builder.addObjectConverter(
+                        Class.class.cast(args[0]), (ObjectConverter.Writer)
+                        (instance, jsonbGenerator) -> s.serialize(instance, jsonbGenerator.getJsonGenerator(), new JohnzonSerializationContext(jsonbGenerator)));
+            });
+        });
+        config.getProperty(JsonbConfig.DESERIALIZERS).map(JsonbDeserializer[].class::cast).ifPresent(deserializers -> {
+            Stream.of(deserializers).forEach(d -> {
+                final ParameterizedType pt = findPT(d, JsonbDeserializer.class);
+                if (pt == null) {
+                    throw new IllegalArgumentException(d + " doesn't implement JsonbDeserializer");
+                }
+                final Type[] args = pt.getActualTypeArguments();
+                if (args.length != 1 || !Class.class.isInstance(args[0])) {
+                    throw new IllegalArgumentException("We only support deserializer on Class for now");
+                }
+                // 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));
+            });
+        });
+
         final boolean useCdi = cdiIntegration != null && cdiIntegration.isCanWrite();
         final Mapper mapper = builder.addCloseable(accessMode).build();
 
@@ -261,6 +322,13 @@ public class JohnzonBuilder implements JsonbBuilder {
         } : new JohnsonJsonb(mapper);
     }
 
+    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));
+    }
+
     private Object getBeanManager() {
         if (beanManager == null) {
             try { // don't trigger CDI is not there

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
index 4a0a340..fa2e536 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
@@ -25,8 +25,11 @@ 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.jsonb.serializer.JohnzonDeserializationContext;
+import org.apache.johnzon.jsonb.serializer.JohnzonSerializationContext;
 import org.apache.johnzon.jsonb.spi.JohnzonAdapterFactory;
 import org.apache.johnzon.mapper.Adapter;
+import org.apache.johnzon.mapper.ObjectConverter;
 import org.apache.johnzon.mapper.access.AccessMode;
 import org.apache.johnzon.mapper.access.FieldAccessMode;
 import org.apache.johnzon.mapper.access.FieldAndMethodAccessMode;
@@ -44,9 +47,14 @@ 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.JsonbTypeDeserializer;
+import javax.json.bind.annotation.JsonbTypeSerializer;
 import javax.json.bind.config.PropertyNamingStrategy;
 import javax.json.bind.config.PropertyOrderStrategy;
 import javax.json.bind.config.PropertyVisibilityStrategy;
+import javax.json.bind.serializer.JsonbDeserializer;
+import javax.json.bind.serializer.JsonbSerializer;
+import javax.json.stream.JsonParserFactory;
 import java.io.Closeable;
 import java.io.IOException;
 import java.lang.annotation.Annotation;
@@ -74,6 +82,7 @@ import java.util.OptionalLong;
 import java.util.TreeMap;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
+import java.util.function.Supplier;
 import java.util.stream.Stream;
 
 import static java.util.Arrays.asList;
@@ -89,10 +98,12 @@ public class JsonbAccessMode implements AccessMode, Closeable {
     private final Map<AdapterKey, Adapter<?, ?>> defaultConverters;
     private final JohnzonAdapterFactory factory;
     private final Collection<JohnzonAdapterFactory.Instance<?>> toRelease = new ArrayList<>();
+    private final Supplier<JsonParserFactory> parserFactory;
 
     public JsonbAccessMode(final PropertyNamingStrategy propertyNamingStrategy, final String orderValue,
                            final PropertyVisibilityStrategy visibilityStrategy, final boolean caseSensitive,
-                           final Map<AdapterKey, Adapter<?, ?>> defaultConverters, final JohnzonAdapterFactory factory) {
+                           final Map<AdapterKey, Adapter<?, ?>> defaultConverters, final JohnzonAdapterFactory factory,
+                           final Supplier<JsonParserFactory> parserFactory) {
         this.naming = propertyNamingStrategy;
         this.order = orderValue;
         this.visibility = visibilityStrategy;
@@ -100,6 +111,7 @@ public class JsonbAccessMode implements AccessMode, Closeable {
         this.delegate = new FieldAndMethodAccessMode(true, true);
         this.defaultConverters = defaultConverters;
         this.factory = factory;
+        this.parserFactory = parserFactory;
     }
 
     @Override
@@ -266,13 +278,11 @@ public class JsonbAccessMode implements AccessMode, Closeable {
         final Adapter converter;
         if (adapter != null) {
             final Class<? extends JsonbAdapter> value = adapter.value();
-            final ParameterizedType pt = ParameterizedType.class.cast(
-                    Stream.of(value.getGenericInterfaces())
-                            .filter(i -> ParameterizedType.class.isInstance(i) && ParameterizedType.class.cast(i).getRawType() == JsonbAdapter.class).findFirst().orElse(null));
+            final ParameterizedType pt = findPt(value, JsonbAdapter.class);
             if (pt == null) {
                 throw new IllegalArgumentException(value + " doesn't implement JsonbAdapter");
             }
-            final JohnzonAdapterFactory.Instance<? extends JsonbAdapter> instance = newAdapter(value);
+            final JohnzonAdapterFactory.Instance<? extends JsonbAdapter> instance = newInstance(value);
             toRelease.add(instance);
             final Type[] actualTypeArguments = pt.getActualTypeArguments();
             converter = new JohnzonJsonbAdapter(instance.getValue(), actualTypeArguments[0], actualTypeArguments[1]);
@@ -296,7 +306,13 @@ public class JsonbAccessMode implements AccessMode, Closeable {
         return converter;
     }
 
-    private JohnzonAdapterFactory.Instance<? extends JsonbAdapter> newAdapter(final Class<? extends JsonbAdapter> value) {
+    private ParameterizedType findPt(final Class<?> value, final Class<?> type) {
+        return ParameterizedType.class.cast(
+                        Stream.of(value.getGenericInterfaces())
+                                .filter(i -> ParameterizedType.class.isInstance(i) && ParameterizedType.class.cast(i).getRawType() == type).findFirst().orElse(null));
+    }
+
+    private JohnzonAdapterFactory.Instance newInstance(final Class<?> value) {
         return factory.create(value);
     }
 
@@ -326,6 +342,7 @@ public class JsonbAccessMode implements AccessMode, Closeable {
             }
 
             // we are visible
+            final JsonbTypeSerializer serializer = initialReader.getAnnotation(JsonbTypeSerializer.class);
             final JsonbProperty property = initialReader.getAnnotation(JsonbProperty.class);
             final JsonbNillable nillable = initialReader.getClassOrPackageAnnotation(JsonbNillable.class);
             final boolean isNillable = nillable != null || (property != null && property.nillable());
@@ -343,6 +360,21 @@ public class JsonbAccessMode implements AccessMode, Closeable {
                 throw new IllegalArgumentException(e);
             }
 
+            final ObjectConverter.Writer writer;
+            if (serializer != null) {
+                final Class<? extends JsonbSerializer> value = serializer.value();
+                final ParameterizedType pt = findPt(value, JsonbSerializer.class);
+                if (pt == null) {
+                    throw new IllegalArgumentException(value + " doesn't implement JsonbSerializer");
+                }
+                final JohnzonAdapterFactory.Instance<? extends JsonbSerializer> instance = newInstance(value);
+                toRelease.add(instance);
+                writer = (instance1, jsonbGenerator) ->
+                        instance.getValue().serialize(instance1, jsonbGenerator.getJsonGenerator(), new JohnzonSerializationContext(jsonbGenerator));
+            } else {
+                writer = null;
+            }
+
             // handle optionals since mapper is still only java 7
             final Type type;
             final Function<Object, Object> reader;
@@ -371,6 +403,11 @@ public class JsonbAccessMode implements AccessMode, Closeable {
                 }
 
                 @Override
+                public ObjectConverter.Writer<?> findObjectConverterWriter() {
+                    return writer;
+                }
+
+                @Override
                 public Type getType() {
                     return type;
                 }
@@ -427,6 +464,7 @@ public class JsonbAccessMode implements AccessMode, Closeable {
             }
 
             // we are visible
+            final JsonbTypeDeserializer deserializer = initialWriter.getAnnotation(JsonbTypeDeserializer.class);
             final JsonbProperty property = initialWriter.getAnnotation(JsonbProperty.class);
             final JsonbNillable nillable = initialWriter.getClassOrPackageAnnotation(JsonbNillable.class);
             final boolean isNillable = nillable != null || (property != null && property.nillable());
@@ -444,6 +482,21 @@ public class JsonbAccessMode implements AccessMode, Closeable {
                 throw new IllegalArgumentException(e);
             }
 
+            final ObjectConverter.Reader reader;
+            if (deserializer != null) {
+                final Class<? extends JsonbDeserializer> value = deserializer.value();
+                final ParameterizedType pt = findPt(value, JsonbDeserializer.class);
+                if (pt == null) {
+                    throw new IllegalArgumentException(value + " doesn't implement JsonbDeserializer");
+                }
+                final JohnzonAdapterFactory.Instance<? extends JsonbDeserializer> instance = newInstance(value);
+                toRelease.add(instance);
+                reader = (jsonObject, targetType, parser) ->
+                        instance.getValue().deserialize(parserFactory.get().createParser(jsonObject), new JohnzonDeserializationContext(parser), targetType);
+            } else {
+                reader = null;
+            }
+
             // handle optionals since mapper is still only java 7
             final Type type;
             final BiConsumer<Object, Object> writer;
@@ -472,6 +525,11 @@ public class JsonbAccessMode implements AccessMode, Closeable {
                 }
 
                 @Override
+                public ObjectConverter.Reader<?> findObjectConverterReader() {
+                    return reader;
+                }
+
+                @Override
                 public Type getType() {
                     return type;
                 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonDeserializationContext.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonDeserializationContext.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonDeserializationContext.java
new file mode 100644
index 0000000..2049603
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonDeserializationContext.java
@@ -0,0 +1,48 @@
+/*
+ * 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.serializer;
+
+import org.apache.johnzon.mapper.MappingParser;
+
+import javax.json.bind.serializer.DeserializationContext;
+import javax.json.stream.JsonParser;
+import java.lang.reflect.Type;
+
+public class JohnzonDeserializationContext implements DeserializationContext {
+    private final MappingParser runtime;
+
+    public JohnzonDeserializationContext(final MappingParser runtime) {
+        this.runtime = runtime;
+    }
+
+    @Override
+    public <T> T deserialize(final Class<T> clazz, final JsonParser parser) {
+        return null;
+    }
+
+    @Override
+    public <T> T deserialize(final Type type, final JsonParser parser) {
+        return null;
+    }
+
+    @Override
+    public <T> T convertDefault(final Class<T> clazz, final String value) {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonSerializationContext.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonSerializationContext.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonSerializationContext.java
new file mode 100644
index 0000000..d40ca24
--- /dev/null
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonSerializationContext.java
@@ -0,0 +1,48 @@
+/*
+ * 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.serializer;
+
+import org.apache.johnzon.mapper.MappingGenerator;
+
+import javax.json.bind.serializer.SerializationContext;
+import javax.json.stream.JsonGenerator;
+
+// TODO: fix it
+public class JohnzonSerializationContext implements SerializationContext {
+    private final MappingGenerator runtime;
+
+    public JohnzonSerializationContext(final MappingGenerator runtime) {
+        this.runtime = runtime;
+    }
+
+    @Override
+    public <T> void serialize(final String key, final T object, final JsonGenerator generator) {
+        runtime.writeObject(object, generator);
+    }
+
+    @Override
+    public <T> void serialize(final T object, final JsonGenerator generator) {
+        runtime.writeObject(object, generator);
+    }
+
+    @Override
+    public <T> String convertDefault(final T obj, final JsonGenerator generator) {
+        return runtime.convert(obj);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializerTest.java
----------------------------------------------------------------------
diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializerTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializerTest.java
new file mode 100644
index 0000000..475fbcc
--- /dev/null
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializerTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.Jsonb;
+import javax.json.bind.JsonbBuilder;
+import javax.json.bind.annotation.JsonbTypeDeserializer;
+import javax.json.bind.annotation.JsonbTypeSerializer;
+import javax.json.bind.serializer.DeserializationContext;
+import javax.json.bind.serializer.JsonbDeserializer;
+import javax.json.bind.serializer.JsonbSerializer;
+import javax.json.bind.serializer.SerializationContext;
+import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonParser;
+import java.lang.reflect.Type;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+// TODO: enhance
+public class SerializerTest {
+    @Test
+    public void roundTrip() {
+        final Jsonb jsonb = JsonbBuilder.create();
+
+        final String json = "{\"foo\":{\"full\":true,\"name\":\"SerializerTest\"}}";
+
+        final Foo foo = new Foo();
+        foo.name = "SerializerTest";
+        final Wrapper wrapper = new Wrapper();
+        wrapper.foo = foo;
+
+        assertEquals(json, jsonb.toJson(wrapper));
+
+        final Wrapper deser = jsonb.fromJson(json, Wrapper.class);
+        assertEquals(foo.name, deser.foo.name);
+        assertEquals(foo.name.length(), deser.foo.value);
+        assertTrue(deser.foo.flag);
+    }
+
+    public static class Foo {
+        public String name;
+        public int value;
+        public boolean flag;
+    }
+
+    public static class Wrapper {
+        @JsonbTypeSerializer(FooSer.class)
+        @JsonbTypeDeserializer(FooDeser.class)
+        public Foo foo;
+    }
+
+    public static class FooDeser implements JsonbDeserializer<Foo> {
+        @Override
+        public Foo deserialize(final JsonParser parser, final DeserializationContext ctx, final Type rtType) {
+            final Foo f = new Foo();
+            assertTrue(parser.hasNext());
+            assertEquals(JsonParser.Event.START_OBJECT, parser.next());
+            assertTrue(parser.hasNext());
+            assertEquals(JsonParser.Event.KEY_NAME, parser.next());
+            assertEquals("full", parser.getString());
+            assertTrue(parser.hasNext());
+            assertEquals(JsonParser.Event.VALUE_TRUE, parser.next());
+            assertTrue(parser.hasNext());
+            assertEquals(JsonParser.Event.KEY_NAME, parser.next());
+            assertEquals("name", parser.getString());
+            assertTrue(parser.hasNext());
+            assertEquals(JsonParser.Event.VALUE_STRING, parser.next());
+            f.name = parser.getString();
+            assertTrue(parser.hasNext());
+            assertEquals(JsonParser.Event.END_OBJECT, parser.next());
+
+            // to be sure we passed there
+            f.flag = true;
+            f.value = f.name.length();
+            return f;
+        }
+    }
+
+    public static class FooSer implements JsonbSerializer<Foo> {
+        @Override
+        public void serialize(final Foo obj, final JsonGenerator generator, final SerializationContext ctx) {
+            generator.write("full", true);
+            generator.write("name", obj.name);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
index 986f4c3..c8a163e 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
@@ -136,7 +136,7 @@ public class Mapper implements Closeable {
 
         RuntimeException originalException = null;
         try {
-            mappingGenerator.doWriteObject(object, true);
+            mappingGenerator.doWriteObject(object, generator, true);
         } catch (RuntimeException e) {
             originalException = e;
         } finally {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
index d354950..73c32da 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
@@ -122,7 +122,8 @@ public class MapperBuilder {
     private AccessMode accessMode;
     private Charset encoding = Charset.forName(System.getProperty("johnzon.mapper.encoding", "UTF-8"));
     private ConcurrentMap<AdapterKey, Adapter<?, ?>> adapters = new ConcurrentHashMap<AdapterKey, Adapter<?, ?>>(DEFAULT_CONVERTERS);
-    private Map<Class<?>, ObjectConverter<?>> objectConverters = new HashMap<Class<?>, ObjectConverter<?>>();
+    private Map<Class<?>, ObjectConverter.Reader<?>> objectConverterReaders = new HashMap<Class<?>, ObjectConverter.Reader<?>>();
+    private Map<Class<?>, ObjectConverter.Writer<?>> objectConverterWriters = new HashMap<Class<?>, ObjectConverter.Writer<?>>();
     private Map<Class<?>, String[]> ignoredForFields = new HashMap<Class<?>, String[]>();
 
     public Mapper build() {
@@ -187,7 +188,7 @@ public class MapperBuilder {
         return new Mapper(
                 readerFactory, generatorFactory,
                 new MapperConfig(
-                        adapters, objectConverters,
+                        adapters, objectConverterWriters, objectConverterReaders,
                         version, close,
                         skipNull, skipEmptyArray,
                         treatByteArrayAsBase64, treatByteArrayAsBase64URL, readAttributeBeforeWrite,
@@ -342,8 +343,13 @@ public class MapperBuilder {
         return this;
     }
 
-    public <T> MapperBuilder addObjectConverter(final Class<T> targetType, final ObjectConverter<T> objectConverter) {
-        this.objectConverters.put(targetType, objectConverter);
+    public <T> MapperBuilder addObjectConverter(final Class<T> targetType, final MapperConverter objectConverter) {
+        if (ObjectConverter.Reader.class.isInstance(objectConverter)) {
+            this.objectConverterReaders.put(targetType, ObjectConverter.Reader.class.cast(objectConverter));
+        }
+        if (ObjectConverter.Writer.class.isInstance(objectConverter)) {
+            this.objectConverterWriters.put(targetType, ObjectConverter.Writer.class.cast(objectConverter));
+        }
         return this;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
index afd40b2..590c238 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
@@ -37,7 +37,7 @@ import java.util.concurrent.ConcurrentMap;
  */
 class MapperConfig implements Cloneable {
 
-    private static final ObjectConverter NO_CONVERTER = new ObjectConverter() {
+    private static final ObjectConverter.Codec NO_CONVERTER = new ObjectConverter.Codec() {
         @Override
         public void writeJson(Object instance, MappingGenerator jsonbGenerator) {
             // just a dummy
@@ -59,15 +59,18 @@ class MapperConfig implements Cloneable {
     private final AccessMode accessMode;
     private final Charset encoding;
     private final ConcurrentMap<AdapterKey, Adapter<?, ?>> adapters;
-    private final Map<Class<?>, ObjectConverter<?>> objectConverters;
+    private final Map<Class<?>, ObjectConverter.Writer<?>> objectConverterWriters;
+    private final Map<Class<?>, ObjectConverter.Reader<?>> objectConverterReaders;
     private final Comparator<String> attributeOrder;
 
-    private final Map<Class<?>, ObjectConverter<?>> objectConverterCache;
+    private final Map<Class<?>, ObjectConverter.Writer<?>> objectConverterWriterCache;
+    private final Map<Class<?>, ObjectConverter.Reader<?>> objectConverterReaderCache;
 
     //disable checkstyle for 10+ parameters
     //CHECKSTYLE:OFF
     public MapperConfig(final ConcurrentMap<AdapterKey, Adapter<?, ?>> adapters,
-                        final Map<Class<?>, ObjectConverter<?>> objectConverters,
+                        final Map<Class<?>, ObjectConverter.Writer<?>> objectConverterWriters,
+                        final Map<Class<?>, ObjectConverter.Reader<?>> objectConverterReaders,
                         final int version, final boolean close,
                         final boolean skipNull, final boolean skipEmptyArray,
                         final boolean treatByteArrayAsBase64, final boolean treatByteArrayAsBase64URL,
@@ -75,7 +78,8 @@ class MapperConfig implements Cloneable {
                         final AccessMode accessMode, final Charset encoding,
                         final Comparator<String> attributeOrder) {
     //CHECKSTYLE:ON
-        this.objectConverters = objectConverters;
+        this.objectConverterWriters = objectConverterWriters;
+        this.objectConverterReaders = objectConverterReaders;
         this.version = version;
         this.close = close;
         this.skipNull = skipNull;
@@ -88,7 +92,8 @@ class MapperConfig implements Cloneable {
         this.adapters = adapters;
         this.attributeOrder = attributeOrder;
 
-        this.objectConverterCache = new HashMap<Class<?>, ObjectConverter<?>>(objectConverters.size());
+        this.objectConverterWriterCache = new HashMap<Class<?>, ObjectConverter.Writer<?>>(objectConverterWriters.size());
+        this.objectConverterReaderCache = new HashMap<Class<?>, ObjectConverter.Reader<?>>(objectConverterReaders.size());
     }
 
     public Adapter findAdapter(final Type aClass) {
@@ -123,13 +128,22 @@ class MapperConfig implements Cloneable {
      *
      * @throws IllegalArgumentException if {@code clazz} is {@code null}
      */
-    public ObjectConverter findObjectConverter(Class clazz) {
+    public ObjectConverter.Reader findObjectConverterReader(Class clazz) {
+        return findObjectConverter(clazz, objectConverterReaders, objectConverterReaderCache);
+    }
+    public ObjectConverter.Writer findObjectConverterWriter(Class clazz) {
+        return findObjectConverter(clazz, objectConverterWriters, objectConverterWriterCache);
+    }
+
+    private <T> T findObjectConverter(final Class clazz,
+                                                final Map<Class<?>, T> from,
+                                                final Map<Class<?>, T> cache) {
         if (clazz == null) {
             throw new IllegalArgumentException("clazz must not be null");
         }
 
         // first lets look in our cache
-        ObjectConverter<?> converter = objectConverterCache.get(clazz);
+        T converter = cache.get(clazz);
         if (converter != null && converter != NO_CONVERTER) {
             return converter;
         }
@@ -142,9 +156,9 @@ class MapperConfig implements Cloneable {
         // we get called the first time for this class
         // lets search...
 
-        Map<Class<?>, ObjectConverter<?>> matchingConverters = new HashMap<Class<?>, ObjectConverter<?>>();
+        Map<Class<?>, T> matchingConverters = new HashMap<Class<?>, T>();
 
-        for (Map.Entry<Class<?>, ObjectConverter<?>> entry : objectConverters.entrySet()) {
+        for (Map.Entry<Class<?>, T> entry : from.entrySet()) {
 
             if (clazz == entry.getKey()) {
                 converter = entry.getValue();
@@ -157,12 +171,12 @@ class MapperConfig implements Cloneable {
         }
 
         if (converter != null) {
-            objectConverterCache.put(clazz, converter);
+            cache.put(clazz, converter);
             return converter;
         }
 
         if (matchingConverters.isEmpty()) {
-            objectConverterCache.put(clazz, NO_CONVERTER);
+            cache.put(clazz, (T) NO_CONVERTER);
             return null;
         }
 
@@ -195,9 +209,9 @@ class MapperConfig implements Cloneable {
         }
 
         if (converter == null) {
-            objectConverterCache.put(clazz, NO_CONVERTER);
+            cache.put(clazz, (T) NO_CONVERTER);
         } else {
-            objectConverterCache.put(clazz, converter);
+            cache.put(clazz, converter);
         }
 
         return converter;
@@ -243,8 +257,12 @@ class MapperConfig implements Cloneable {
         return adapters;
     }
 
-    public Map<Class<?>, ObjectConverter<?>> getObjectConverters() {
-        return objectConverters;
+    public Map<Class<?>, ObjectConverter.Writer<?>> getObjectConverterWriters() {
+        return objectConverterWriters;
+    }
+
+    public Map<Class<?>, ObjectConverter.Reader<?>> getObjectConverterReaders() {
+        return objectConverterReaders;
     }
 
     public Comparator<String> getAttributeOrder() {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
index b3719a2..bd02cfe 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
@@ -53,9 +53,12 @@ public interface MappingGenerator {
      *     "firstName":"Karl", "lastName":"SomeName", "address":{"street":"mystreet"}
      * </pre>
      * @param o the object to write
+     * @param generator the jsonp generator to use
      * @return itself, for easier chaining of commands
      */
-    MappingGenerator writeObject(Object o);
+    MappingGenerator writeObject(Object o, JsonGenerator generator);
 
 
+    // @Experimental
+    <T> String convert(T obj);
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
index 48c999d..f984373 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
@@ -18,6 +18,11 @@
  */
 package org.apache.johnzon.mapper;
 
+import org.apache.johnzon.mapper.internal.AdapterKey;
+
+import javax.json.JsonValue;
+import javax.json.stream.JsonGenerator;
+import javax.xml.bind.DatatypeConverter;
 import java.lang.reflect.Array;
 import java.lang.reflect.InvocationTargetException;
 import java.math.BigDecimal;
@@ -25,12 +30,6 @@ import java.math.BigInteger;
 import java.util.Collection;
 import java.util.Map;
 
-import javax.json.JsonValue;
-import javax.json.stream.JsonGenerator;
-import javax.xml.bind.DatatypeConverter;
-
-import org.apache.johnzon.mapper.internal.AdapterKey;
-
 public class MappingGeneratorImpl implements MappingGenerator {
     private final MapperConfig config;
     private final JsonGenerator generator;
@@ -49,18 +48,23 @@ public class MappingGeneratorImpl implements MappingGenerator {
     }
 
     @Override
-    public MappingGenerator writeObject(Object object) {
+    public MappingGenerator writeObject(Object object, JsonGenerator generator) {
         if (object == null) {
             return this;
         } else if (object instanceof JsonValue) {
             generator.write((JsonValue) object);
         } else {
-            doWriteObject(object, false);
+            doWriteObject(object, generator, false);
         }
         return this;
     }
 
-    public void doWriteObject(Object object, boolean writeBody) {
+    @Override
+    public <T> String convert(final T obj) {
+        return (String) config.findAdapter(obj.getClass()).to(obj);
+    }
+
+    public void doWriteObject(Object object, JsonGenerator generator, boolean writeBody) {
         try {
             if (object instanceof Map) {
                 if (writeBody) {
@@ -94,7 +98,7 @@ public class MappingGeneratorImpl implements MappingGenerator {
                 generator.writeStartObject();
             }
 
-            ObjectConverter objectConverter = config.findObjectConverter(objectClass);
+            ObjectConverter.Writer objectConverter = config.findObjectConverterWriter(objectClass);
             if (writeBody && objectConverter != null) {
                 objectConverter.writeJson(object, this);
             } else {
@@ -269,7 +273,8 @@ public class MappingGeneratorImpl implements MappingGenerator {
                             final boolean primitive, final boolean array,
                             final boolean collection, final boolean map,
                             final Adapter itemConverter,
-                            final String key, final Object value, final ObjectConverter objectConverter) throws InvocationTargetException, IllegalAccessException {
+                            final String key, final Object value,
+                            final ObjectConverter.Writer objectConverter) throws InvocationTargetException, IllegalAccessException {
         if (array) {
             final int length = Array.getLength(value);
             if (length == 0 && config.isSkipEmptyArray()) {
@@ -319,9 +324,9 @@ public class MappingGeneratorImpl implements MappingGenerator {
                 return;
             } else {
 
-                ObjectConverter objectConverterToUse = objectConverter;
+                ObjectConverter.Writer objectConverterToUse = objectConverter;
                 if (objectConverterToUse == null) {
-                    objectConverterToUse = config.findObjectConverter(type);
+                    objectConverterToUse = config.findObjectConverterWriter(type);
                 }
 
                 if (objectConverterToUse != null) {
@@ -358,7 +363,7 @@ public class MappingGeneratorImpl implements MappingGenerator {
             } else if (o == null) {
                 generator.writeNull();
             } else {
-                doWriteObject(o, true);
+                doWriteObject(o, generator, true);
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParser.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParser.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParser.java
index cee68d8..6269884 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParser.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParser.java
@@ -31,4 +31,6 @@ public interface MappingParser {
     <T> T readObject(Type targetType);
 
     <T> T readObject(JsonValue jsonValue, Type targetType);
+
+    <T> T convert(Class<T> clazz, String value);
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
index 87ceb49..812b7a6 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
@@ -115,6 +115,11 @@ public class MappingParserImpl implements MappingParser {
         return readObject(jsonValue, targetType, targetType instanceof Class || targetType instanceof ParameterizedType);
     }
 
+    @Override
+    public <T> T convert(final Class<T> clazz, final String value) {
+        return (T) config.findAdapter(clazz).to(value);
+    }
+
     private <T> T readObject(JsonValue jsonValue, Type targetType, boolean applyObjectConverter) {
         if (JsonStructure.class == targetType || JsonObject.class == targetType || JsonValue.class == targetType) {
             return (T) jsonValue;
@@ -186,7 +191,7 @@ public class MappingParserImpl implements MappingParser {
                 throw new MapperException("ObjectConverters are only supported for Classes not Types");
             }
 
-            ObjectConverter objectConverter = config.findObjectConverter((Class) type);
+            ObjectConverter.Reader objectConverter = config.findObjectConverterReader((Class) type);
             if (objectConverter != null) {
                 return objectConverter.fromJson(object, type, new SuppressConversionMappingParser(this, object));
             }
@@ -535,7 +540,7 @@ public class MappingParserImpl implements MappingParser {
     }
 
     private Object toValue(final Object baseInstance, final JsonValue jsonValue, final Adapter converter,
-                           final Adapter itemConverter, final Type type, final ObjectConverter objectConverter) {
+                           final Adapter itemConverter, final Type type, final ObjectConverter.Reader objectConverter) {
 
         if (objectConverter != null) {
 
@@ -627,6 +632,10 @@ public class MappingParserImpl implements MappingParser {
             return delegate.readObject(jsonValue, targetType);
         }
 
+        @Override
+        public <T> T convert(final Class<T> clazz, final String value) {
+            return delegate.convert(clazz, value);
+        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
index 8c1154b..db0ce1c 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
@@ -85,7 +85,7 @@ public class Mappings {
         final int version;
         final Adapter converter;
         final Adapter itemConverter;
-        final ObjectConverter objectConverter;
+        final ObjectConverter.Writer objectConverter;
         final boolean primitive;
         final boolean array;
         final boolean map;
@@ -95,6 +95,7 @@ public class Mappings {
                       final boolean primitive, final boolean array,
                       final boolean collection, final boolean map,
                       final MapperConverter converter,
+                      final ObjectConverter.Writer providedObjectConverter,
                       final int version) {
             this.reader = reader;
             this.version = version;
@@ -104,14 +105,14 @@ public class Mappings {
 
             Adapter theConverter = null;
             Adapter theItemConverter = null;
-            ObjectConverter theObjectConverter = null;
+            ObjectConverter.Writer theObjectConverter = providedObjectConverter;
 
             if (converter != null) {
 
-                if (converter instanceof ObjectConverter) {
-                    theObjectConverter = (ObjectConverter) converter;
-                } else {
-
+                if (converter instanceof ObjectConverter.Writer) {
+                    theObjectConverter = (ObjectConverter.Writer) converter;
+                }
+                if (theObjectConverter == null) {
                     Adapter adapter;
                     if (converter instanceof Converter) {
                         adapter = new ConverterAdapter((Converter) converter);
@@ -155,12 +156,12 @@ public class Mappings {
         public final Type paramType;
         public final Adapter converter;
         public final Adapter itemConverter;
-        public final ObjectConverter objectConverter;
+        public final ObjectConverter.Reader objectConverter;
         public final boolean primitive;
         public final boolean array;
 
         public Setter(final AccessMode.Writer writer, final boolean primitive, final boolean array,
-                      final Type paramType, final MapperConverter converter,
+                      final Type paramType, final MapperConverter converter, final ObjectConverter.Reader providedObjectConverter,
                       final int version) {
             this.writer = writer;
             this.paramType = paramType;
@@ -170,14 +171,14 @@ public class Mappings {
 
             Adapter theConverter = null;
             Adapter theItemConverter = null;
-            ObjectConverter theObjectConverter = null;
+            ObjectConverter.Reader theObjectConverter = providedObjectConverter;
 
             if (converter != null) {
 
-                if (converter instanceof ObjectConverter) {
-                    theObjectConverter = (ObjectConverter) converter;
-                } else {
-
+                if (converter instanceof ObjectConverter.Reader) {
+                    theObjectConverter = (ObjectConverter.Reader) converter;
+                }
+                if (theObjectConverter == null){
                     Adapter adapter;
                     if (converter instanceof Converter) {
                         adapter = new ConverterAdapter((Converter) converter);
@@ -398,7 +399,8 @@ public class Mappings {
             final Class<?> returnType = Class.class.isInstance(param) ? Class.class.cast(param) : null;
             final Setter setter = new Setter(
                 value, isPrimitive(param), returnType != null && returnType.isArray(), param,
-                findConverter(copyDate, value), writeIgnore != null ? writeIgnore.minVersion() : -1);
+                findConverter(copyDate, value), value.findObjectConverterReader(),
+                writeIgnore != null ? writeIgnore.minVersion() : -1);
             setters.put(key, setter);
         }
     }
@@ -417,7 +419,7 @@ public class Mappings {
                     || (returnType != null && Collection.class.isAssignableFrom(returnType)),
                 (pt != null && Map.class.isAssignableFrom(Class.class.cast(pt.getRawType())))
                     || (returnType != null && Map.class.isAssignableFrom(returnType)),
-                findConverter(copyDate, value),
+                findConverter(copyDate, value), value.findObjectConverterWriter(),
                 readIgnore != null ? readIgnore.minVersion() : -1);
             getters.put(key, getter);
         }
@@ -465,11 +467,11 @@ public class Mappings {
 
         final Getter getter = getters.get(key);
         final MapBuilderReader newReader = new MapBuilderReader(objectGetters, path, config.getVersion());
-        getters.put(key, new Getter(getter == null ? newReader : new CompositeReader(getter.reader, newReader), false, false, false, true, null, -1));
+        getters.put(key, new Getter(getter == null ? newReader : new CompositeReader(getter.reader, newReader), false, false, false, true, null, null, -1));
 
         final Setter newSetter = setters.get(key);
         final MapUnwrapperWriter newWriter = new MapUnwrapperWriter(objectSetters, path);
-        setters.put(key, new Setter(newSetter == null ? newWriter : new CompositeWriter(newSetter.writer, newWriter), false, false, VIRTUAL_TYPE, null, -1));
+        setters.put(key, new Setter(newSetter == null ? newWriter : new CompositeWriter(newSetter.writer, newWriter), false, false, VIRTUAL_TYPE, null, null, -1));
     }
 
     private MapperConverter findConverter(final boolean copyDate, final AccessMode.DecoratedType decoratedType) {
@@ -574,6 +576,11 @@ public class Mappings {
         }
 
         @Override
+        public ObjectConverter.Writer<?> findObjectConverterWriter() {
+            return null;
+        }
+
+        @Override
         public Type getType() {
             return VIRTUAL_TYPE;
         }
@@ -648,6 +655,11 @@ public class Mappings {
         }
 
         @Override
+        public ObjectConverter.Reader<?> findObjectConverterReader() {
+            return null;
+        }
+
+        @Override
         public Type getType() {
             return VIRTUAL_TYPE;
         }
@@ -708,6 +720,17 @@ public class Mappings {
         }
 
         @Override
+        public ObjectConverter.Writer<?> findObjectConverterWriter() {
+            for (final AccessMode.Reader w : delegates) {
+                final ObjectConverter.Writer<?> objectConverter = w.findObjectConverterWriter();
+                if (objectConverter != null) {
+                    return objectConverter;
+                }
+            }
+            return null;
+        }
+
+        @Override
         public Type getType() {
             return VIRTUAL_TYPE;
         }
@@ -767,6 +790,17 @@ public class Mappings {
         }
 
         @Override
+        public ObjectConverter.Reader<?> findObjectConverterReader() {
+            for (final AccessMode.Writer w : delegates) {
+                final ObjectConverter.Reader<?> objectConverter = w.findObjectConverterReader();
+                if (objectConverter != null) {
+                    return objectConverter;
+                }
+            }
+            return null;
+        }
+
+        @Override
         public Type getType() {
             return VIRTUAL_TYPE;
         }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
index 5869f4d..03ce47e 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
@@ -28,10 +28,20 @@ import java.lang.reflect.Type;
  * An example would be to convert a custom Project POJO, like Dog.class
  * to it's JSON representation
  *
- * @param <T>
  */
-public interface ObjectConverter<T> extends MapperConverter {
-    void writeJson(T instance, MappingGenerator jsonbGenerator);
+public final class ObjectConverter {
+    private ObjectConverter() {
+        // no-op
+    }
 
-    T fromJson(JsonObject jsonObject, Type targetType, MappingParser parser);
+    public interface Writer<T> extends MapperConverter {
+        void writeJson(T instance, MappingGenerator jsonbGenerator);
+    }
+
+    public interface Reader<T> extends MapperConverter {
+        T fromJson(JsonObject jsonObject, Type targetType, MappingParser parser);
+    }
+
+    public interface Codec<T> extends ObjectConverter.Writer<T>, ObjectConverter.Reader<T> {
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
index 0e667d4..f47e0d0 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
@@ -19,6 +19,7 @@
 package org.apache.johnzon.mapper.access;
 
 import org.apache.johnzon.mapper.Adapter;
+import org.apache.johnzon.mapper.ObjectConverter;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
@@ -36,10 +37,12 @@ public interface AccessMode {
 
     interface Writer extends DecoratedType {
         void write(Object instance, Object value);
+        ObjectConverter.Reader<?> findObjectConverterReader();
     }
 
     interface Reader extends DecoratedType {
         Object read(Object instance);
+        ObjectConverter.Writer<?> findObjectConverterWriter();
     }
 
     interface Factory {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
index 37d92cc..0bb6a4f 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
@@ -21,6 +21,7 @@ package org.apache.johnzon.mapper.access;
 import org.apache.johnzon.mapper.Adapter;
 import org.apache.johnzon.mapper.JohnzonProperty;
 import org.apache.johnzon.mapper.MapperException;
+import org.apache.johnzon.mapper.ObjectConverter;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
@@ -149,6 +150,11 @@ public class FieldAccessMode extends BaseAccessMode {
                 throw new MapperException(e);
             }
         }
+
+        @Override
+        public ObjectConverter.Reader<?> findObjectConverterReader() {
+            return null;
+        }
     }
 
     public static class FieldReader extends FieldDecoratedType  implements Reader {
@@ -166,6 +172,11 @@ public class FieldAccessMode extends BaseAccessMode {
         }
 
         @Override
+        public ObjectConverter.Writer<?> findObjectConverterWriter() {
+            return null;
+        }
+
+        @Override
         public Type getType() {
             return type;
         }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
index 7fc224a..0e4d9e7 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
@@ -19,6 +19,7 @@
 package org.apache.johnzon.mapper.access;
 
 import org.apache.johnzon.mapper.Adapter;
+import org.apache.johnzon.mapper.ObjectConverter;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
@@ -122,6 +123,12 @@ public class FieldAndMethodAccessMode extends BaseAccessMode {
         public Object read(final Object instance) {
             return reader.read(instance);
         }
+
+        @Override
+        public ObjectConverter.Writer<?> findObjectConverterWriter() {
+            final ObjectConverter.Writer<?> objectConverter = Reader.class.cast(type1).findObjectConverterWriter();
+            return objectConverter == null ? reader.findObjectConverterWriter() : objectConverter;
+        }
     }
 
     public static final class CompositeWriter extends CompositeDecoratedType implements Writer {
@@ -136,5 +143,11 @@ public class FieldAndMethodAccessMode extends BaseAccessMode {
         public void write(final Object instance, final Object value) {
             writer.write(instance, value);
         }
+
+        @Override
+        public ObjectConverter.Reader<?> findObjectConverterReader() {
+            final ObjectConverter.Reader<?> objectConverter = Writer.class.cast(type1).findObjectConverterReader();
+            return objectConverter == null ? writer.findObjectConverterReader() : objectConverter;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
index 894d03e..4309c28 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
@@ -21,6 +21,7 @@ package org.apache.johnzon.mapper.access;
 import org.apache.johnzon.mapper.Adapter;
 import org.apache.johnzon.mapper.JohnzonProperty;
 import org.apache.johnzon.mapper.MapperException;
+import org.apache.johnzon.mapper.ObjectConverter;
 
 import java.beans.IntrospectionException;
 import java.beans.Introspector;
@@ -153,6 +154,11 @@ public class MethodAccessMode extends BaseAccessMode {
                 throw new MapperException(e);
             }
         }
+
+        @Override
+        public ObjectConverter.Reader<?> findObjectConverterReader() {
+            return null;
+        }
     }
 
     public static class MethodReader extends MethodDecoratedType implements Reader {
@@ -168,6 +174,11 @@ public class MethodAccessMode extends BaseAccessMode {
                 throw new MapperException(e);
             }
         }
+
+        @Override
+        public ObjectConverter.Writer<?> findObjectConverterWriter() {
+            return null;
+        }
     }
 
     private class MethodGetterAsWriter extends MethodReader implements Writer {
@@ -188,5 +199,10 @@ public class MethodAccessMode extends BaseAccessMode {
                 }
             }
         }
+
+        @Override
+        public ObjectConverter.Reader<?> findObjectConverterReader() {
+            return null;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
index 7f5bac2..52a3eeb 100644
--- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
@@ -36,14 +36,14 @@ public class MapperConfigTest {
     @Test
     public void testFindObjectConverterConverterForSpecificClass() {
 
-        ObjectConverter<ClassWithoutSupertypes> theConverter = new TheConverter<ClassWithoutSupertypes>();
+        ObjectConverter.Codec<ClassWithoutSupertypes> theConverter = new TheConverter<ClassWithoutSupertypes>();
 
-        Map<Class<?>, ObjectConverter<?>> converterMap = new HashMap<Class<?>, ObjectConverter<?>>(1);
+        Map<Class<?>, ObjectConverter.Codec<?>> converterMap = new HashMap<Class<?>, ObjectConverter.Codec<?>>(1);
         converterMap.put(ClassWithoutSupertypes.class, theConverter);
 
         MapperConfig config = createConfig(converterMap);
 
-        ObjectConverter converter = config.findObjectConverter(ClassWithoutSupertypes.class);
+        ObjectConverter.Reader converter = config.findObjectConverterReader(ClassWithoutSupertypes.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(theConverter, converter);
     }
@@ -51,11 +51,11 @@ public class MapperConfigTest {
     @Test
     public void testFindObjectConverterConverterForInterface() {
 
-        ObjectConverter<TheInterface> theConverter = new TheConverter<TheInterface>();
+        ObjectConverter.Codec<TheInterface> theConverter = new TheConverter<TheInterface>();
 
-        MapperConfig config = createConfig(Collections.<Class<?>, ObjectConverter<?>>singletonMap(TheInterface.class, theConverter));
+        MapperConfig config = createConfig(Collections.<Class<?>, ObjectConverter.Codec<?>>singletonMap(TheInterface.class, theConverter));
 
-        ObjectConverter converter = config.findObjectConverter(ClassForTheInterface.class);
+        ObjectConverter.Writer converter = config.findObjectConverterWriter(ClassForTheInterface.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(theConverter, converter);
     }
@@ -63,11 +63,11 @@ public class MapperConfigTest {
     @Test
     public void testFindObjectConverterConverterOnlyForSuperclass() {
 
-        ObjectConverter<ClassForTheInterface> theConverter = new TheConverter<ClassForTheInterface>();
+        ObjectConverter.Codec<ClassForTheInterface> theConverter = new TheConverter<ClassForTheInterface>();
 
-        MapperConfig config = createConfig(Collections.<Class<?>, ObjectConverter<?>>singletonMap(ClassForTheInterface.class, theConverter));
+        MapperConfig config = createConfig(Collections.<Class<?>, ObjectConverter.Codec<?>>singletonMap(ClassForTheInterface.class, theConverter));
 
-        ObjectConverter converter = config.findObjectConverter(ExtendingClassForTheInterface.class);
+        ObjectConverter.Reader converter = config.findObjectConverterReader(ExtendingClassForTheInterface.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(theConverter, converter);
     }
@@ -75,36 +75,40 @@ public class MapperConfigTest {
     @Test
     public void testFindObjectConverterConverterForInterfaceAndClass() {
 
-        ObjectConverter<TheInterface> interfaceConverter = new TheConverter<TheInterface>();
-        ObjectConverter<ClassForTheInterface> theConverter = new TheConverter<ClassForTheInterface>();
+        ObjectConverter.Codec<TheInterface> interfaceConverter = new TheConverter<TheInterface>();
+        ObjectConverter.Codec<ClassForTheInterface> theConverter = new TheConverter<ClassForTheInterface>();
 
-        Map<Class<?>, ObjectConverter<?>> converterMap = new HashMap<Class<?>, ObjectConverter<?>>(2);
+        Map<Class<?>, ObjectConverter.Codec<?>> converterMap = new HashMap<Class<?>, ObjectConverter.Codec<?>>(2);
         converterMap.put(TheInterface.class, interfaceConverter);
         converterMap.put(ClassForTheInterface.class, theConverter);
 
         MapperConfig config = createConfig(converterMap);
 
-        ObjectConverter converter = config.findObjectConverter(ClassForTheInterface.class);
-        Assert.assertNotNull(converter);
-        Assert.assertEquals(theConverter, converter);
+        {
+            ObjectConverter.Reader converter = config.findObjectConverterReader(ClassForTheInterface.class);
+            Assert.assertNotNull(converter);
+            Assert.assertEquals(theConverter, converter);
+        }
 
-        converter = config.findObjectConverter(ExtendingClassForTheInterface.class);
-        Assert.assertNotNull(converter);
-        Assert.assertEquals(theConverter, converter);
+        {
+            ObjectConverter.Writer converter = config.findObjectConverterWriter(ExtendingClassForTheInterface.class);
+            Assert.assertNotNull(converter);
+            Assert.assertEquals(theConverter, converter);
+        }
     }
 
     @Test
     public void testFindObjectConverterConverterForMoreInterfaces() {
 
-        ObjectConverter<TheInterface> firstConverter = new TheConverter<TheInterface>();
-        ObjectConverter<TheSecondInterface> secondConverter = new TheConverter<TheSecondInterface>();
+        ObjectConverter.Codec<TheInterface> firstConverter = new TheConverter<TheInterface>();
+        ObjectConverter.Codec<TheSecondInterface> secondConverter = new TheConverter<TheSecondInterface>();
 
-        Map<Class<?>, ObjectConverter<?>> converterMap = new HashMap<Class<?>, ObjectConverter<?>>(2);
+        Map<Class<?>, ObjectConverter.Codec<?>> converterMap = new HashMap<Class<?>, ObjectConverter.Codec<?>>(2);
         converterMap.put(TheInterface.class, firstConverter);
         converterMap.put(TheSecondInterface.class, secondConverter);
         MapperConfig config = createConfig(converterMap);
 
-        ObjectConverter converter = config.findObjectConverter(ClassWithTwoInterfaces.class);
+        ObjectConverter.Writer converter = config.findObjectConverterWriter(ClassWithTwoInterfaces.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(converterMap.get(ClassWithTwoInterfaces.class.getInterfaces()[0]), converter);
     }
@@ -114,40 +118,44 @@ public class MapperConfigTest {
 
         TheAbstractConverter<ClassForTheInterface> theConverter = new TheAbstractConverter<ClassForTheInterface>() {};
 
-        MapperConfig config = createConfig(Collections.<Class<?>, ObjectConverter<?>>singletonMap(ClassForTheInterface.class, theConverter));
+        MapperConfig config = createConfig(Collections.<Class<?>, ObjectConverter.Codec<?>>singletonMap(ClassForTheInterface.class, theConverter));
 
-        ObjectConverter converter = config.findObjectConverter(ClassForTheInterface.class);
-        Assert.assertNotNull(converter);
-        Assert.assertEquals(theConverter, converter);
+        {
+            ObjectConverter.Writer converter = config.findObjectConverterWriter(ClassForTheInterface.class);
+            Assert.assertNotNull(converter);
+            Assert.assertEquals(theConverter, converter);
+        }
 
-        converter = config.findObjectConverter(ExtendingClassForTheInterface.class);
-        Assert.assertNotNull(converter);
-        Assert.assertEquals(theConverter, converter);
+        {
+            ObjectConverter.Writer converter = config.findObjectConverterWriter(ExtendingClassForTheInterface.class);
+            Assert.assertNotNull(converter);
+            Assert.assertEquals(theConverter, converter);
+        }
     }
 
     @Test
     public void testfindObjectConverterConverterForObject() {
         TheConverter<Object> theConverter = new TheConverter<Object>();
 
-        MapperConfig config = createConfig(Collections.<Class<?>, ObjectConverter<?>>singletonMap(Object.class, theConverter));
+        MapperConfig config = createConfig(Collections.<Class<?>, ObjectConverter.Codec<?>>singletonMap(Object.class, theConverter));
 
-        ObjectConverter converter = config.findObjectConverter(ClassForTheInterface.class);
+        ObjectConverter.Reader converter = config.findObjectConverterReader(ClassForTheInterface.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(theConverter, converter);
 
-        converter = config.findObjectConverter(TheInterface.class);
+        converter = config.findObjectConverterReader(TheInterface.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(theConverter, converter);
 
-        converter = config.findObjectConverter(InterfaceExtendingTwoInterfaces.class);
+        converter = config.findObjectConverterReader(InterfaceExtendingTwoInterfaces.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(theConverter, converter);
     }
 
 
-    private MapperConfig createConfig(Map<Class<?>, ObjectConverter<?>> converter) {
+    private MapperConfig createConfig(Map<Class<?>, ObjectConverter.Codec<?>> converter) {
         return new MapperConfig(new ConcurrentHashMap<AdapterKey, Adapter<?, ?>>(0),
-                                converter,
+                                Map.class.cast(converter), Map.class.cast(converter),
                                 -1,
                                 true,
                                 true,
@@ -173,7 +181,7 @@ public class MapperConfigTest {
     private interface InterfaceExtendingTwoInterfaces extends TheInterface, TheSecondInterface {}
 
 
-    private static class TheConverter<T> implements ObjectConverter<T>{
+    private static class TheConverter<T> implements ObjectConverter.Codec<T>{
         @Override
         public void writeJson(T instance, MappingGenerator jsonbGenerator) {
             // dummy
@@ -186,7 +194,7 @@ public class MapperConfigTest {
         }
     }
 
-    private static abstract class TheAbstractConverter<T extends TheInterface> implements ObjectConverter<T> {
+    private static abstract class TheAbstractConverter<T extends TheInterface> implements ObjectConverter.Codec<T> {
         @Override
         public void writeJson(T instance, MappingGenerator jsonbGenerator) {
             // dummy

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
index c14094e..510672d 100644
--- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
@@ -348,7 +348,7 @@ public class ObjectConverterWithAnnotationTest {
         TRIATHLON
     }
 
-    public static class BikeConverter implements ObjectConverter<Bike> {
+    public static class BikeConverter implements ObjectConverter.Codec<Bike> {
 
         public static final List<String> MANUFACTURERS = Arrays.asList("Specialized / S-Works", "Canyon", "Trek", "Scott");
 

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
index 88b03a8..b003ac2 100644
--- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
@@ -160,11 +160,11 @@ public class ObjectTypeTest {
     }
 
 
-    public static class TestWithTypeConverter implements ObjectConverter<Dog> {
+    public static class TestWithTypeConverter implements ObjectConverter.Codec<Dog> {
         @Override
         public void writeJson(Dog instance, MappingGenerator mappingGenerator) {
             mappingGenerator.getJsonGenerator().write("//javaType", instance.getClass().getName());
-            mappingGenerator.writeObject(instance);
+            mappingGenerator.writeObject(instance, mappingGenerator.getJsonGenerator());
         }
 
         @Override
@@ -287,7 +287,7 @@ public class ObjectTypeTest {
     }
 
 
-    public static class DBAccessPoodleConverter implements ObjectConverter<Poodle> {
+    public static class DBAccessPoodleConverter implements ObjectConverter.Codec<Poodle> {
 
         public static final String POODLE_1_NAME = "Poodle1";
         public static final String POODLE_2_NAME = "Poodle2";

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java b/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java
index 717cb15..597c88c 100644
--- a/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java
+++ b/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java
@@ -21,6 +21,8 @@ package javax.json.bind;
 import javax.json.bind.adapter.JsonbAdapter;
 import javax.json.bind.config.PropertyNamingStrategy;
 import javax.json.bind.config.PropertyVisibilityStrategy;
+import javax.json.bind.serializer.JsonbDeserializer;
+import javax.json.bind.serializer.JsonbSerializer;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Locale;
@@ -41,6 +43,8 @@ public class JsonbConfig {
     public static final String BINARY_DATA_STRATEGY = "jsonb.binary-data-strategy";
     public static final String DATE_FORMAT = "jsonb.date-format";
     public static final String LOCALE = "jsonb.locale";
+    public static final String SERIALIZERS = "jsonb.serializers";
+    public static final String DESERIALIZERS = "jsonb.derializers";
 
     public final JsonbConfig withDateFormat(final String dateFormat, final Locale locale) {
         return setProperty(DATE_FORMAT, dateFormat).setProperty(LOCALE, locale != null ? locale : Locale.getDefault());
@@ -102,4 +106,12 @@ public class JsonbConfig {
     public final JsonbConfig withBinaryDataStrategy(final String binaryDataStrategy) {
         return setProperty(BINARY_DATA_STRATEGY, binaryDataStrategy);
     }
+
+    public final JsonbConfig withSerializers(final JsonbSerializer... serializers) {
+        return setProperty(SERIALIZERS, serializers);
+    }
+
+    public final JsonbConfig withDeserializers(final JsonbDeserializer... deserializers) {
+        return setProperty(DESERIALIZERS, deserializers);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeDeserializer.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeDeserializer.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeDeserializer.java
new file mode 100644
index 0000000..ad8fba2
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeDeserializer.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.json.bind.annotation;
+
+import javax.json.bind.serializer.JsonbDeserializer;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ANNOTATION_TYPE, FIELD, METHOD})
+public @interface JsonbTypeDeserializer {
+    Class<? extends JsonbDeserializer> value();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeSerializer.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeSerializer.java b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeSerializer.java
new file mode 100644
index 0000000..f2efdda
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeSerializer.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.json.bind.annotation;
+
+import javax.json.bind.serializer.JsonbSerializer;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ANNOTATION_TYPE, FIELD, METHOD})
+public @interface JsonbTypeSerializer {
+    Class<? extends JsonbSerializer> value();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/serializer/DeserializationContext.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/serializer/DeserializationContext.java b/jsonb-api/src/main/java/javax/json/bind/serializer/DeserializationContext.java
new file mode 100644
index 0000000..05952fb
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/serializer/DeserializationContext.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.json.bind.serializer;
+
+import javax.json.stream.JsonParser;
+import java.lang.reflect.Type;
+
+public interface DeserializationContext {
+    /**
+     * JsonParser cursor is at KEY_NAME event.
+     */
+    <T> T deserialize(Class<T> clazz, JsonParser parser);
+
+    <T> T deserialize(Type type, JsonParser parser);
+
+    <T> T convertDefault(Class<T> clazz, String value);
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbDeserializer.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbDeserializer.java b/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbDeserializer.java
new file mode 100644
index 0000000..1f4de04
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbDeserializer.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.json.bind.serializer;
+
+import javax.json.stream.JsonParser;
+import java.lang.reflect.Type;
+
+public interface JsonbDeserializer<T> {
+    /**
+     * JsonParser is at START_OBJECT event.
+     */
+    T deserialize(JsonParser parser, DeserializationContext ctx, Type rtType);
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbSerializer.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbSerializer.java b/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbSerializer.java
new file mode 100644
index 0000000..6b487a8
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbSerializer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.json.bind.serializer;
+
+import javax.json.stream.JsonGenerator;
+
+public interface JsonbSerializer<T> {
+    void serialize(T obj, JsonGenerator generator, SerializationContext ctx);
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/serializer/SerializationContext.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/serializer/SerializationContext.java b/jsonb-api/src/main/java/javax/json/bind/serializer/SerializationContext.java
new file mode 100644
index 0000000..f26cd1c
--- /dev/null
+++ b/jsonb-api/src/main/java/javax/json/bind/serializer/SerializationContext.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.json.bind.serializer;
+
+import javax.json.stream.JsonGenerator;
+
+public interface SerializationContext {
+    <T> void serialize(String key, T object, JsonGenerator generator);
+
+    <T> void serialize(T object, JsonGenerator generator);
+
+    <T> String convertDefault(T obj, JsonGenerator generator);
+}



Fwd: incubator-johnzon git commit: upgrading jsonb-api + filling some TODO but not complete + splitting ObjectConverter in two (read/write)

Posted by Romain Manni-Bucau <rm...@gmail.com>.
Hello guys,

Trying to write quickly a mail about that if you want to join the effort -
I'll need to move on something else tomorrow.

Updated jsonb-api. Started to impl some parts but that's really just a
first pass to have something and not forget to read some config later.

What is not handled is mainly lists (either serialization of an object from
a list or a list itself, spec expects Type to be List<T> and the T instance
to be passed to the serializer) + root objects (see other thread about
ObjectConverter).

I needed to split ObjectConverter in two to avoid to redefine other API
(Reader/Writer - feel free to extract the 3 classes I created in their own
files if you prefer and to rename it if names are misleading). Also since
we use reader and not parser we need to reparse the loaded instance for
jsonb (de)serializer api. This is not as optimial as it should so I guess
we'll need to move to JsonParser at some point (+ it will make our mapper
symmetric which is not bad ;)).

I probably forget something but at least there is a thread now to shout my
way if you need ;).

Romain Manni-Bucau
@rmannibucau <https://twitter.com/rmannibucau> |  Blog
<http://rmannibucau.wordpress.com> | Github <https://github.com/rmannibucau> |
LinkedIn <https://www.linkedin.com/in/rmannibucau> | Tomitriber
<http://www.tomitribe.com> | JavaEE Factory
<https://javaeefactory-rmannibucau.rhcloud.com>

---------- Forwarded message ----------
From: <rm...@apache.org>
Date: 2016-05-10 20:21 GMT+02:00
Subject: incubator-johnzon git commit: upgrading jsonb-api + filling some
TODO but not complete + splitting ObjectConverter in two (read/write)
To: commits@johnzon.incubator.apache.org


Repository: incubator-johnzon
Updated Branches:
  refs/heads/master 04fbc250a -> 745668a81


upgrading jsonb-api + filling some TODO but not complete + splitting
ObjectConverter in two (read/write)


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

Branch: refs/heads/master
Commit: 745668a81818ec37aed31dc6db868740191a9806
Parents: 04fbc25
Author: Romain manni-Bucau <rm...@gmail.com>
Authored: Tue May 10 20:21:03 2016 +0200
Committer: Romain manni-Bucau <rm...@gmail.com>
Committed: Tue May 10 20:21:03 2016 +0200

----------------------------------------------------------------------
 .../apache/johnzon/jsonb/JohnzonBuilder.java    |  70 ++++++++++++-
 .../apache/johnzon/jsonb/JsonbAccessMode.java   |  70 +++++++++++--
 .../JohnzonDeserializationContext.java          |  48 +++++++++
 .../serializer/JohnzonSerializationContext.java |  48 +++++++++
 .../apache/johnzon/jsonb/SerializerTest.java    | 105 +++++++++++++++++++
 .../java/org/apache/johnzon/mapper/Mapper.java  |   2 +-
 .../apache/johnzon/mapper/MapperBuilder.java    |  14 ++-
 .../org/apache/johnzon/mapper/MapperConfig.java |  50 ++++++---
 .../apache/johnzon/mapper/MappingGenerator.java |   5 +-
 .../johnzon/mapper/MappingGeneratorImpl.java    |  33 +++---
 .../apache/johnzon/mapper/MappingParser.java    |   2 +
 .../johnzon/mapper/MappingParserImpl.java       |  13 ++-
 .../org/apache/johnzon/mapper/Mappings.java     |  68 +++++++++---
 .../apache/johnzon/mapper/ObjectConverter.java  |  18 +++-
 .../johnzon/mapper/access/AccessMode.java       |   3 +
 .../johnzon/mapper/access/FieldAccessMode.java  |  11 ++
 .../mapper/access/FieldAndMethodAccessMode.java |  13 +++
 .../johnzon/mapper/access/MethodAccessMode.java |  16 +++
 .../apache/johnzon/mapper/MapperConfigTest.java |  82 ++++++++-------
 .../ObjectConverterWithAnnotationTest.java      |   2 +-
 .../apache/johnzon/mapper/ObjectTypeTest.java   |   6 +-
 .../main/java/javax/json/bind/JsonbConfig.java  |  12 +++
 .../bind/annotation/JsonbTypeDeserializer.java  |  35 +++++++
 .../bind/annotation/JsonbTypeSerializer.java    |  35 +++++++
 .../bind/serializer/DeserializationContext.java |  33 ++++++
 .../json/bind/serializer/JsonbDeserializer.java |  30 ++++++
 .../json/bind/serializer/JsonbSerializer.java   |  25 +++++
 .../bind/serializer/SerializationContext.java   |  29 +++++
 28 files changed, 771 insertions(+), 107 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/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 13661c2..390c2bc 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
@@ -23,11 +23,14 @@ import org.apache.johnzon.core.JsonGeneratorFactoryImpl;
 import org.apache.johnzon.jsonb.cdi.CDIs;
 import org.apache.johnzon.jsonb.converter.JohnzonJsonbAdapter;
 import org.apache.johnzon.jsonb.factory.SimpleJohnzonAdapterFactory;
+import org.apache.johnzon.jsonb.serializer.JohnzonDeserializationContext;
+import org.apache.johnzon.jsonb.serializer.JohnzonSerializationContext;
 import org.apache.johnzon.jsonb.spi.JohnzonAdapterFactory;
 import org.apache.johnzon.mapper.Adapter;
 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.internal.AdapterKey;
 import org.apache.johnzon.mapper.internal.ConverterAdapter;

@@ -39,8 +42,11 @@ 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.bind.serializer.JsonbDeserializer;
+import javax.json.bind.serializer.JsonbSerializer;
 import javax.json.spi.JsonProvider;
 import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonParserFactory;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -72,6 +78,8 @@ import java.util.SimpleTimeZone;
 import java.util.TimeZone;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
 import java.util.stream.Stream;

 import static java.time.format.DateTimeFormatter.ofPattern;
@@ -107,6 +115,25 @@ public class JohnzonBuilder implements JsonbBuilder {

 builder.setGeneratorFactory(jsonp.createGeneratorFactory(generatorConfig()));

 builder.setReaderFactory(jsonp.createReaderFactory(emptyMap()));
         }
+        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());
+            }
+        };

         if (config == null) {
             config = new JsonbConfig();
@@ -189,7 +216,7 @@ public class JohnzonBuilder implements JsonbBuilder {
                 propertyNamingStrategy, orderValue, visibilityStrategy,

 !namingStrategyValue.orElse("").equals(PropertyNamingStrategy.CASE_INSENSITIVE),
                 defaultConverters,
-                factory);
+                factory, parserFactoryProvider);
         builder.setAccessMode(accessMode);


@@ -240,6 +267,40 @@ public class JohnzonBuilder implements JsonbBuilder {
         builder.setReadAttributeBeforeWrite(

 config.getProperty("johnzon.readAttributeBeforeWrite").map(Boolean.class::cast).orElse(false));

+
config.getProperty(JsonbConfig.SERIALIZERS).map(JsonbSerializer[].class::cast).ifPresent(serializers
-> {
+            Stream.of(serializers).forEach(s -> {
+                final ParameterizedType pt = findPT(s,
JsonbSerializer.class);
+                if (pt == null) {
+                    throw new IllegalArgumentException(s + " doesn't
implement JsonbSerializer");
+                }
+                final Type[] args = pt.getActualTypeArguments();
+                // TODO: support PT in ObjectConverter (list)
+                if (args.length != 1 || !Class.class.isInstance(args[0])) {
+                    throw new IllegalArgumentException("We only support
serializer on Class for now");
+                }
+                builder.addObjectConverter(
+                        Class.class.cast(args[0]), (ObjectConverter.Writer)
+                        (instance, jsonbGenerator) ->
s.serialize(instance, jsonbGenerator.getJsonGenerator(), new
JohnzonSerializationContext(jsonbGenerator)));
+            });
+        });
+
config.getProperty(JsonbConfig.DESERIALIZERS).map(JsonbDeserializer[].class::cast).ifPresent(deserializers
-> {
+            Stream.of(deserializers).forEach(d -> {
+                final ParameterizedType pt = findPT(d,
JsonbDeserializer.class);
+                if (pt == null) {
+                    throw new IllegalArgumentException(d + " doesn't
implement JsonbDeserializer");
+                }
+                final Type[] args = pt.getActualTypeArguments();
+                if (args.length != 1 || !Class.class.isInstance(args[0])) {
+                    throw new IllegalArgumentException("We only support
deserializer on Class for now");
+                }
+                // 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));
+            });
+        });
+
         final boolean useCdi = cdiIntegration != null &&
cdiIntegration.isCanWrite();
         final Mapper mapper = builder.addCloseable(accessMode).build();

@@ -261,6 +322,13 @@ public class JohnzonBuilder implements JsonbBuilder {
         } : new JohnsonJsonb(mapper);
     }

+    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));
+    }
+
     private Object getBeanManager() {
         if (beanManager == null) {
             try { // don't trigger CDI is not there

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
----------------------------------------------------------------------
diff --git
a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
index 4a0a340..fa2e536 100644
---
a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
+++
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
@@ -25,8 +25,11 @@ 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.jsonb.serializer.JohnzonDeserializationContext;
+import org.apache.johnzon.jsonb.serializer.JohnzonSerializationContext;
 import org.apache.johnzon.jsonb.spi.JohnzonAdapterFactory;
 import org.apache.johnzon.mapper.Adapter;
+import org.apache.johnzon.mapper.ObjectConverter;
 import org.apache.johnzon.mapper.access.AccessMode;
 import org.apache.johnzon.mapper.access.FieldAccessMode;
 import org.apache.johnzon.mapper.access.FieldAndMethodAccessMode;
@@ -44,9 +47,14 @@ 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.JsonbTypeDeserializer;
+import javax.json.bind.annotation.JsonbTypeSerializer;
 import javax.json.bind.config.PropertyNamingStrategy;
 import javax.json.bind.config.PropertyOrderStrategy;
 import javax.json.bind.config.PropertyVisibilityStrategy;
+import javax.json.bind.serializer.JsonbDeserializer;
+import javax.json.bind.serializer.JsonbSerializer;
+import javax.json.stream.JsonParserFactory;
 import java.io.Closeable;
 import java.io.IOException;
 import java.lang.annotation.Annotation;
@@ -74,6 +82,7 @@ import java.util.OptionalLong;
 import java.util.TreeMap;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
+import java.util.function.Supplier;
 import java.util.stream.Stream;

 import static java.util.Arrays.asList;
@@ -89,10 +98,12 @@ public class JsonbAccessMode implements AccessMode,
Closeable {
     private final Map<AdapterKey, Adapter<?, ?>> defaultConverters;
     private final JohnzonAdapterFactory factory;
     private final Collection<JohnzonAdapterFactory.Instance<?>> toRelease
= new ArrayList<>();
+    private final Supplier<JsonParserFactory> parserFactory;

     public JsonbAccessMode(final PropertyNamingStrategy
propertyNamingStrategy, final String orderValue,
                            final PropertyVisibilityStrategy
visibilityStrategy, final boolean caseSensitive,
-                           final Map<AdapterKey, Adapter<?, ?>>
defaultConverters, final JohnzonAdapterFactory factory) {
+                           final Map<AdapterKey, Adapter<?, ?>>
defaultConverters, final JohnzonAdapterFactory factory,
+                           final Supplier<JsonParserFactory>
parserFactory) {
         this.naming = propertyNamingStrategy;
         this.order = orderValue;
         this.visibility = visibilityStrategy;
@@ -100,6 +111,7 @@ public class JsonbAccessMode implements AccessMode,
Closeable {
         this.delegate = new FieldAndMethodAccessMode(true, true);
         this.defaultConverters = defaultConverters;
         this.factory = factory;
+        this.parserFactory = parserFactory;
     }

     @Override
@@ -266,13 +278,11 @@ public class JsonbAccessMode implements AccessMode,
Closeable {
         final Adapter converter;
         if (adapter != null) {
             final Class<? extends JsonbAdapter> value = adapter.value();
-            final ParameterizedType pt = ParameterizedType.class.cast(
-                    Stream.of(value.getGenericInterfaces())
-                            .filter(i ->
ParameterizedType.class.isInstance(i) &&
ParameterizedType.class.cast(i).getRawType() ==
JsonbAdapter.class).findFirst().orElse(null));
+            final ParameterizedType pt = findPt(value, JsonbAdapter.class);
             if (pt == null) {
                 throw new IllegalArgumentException(value + " doesn't
implement JsonbAdapter");
             }
-            final JohnzonAdapterFactory.Instance<? extends JsonbAdapter>
instance = newAdapter(value);
+            final JohnzonAdapterFactory.Instance<? extends JsonbAdapter>
instance = newInstance(value);
             toRelease.add(instance);
             final Type[] actualTypeArguments = pt.getActualTypeArguments();
             converter = new JohnzonJsonbAdapter(instance.getValue(),
actualTypeArguments[0], actualTypeArguments[1]);
@@ -296,7 +306,13 @@ public class JsonbAccessMode implements AccessMode,
Closeable {
         return converter;
     }

-    private JohnzonAdapterFactory.Instance<? extends JsonbAdapter>
newAdapter(final Class<? extends JsonbAdapter> value) {
+    private ParameterizedType findPt(final Class<?> value, final Class<?>
type) {
+        return ParameterizedType.class.cast(
+                        Stream.of(value.getGenericInterfaces())
+                                .filter(i ->
ParameterizedType.class.isInstance(i) &&
ParameterizedType.class.cast(i).getRawType() ==
type).findFirst().orElse(null));
+    }
+
+    private JohnzonAdapterFactory.Instance newInstance(final Class<?>
value) {
         return factory.create(value);
     }

@@ -326,6 +342,7 @@ public class JsonbAccessMode implements AccessMode,
Closeable {
             }

             // we are visible
+            final JsonbTypeSerializer serializer =
initialReader.getAnnotation(JsonbTypeSerializer.class);
             final JsonbProperty property =
initialReader.getAnnotation(JsonbProperty.class);
             final JsonbNillable nillable =
initialReader.getClassOrPackageAnnotation(JsonbNillable.class);
             final boolean isNillable = nillable != null || (property !=
null && property.nillable());
@@ -343,6 +360,21 @@ public class JsonbAccessMode implements AccessMode,
Closeable {
                 throw new IllegalArgumentException(e);
             }

+            final ObjectConverter.Writer writer;
+            if (serializer != null) {
+                final Class<? extends JsonbSerializer> value =
serializer.value();
+                final ParameterizedType pt = findPt(value,
JsonbSerializer.class);
+                if (pt == null) {
+                    throw new IllegalArgumentException(value + " doesn't
implement JsonbSerializer");
+                }
+                final JohnzonAdapterFactory.Instance<? extends
JsonbSerializer> instance = newInstance(value);
+                toRelease.add(instance);
+                writer = (instance1, jsonbGenerator) ->
+                        instance.getValue().serialize(instance1,
jsonbGenerator.getJsonGenerator(), new
JohnzonSerializationContext(jsonbGenerator));
+            } else {
+                writer = null;
+            }
+
             // handle optionals since mapper is still only java 7
             final Type type;
             final Function<Object, Object> reader;
@@ -371,6 +403,11 @@ public class JsonbAccessMode implements AccessMode,
Closeable {
                 }

                 @Override
+                public ObjectConverter.Writer<?>
findObjectConverterWriter() {
+                    return writer;
+                }
+
+                @Override
                 public Type getType() {
                     return type;
                 }
@@ -427,6 +464,7 @@ public class JsonbAccessMode implements AccessMode,
Closeable {
             }

             // we are visible
+            final JsonbTypeDeserializer deserializer =
initialWriter.getAnnotation(JsonbTypeDeserializer.class);
             final JsonbProperty property =
initialWriter.getAnnotation(JsonbProperty.class);
             final JsonbNillable nillable =
initialWriter.getClassOrPackageAnnotation(JsonbNillable.class);
             final boolean isNillable = nillable != null || (property !=
null && property.nillable());
@@ -444,6 +482,21 @@ public class JsonbAccessMode implements AccessMode,
Closeable {
                 throw new IllegalArgumentException(e);
             }

+            final ObjectConverter.Reader reader;
+            if (deserializer != null) {
+                final Class<? extends JsonbDeserializer> value =
deserializer.value();
+                final ParameterizedType pt = findPt(value,
JsonbDeserializer.class);
+                if (pt == null) {
+                    throw new IllegalArgumentException(value + " doesn't
implement JsonbDeserializer");
+                }
+                final JohnzonAdapterFactory.Instance<? extends
JsonbDeserializer> instance = newInstance(value);
+                toRelease.add(instance);
+                reader = (jsonObject, targetType, parser) ->
+
instance.getValue().deserialize(parserFactory.get().createParser(jsonObject),
new JohnzonDeserializationContext(parser), targetType);
+            } else {
+                reader = null;
+            }
+
             // handle optionals since mapper is still only java 7
             final Type type;
             final BiConsumer<Object, Object> writer;
@@ -472,6 +525,11 @@ public class JsonbAccessMode implements AccessMode,
Closeable {
                 }

                 @Override
+                public ObjectConverter.Reader<?>
findObjectConverterReader() {
+                    return reader;
+                }
+
+                @Override
                 public Type getType() {
                     return type;
                 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonDeserializationContext.java
----------------------------------------------------------------------
diff --git
a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonDeserializationContext.java
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonDeserializationContext.java
new file mode 100644
index 0000000..2049603
--- /dev/null
+++
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonDeserializationContext.java
@@ -0,0 +1,48 @@
+/*
+ * 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.serializer;
+
+import org.apache.johnzon.mapper.MappingParser;
+
+import javax.json.bind.serializer.DeserializationContext;
+import javax.json.stream.JsonParser;
+import java.lang.reflect.Type;
+
+public class JohnzonDeserializationContext implements
DeserializationContext {
+    private final MappingParser runtime;
+
+    public JohnzonDeserializationContext(final MappingParser runtime) {
+        this.runtime = runtime;
+    }
+
+    @Override
+    public <T> T deserialize(final Class<T> clazz, final JsonParser
parser) {
+        return null;
+    }
+
+    @Override
+    public <T> T deserialize(final Type type, final JsonParser parser) {
+        return null;
+    }
+
+    @Override
+    public <T> T convertDefault(final Class<T> clazz, final String value) {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonSerializationContext.java
----------------------------------------------------------------------
diff --git
a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonSerializationContext.java
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonSerializationContext.java
new file mode 100644
index 0000000..d40ca24
--- /dev/null
+++
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/serializer/JohnzonSerializationContext.java
@@ -0,0 +1,48 @@
+/*
+ * 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.serializer;
+
+import org.apache.johnzon.mapper.MappingGenerator;
+
+import javax.json.bind.serializer.SerializationContext;
+import javax.json.stream.JsonGenerator;
+
+// TODO: fix it
+public class JohnzonSerializationContext implements SerializationContext {
+    private final MappingGenerator runtime;
+
+    public JohnzonSerializationContext(final MappingGenerator runtime) {
+        this.runtime = runtime;
+    }
+
+    @Override
+    public <T> void serialize(final String key, final T object, final
JsonGenerator generator) {
+        runtime.writeObject(object, generator);
+    }
+
+    @Override
+    public <T> void serialize(final T object, final JsonGenerator
generator) {
+        runtime.writeObject(object, generator);
+    }
+
+    @Override
+    public <T> String convertDefault(final T obj, final JsonGenerator
generator) {
+        return runtime.convert(obj);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializerTest.java
----------------------------------------------------------------------
diff --git
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializerTest.java
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializerTest.java
new file mode 100644
index 0000000..475fbcc
--- /dev/null
+++
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/SerializerTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.Jsonb;
+import javax.json.bind.JsonbBuilder;
+import javax.json.bind.annotation.JsonbTypeDeserializer;
+import javax.json.bind.annotation.JsonbTypeSerializer;
+import javax.json.bind.serializer.DeserializationContext;
+import javax.json.bind.serializer.JsonbDeserializer;
+import javax.json.bind.serializer.JsonbSerializer;
+import javax.json.bind.serializer.SerializationContext;
+import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonParser;
+import java.lang.reflect.Type;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+// TODO: enhance
+public class SerializerTest {
+    @Test
+    public void roundTrip() {
+        final Jsonb jsonb = JsonbBuilder.create();
+
+        final String json =
"{\"foo\":{\"full\":true,\"name\":\"SerializerTest\"}}";
+
+        final Foo foo = new Foo();
+        foo.name = "SerializerTest";
+        final Wrapper wrapper = new Wrapper();
+        wrapper.foo = foo;
+
+        assertEquals(json, jsonb.toJson(wrapper));
+
+        final Wrapper deser = jsonb.fromJson(json, Wrapper.class);
+        assertEquals(foo.name, deser.foo.name);
+        assertEquals(foo.name.length(), deser.foo.value);
+        assertTrue(deser.foo.flag);
+    }
+
+    public static class Foo {
+        public String name;
+        public int value;
+        public boolean flag;
+    }
+
+    public static class Wrapper {
+        @JsonbTypeSerializer(FooSer.class)
+        @JsonbTypeDeserializer(FooDeser.class)
+        public Foo foo;
+    }
+
+    public static class FooDeser implements JsonbDeserializer<Foo> {
+        @Override
+        public Foo deserialize(final JsonParser parser, final
DeserializationContext ctx, final Type rtType) {
+            final Foo f = new Foo();
+            assertTrue(parser.hasNext());
+            assertEquals(JsonParser.Event.START_OBJECT, parser.next());
+            assertTrue(parser.hasNext());
+            assertEquals(JsonParser.Event.KEY_NAME, parser.next());
+            assertEquals("full", parser.getString());
+            assertTrue(parser.hasNext());
+            assertEquals(JsonParser.Event.VALUE_TRUE, parser.next());
+            assertTrue(parser.hasNext());
+            assertEquals(JsonParser.Event.KEY_NAME, parser.next());
+            assertEquals("name", parser.getString());
+            assertTrue(parser.hasNext());
+            assertEquals(JsonParser.Event.VALUE_STRING, parser.next());
+            f.name = parser.getString();
+            assertTrue(parser.hasNext());
+            assertEquals(JsonParser.Event.END_OBJECT, parser.next());
+
+            // to be sure we passed there
+            f.flag = true;
+            f.value = f.name.length();
+            return f;
+        }
+    }
+
+    public static class FooSer implements JsonbSerializer<Foo> {
+        @Override
+        public void serialize(final Foo obj, final JsonGenerator
generator, final SerializationContext ctx) {
+            generator.write("full", true);
+            generator.write("name", obj.name);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
index 986f4c3..c8a163e 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
@@ -136,7 +136,7 @@ public class Mapper implements Closeable {

         RuntimeException originalException = null;
         try {
-            mappingGenerator.doWriteObject(object, true);
+            mappingGenerator.doWriteObject(object, generator, true);
         } catch (RuntimeException e) {
             originalException = e;
         } finally {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
index d354950..73c32da 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
@@ -122,7 +122,8 @@ public class MapperBuilder {
     private AccessMode accessMode;
     private Charset encoding =
Charset.forName(System.getProperty("johnzon.mapper.encoding", "UTF-8"));
     private ConcurrentMap<AdapterKey, Adapter<?, ?>> adapters = new
ConcurrentHashMap<AdapterKey, Adapter<?, ?>>(DEFAULT_CONVERTERS);
-    private Map<Class<?>, ObjectConverter<?>> objectConverters = new
HashMap<Class<?>, ObjectConverter<?>>();
+    private Map<Class<?>, ObjectConverter.Reader<?>>
objectConverterReaders = new HashMap<Class<?>, ObjectConverter.Reader<?>>();
+    private Map<Class<?>, ObjectConverter.Writer<?>>
objectConverterWriters = new HashMap<Class<?>, ObjectConverter.Writer<?>>();
     private Map<Class<?>, String[]> ignoredForFields = new
HashMap<Class<?>, String[]>();

     public Mapper build() {
@@ -187,7 +188,7 @@ public class MapperBuilder {
         return new Mapper(
                 readerFactory, generatorFactory,
                 new MapperConfig(
-                        adapters, objectConverters,
+                        adapters, objectConverterWriters,
objectConverterReaders,
                         version, close,
                         skipNull, skipEmptyArray,
                         treatByteArrayAsBase64, treatByteArrayAsBase64URL,
readAttributeBeforeWrite,
@@ -342,8 +343,13 @@ public class MapperBuilder {
         return this;
     }

-    public <T> MapperBuilder addObjectConverter(final Class<T> targetType,
final ObjectConverter<T> objectConverter) {
-        this.objectConverters.put(targetType, objectConverter);
+    public <T> MapperBuilder addObjectConverter(final Class<T> targetType,
final MapperConverter objectConverter) {
+        if (ObjectConverter.Reader.class.isInstance(objectConverter)) {
+            this.objectConverterReaders.put(targetType,
ObjectConverter.Reader.class.cast(objectConverter));
+        }
+        if (ObjectConverter.Writer.class.isInstance(objectConverter)) {
+            this.objectConverterWriters.put(targetType,
ObjectConverter.Writer.class.cast(objectConverter));
+        }
         return this;
     }


http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
index afd40b2..590c238 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
@@ -37,7 +37,7 @@ import java.util.concurrent.ConcurrentMap;
  */
 class MapperConfig implements Cloneable {

-    private static final ObjectConverter NO_CONVERTER = new
ObjectConverter() {
+    private static final ObjectConverter.Codec NO_CONVERTER = new
ObjectConverter.Codec() {
         @Override
         public void writeJson(Object instance, MappingGenerator
jsonbGenerator) {
             // just a dummy
@@ -59,15 +59,18 @@ class MapperConfig implements Cloneable {
     private final AccessMode accessMode;
     private final Charset encoding;
     private final ConcurrentMap<AdapterKey, Adapter<?, ?>> adapters;
-    private final Map<Class<?>, ObjectConverter<?>> objectConverters;
+    private final Map<Class<?>, ObjectConverter.Writer<?>>
objectConverterWriters;
+    private final Map<Class<?>, ObjectConverter.Reader<?>>
objectConverterReaders;
     private final Comparator<String> attributeOrder;

-    private final Map<Class<?>, ObjectConverter<?>> objectConverterCache;
+    private final Map<Class<?>, ObjectConverter.Writer<?>>
objectConverterWriterCache;
+    private final Map<Class<?>, ObjectConverter.Reader<?>>
objectConverterReaderCache;

     //disable checkstyle for 10+ parameters
     //CHECKSTYLE:OFF
     public MapperConfig(final ConcurrentMap<AdapterKey, Adapter<?, ?>>
adapters,
-                        final Map<Class<?>, ObjectConverter<?>>
objectConverters,
+                        final Map<Class<?>, ObjectConverter.Writer<?>>
objectConverterWriters,
+                        final Map<Class<?>, ObjectConverter.Reader<?>>
objectConverterReaders,
                         final int version, final boolean close,
                         final boolean skipNull, final boolean
skipEmptyArray,
                         final boolean treatByteArrayAsBase64, final
boolean treatByteArrayAsBase64URL,
@@ -75,7 +78,8 @@ class MapperConfig implements Cloneable {
                         final AccessMode accessMode, final Charset
encoding,
                         final Comparator<String> attributeOrder) {
     //CHECKSTYLE:ON
-        this.objectConverters = objectConverters;
+        this.objectConverterWriters = objectConverterWriters;
+        this.objectConverterReaders = objectConverterReaders;
         this.version = version;
         this.close = close;
         this.skipNull = skipNull;
@@ -88,7 +92,8 @@ class MapperConfig implements Cloneable {
         this.adapters = adapters;
         this.attributeOrder = attributeOrder;

-        this.objectConverterCache = new HashMap<Class<?>,
ObjectConverter<?>>(objectConverters.size());
+        this.objectConverterWriterCache = new HashMap<Class<?>,
ObjectConverter.Writer<?>>(objectConverterWriters.size());
+        this.objectConverterReaderCache = new HashMap<Class<?>,
ObjectConverter.Reader<?>>(objectConverterReaders.size());
     }

     public Adapter findAdapter(final Type aClass) {
@@ -123,13 +128,22 @@ class MapperConfig implements Cloneable {
      *
      * @throws IllegalArgumentException if {@code clazz} is {@code null}
      */
-    public ObjectConverter findObjectConverter(Class clazz) {
+    public ObjectConverter.Reader findObjectConverterReader(Class clazz) {
+        return findObjectConverter(clazz, objectConverterReaders,
objectConverterReaderCache);
+    }
+    public ObjectConverter.Writer findObjectConverterWriter(Class clazz) {
+        return findObjectConverter(clazz, objectConverterWriters,
objectConverterWriterCache);
+    }
+
+    private <T> T findObjectConverter(final Class clazz,
+                                                final Map<Class<?>, T>
from,
+                                                final Map<Class<?>, T>
cache) {
         if (clazz == null) {
             throw new IllegalArgumentException("clazz must not be null");
         }

         // first lets look in our cache
-        ObjectConverter<?> converter = objectConverterCache.get(clazz);
+        T converter = cache.get(clazz);
         if (converter != null && converter != NO_CONVERTER) {
             return converter;
         }
@@ -142,9 +156,9 @@ class MapperConfig implements Cloneable {
         // we get called the first time for this class
         // lets search...

-        Map<Class<?>, ObjectConverter<?>> matchingConverters = new
HashMap<Class<?>, ObjectConverter<?>>();
+        Map<Class<?>, T> matchingConverters = new HashMap<Class<?>, T>();

-        for (Map.Entry<Class<?>, ObjectConverter<?>> entry :
objectConverters.entrySet()) {
+        for (Map.Entry<Class<?>, T> entry : from.entrySet()) {

             if (clazz == entry.getKey()) {
                 converter = entry.getValue();
@@ -157,12 +171,12 @@ class MapperConfig implements Cloneable {
         }

         if (converter != null) {
-            objectConverterCache.put(clazz, converter);
+            cache.put(clazz, converter);
             return converter;
         }

         if (matchingConverters.isEmpty()) {
-            objectConverterCache.put(clazz, NO_CONVERTER);
+            cache.put(clazz, (T) NO_CONVERTER);
             return null;
         }

@@ -195,9 +209,9 @@ class MapperConfig implements Cloneable {
         }

         if (converter == null) {
-            objectConverterCache.put(clazz, NO_CONVERTER);
+            cache.put(clazz, (T) NO_CONVERTER);
         } else {
-            objectConverterCache.put(clazz, converter);
+            cache.put(clazz, converter);
         }

         return converter;
@@ -243,8 +257,12 @@ class MapperConfig implements Cloneable {
         return adapters;
     }

-    public Map<Class<?>, ObjectConverter<?>> getObjectConverters() {
-        return objectConverters;
+    public Map<Class<?>, ObjectConverter.Writer<?>>
getObjectConverterWriters() {
+        return objectConverterWriters;
+    }
+
+    public Map<Class<?>, ObjectConverter.Reader<?>>
getObjectConverterReaders() {
+        return objectConverterReaders;
     }

     public Comparator<String> getAttributeOrder() {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
index b3719a2..bd02cfe 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGenerator.java
@@ -53,9 +53,12 @@ public interface MappingGenerator {
      *     "firstName":"Karl", "lastName":"SomeName",
"address":{"street":"mystreet"}
      * </pre>
      * @param o the object to write
+     * @param generator the jsonp generator to use
      * @return itself, for easier chaining of commands
      */
-    MappingGenerator writeObject(Object o);
+    MappingGenerator writeObject(Object o, JsonGenerator generator);


+    // @Experimental
+    <T> String convert(T obj);
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
index 48c999d..f984373 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
@@ -18,6 +18,11 @@
  */
 package org.apache.johnzon.mapper;

+import org.apache.johnzon.mapper.internal.AdapterKey;
+
+import javax.json.JsonValue;
+import javax.json.stream.JsonGenerator;
+import javax.xml.bind.DatatypeConverter;
 import java.lang.reflect.Array;
 import java.lang.reflect.InvocationTargetException;
 import java.math.BigDecimal;
@@ -25,12 +30,6 @@ import java.math.BigInteger;
 import java.util.Collection;
 import java.util.Map;

-import javax.json.JsonValue;
-import javax.json.stream.JsonGenerator;
-import javax.xml.bind.DatatypeConverter;
-
-import org.apache.johnzon.mapper.internal.AdapterKey;
-
 public class MappingGeneratorImpl implements MappingGenerator {
     private final MapperConfig config;
     private final JsonGenerator generator;
@@ -49,18 +48,23 @@ public class MappingGeneratorImpl implements
MappingGenerator {
     }

     @Override
-    public MappingGenerator writeObject(Object object) {
+    public MappingGenerator writeObject(Object object, JsonGenerator
generator) {
         if (object == null) {
             return this;
         } else if (object instanceof JsonValue) {
             generator.write((JsonValue) object);
         } else {
-            doWriteObject(object, false);
+            doWriteObject(object, generator, false);
         }
         return this;
     }

-    public void doWriteObject(Object object, boolean writeBody) {
+    @Override
+    public <T> String convert(final T obj) {
+        return (String) config.findAdapter(obj.getClass()).to(obj);
+    }
+
+    public void doWriteObject(Object object, JsonGenerator generator,
boolean writeBody) {
         try {
             if (object instanceof Map) {
                 if (writeBody) {
@@ -94,7 +98,7 @@ public class MappingGeneratorImpl implements
MappingGenerator {
                 generator.writeStartObject();
             }

-            ObjectConverter objectConverter =
config.findObjectConverter(objectClass);
+            ObjectConverter.Writer objectConverter =
config.findObjectConverterWriter(objectClass);
             if (writeBody && objectConverter != null) {
                 objectConverter.writeJson(object, this);
             } else {
@@ -269,7 +273,8 @@ public class MappingGeneratorImpl implements
MappingGenerator {
                             final boolean primitive, final boolean array,
                             final boolean collection, final boolean map,
                             final Adapter itemConverter,
-                            final String key, final Object value, final
ObjectConverter objectConverter) throws InvocationTargetException,
IllegalAccessException {
+                            final String key, final Object value,
+                            final ObjectConverter.Writer objectConverter)
throws InvocationTargetException, IllegalAccessException {
         if (array) {
             final int length = Array.getLength(value);
             if (length == 0 && config.isSkipEmptyArray()) {
@@ -319,9 +324,9 @@ public class MappingGeneratorImpl implements
MappingGenerator {
                 return;
             } else {

-                ObjectConverter objectConverterToUse = objectConverter;
+                ObjectConverter.Writer objectConverterToUse =
objectConverter;
                 if (objectConverterToUse == null) {
-                    objectConverterToUse =
config.findObjectConverter(type);
+                    objectConverterToUse =
config.findObjectConverterWriter(type);
                 }

                 if (objectConverterToUse != null) {
@@ -358,7 +363,7 @@ public class MappingGeneratorImpl implements
MappingGenerator {
             } else if (o == null) {
                 generator.writeNull();
             } else {
-                doWriteObject(o, true);
+                doWriteObject(o, generator, true);
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParser.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParser.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParser.java
index cee68d8..6269884 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParser.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParser.java
@@ -31,4 +31,6 @@ public interface MappingParser {
     <T> T readObject(Type targetType);

     <T> T readObject(JsonValue jsonValue, Type targetType);
+
+    <T> T convert(Class<T> clazz, String value);
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
index 87ceb49..812b7a6 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
@@ -115,6 +115,11 @@ public class MappingParserImpl implements
MappingParser {
         return readObject(jsonValue, targetType, targetType instanceof
Class || targetType instanceof ParameterizedType);
     }

+    @Override
+    public <T> T convert(final Class<T> clazz, final String value) {
+        return (T) config.findAdapter(clazz).to(value);
+    }
+
     private <T> T readObject(JsonValue jsonValue, Type targetType, boolean
applyObjectConverter) {
         if (JsonStructure.class == targetType || JsonObject.class ==
targetType || JsonValue.class == targetType) {
             return (T) jsonValue;
@@ -186,7 +191,7 @@ public class MappingParserImpl implements MappingParser
{
                 throw new MapperException("ObjectConverters are only
supported for Classes not Types");
             }

-            ObjectConverter objectConverter =
config.findObjectConverter((Class) type);
+            ObjectConverter.Reader objectConverter =
config.findObjectConverterReader((Class) type);
             if (objectConverter != null) {
                 return objectConverter.fromJson(object, type, new
SuppressConversionMappingParser(this, object));
             }
@@ -535,7 +540,7 @@ public class MappingParserImpl implements MappingParser
{
     }

     private Object toValue(final Object baseInstance, final JsonValue
jsonValue, final Adapter converter,
-                           final Adapter itemConverter, final Type type,
final ObjectConverter objectConverter) {
+                           final Adapter itemConverter, final Type type,
final ObjectConverter.Reader objectConverter) {

         if (objectConverter != null) {

@@ -627,6 +632,10 @@ public class MappingParserImpl implements
MappingParser {
             return delegate.readObject(jsonValue, targetType);
         }

+        @Override
+        public <T> T convert(final Class<T> clazz, final String value) {
+            return delegate.convert(clazz, value);
+        }
     }

 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
index 8c1154b..db0ce1c 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
@@ -85,7 +85,7 @@ public class Mappings {
         final int version;
         final Adapter converter;
         final Adapter itemConverter;
-        final ObjectConverter objectConverter;
+        final ObjectConverter.Writer objectConverter;
         final boolean primitive;
         final boolean array;
         final boolean map;
@@ -95,6 +95,7 @@ public class Mappings {
                       final boolean primitive, final boolean array,
                       final boolean collection, final boolean map,
                       final MapperConverter converter,
+                      final ObjectConverter.Writer providedObjectConverter,
                       final int version) {
             this.reader = reader;
             this.version = version;
@@ -104,14 +105,14 @@ public class Mappings {

             Adapter theConverter = null;
             Adapter theItemConverter = null;
-            ObjectConverter theObjectConverter = null;
+            ObjectConverter.Writer theObjectConverter =
providedObjectConverter;

             if (converter != null) {

-                if (converter instanceof ObjectConverter) {
-                    theObjectConverter = (ObjectConverter) converter;
-                } else {
-
+                if (converter instanceof ObjectConverter.Writer) {
+                    theObjectConverter = (ObjectConverter.Writer)
converter;
+                }
+                if (theObjectConverter == null) {
                     Adapter adapter;
                     if (converter instanceof Converter) {
                         adapter = new ConverterAdapter((Converter)
converter);
@@ -155,12 +156,12 @@ public class Mappings {
         public final Type paramType;
         public final Adapter converter;
         public final Adapter itemConverter;
-        public final ObjectConverter objectConverter;
+        public final ObjectConverter.Reader objectConverter;
         public final boolean primitive;
         public final boolean array;

         public Setter(final AccessMode.Writer writer, final boolean
primitive, final boolean array,
-                      final Type paramType, final MapperConverter
converter,
+                      final Type paramType, final MapperConverter
converter, final ObjectConverter.Reader providedObjectConverter,
                       final int version) {
             this.writer = writer;
             this.paramType = paramType;
@@ -170,14 +171,14 @@ public class Mappings {

             Adapter theConverter = null;
             Adapter theItemConverter = null;
-            ObjectConverter theObjectConverter = null;
+            ObjectConverter.Reader theObjectConverter =
providedObjectConverter;

             if (converter != null) {

-                if (converter instanceof ObjectConverter) {
-                    theObjectConverter = (ObjectConverter) converter;
-                } else {
-
+                if (converter instanceof ObjectConverter.Reader) {
+                    theObjectConverter = (ObjectConverter.Reader)
converter;
+                }
+                if (theObjectConverter == null){
                     Adapter adapter;
                     if (converter instanceof Converter) {
                         adapter = new ConverterAdapter((Converter)
converter);
@@ -398,7 +399,8 @@ public class Mappings {
             final Class<?> returnType = Class.class.isInstance(param) ?
Class.class.cast(param) : null;
             final Setter setter = new Setter(
                 value, isPrimitive(param), returnType != null &&
returnType.isArray(), param,
-                findConverter(copyDate, value), writeIgnore != null ?
writeIgnore.minVersion() : -1);
+                findConverter(copyDate, value),
value.findObjectConverterReader(),
+                writeIgnore != null ? writeIgnore.minVersion() : -1);
             setters.put(key, setter);
         }
     }
@@ -417,7 +419,7 @@ public class Mappings {
                     || (returnType != null &&
Collection.class.isAssignableFrom(returnType)),
                 (pt != null &&
Map.class.isAssignableFrom(Class.class.cast(pt.getRawType())))
                     || (returnType != null &&
Map.class.isAssignableFrom(returnType)),
-                findConverter(copyDate, value),
+                findConverter(copyDate, value),
value.findObjectConverterWriter(),
                 readIgnore != null ? readIgnore.minVersion() : -1);
             getters.put(key, getter);
         }
@@ -465,11 +467,11 @@ public class Mappings {

         final Getter getter = getters.get(key);
         final MapBuilderReader newReader = new
MapBuilderReader(objectGetters, path, config.getVersion());
-        getters.put(key, new Getter(getter == null ? newReader : new
CompositeReader(getter.reader, newReader), false, false, false, true, null,
-1));
+        getters.put(key, new Getter(getter == null ? newReader : new
CompositeReader(getter.reader, newReader), false, false, false, true, null,
null, -1));

         final Setter newSetter = setters.get(key);
         final MapUnwrapperWriter newWriter = new
MapUnwrapperWriter(objectSetters, path);
-        setters.put(key, new Setter(newSetter == null ? newWriter : new
CompositeWriter(newSetter.writer, newWriter), false, false, VIRTUAL_TYPE,
null, -1));
+        setters.put(key, new Setter(newSetter == null ? newWriter : new
CompositeWriter(newSetter.writer, newWriter), false, false, VIRTUAL_TYPE,
null, null, -1));
     }

     private MapperConverter findConverter(final boolean copyDate, final
AccessMode.DecoratedType decoratedType) {
@@ -574,6 +576,11 @@ public class Mappings {
         }

         @Override
+        public ObjectConverter.Writer<?> findObjectConverterWriter() {
+            return null;
+        }
+
+        @Override
         public Type getType() {
             return VIRTUAL_TYPE;
         }
@@ -648,6 +655,11 @@ public class Mappings {
         }

         @Override
+        public ObjectConverter.Reader<?> findObjectConverterReader() {
+            return null;
+        }
+
+        @Override
         public Type getType() {
             return VIRTUAL_TYPE;
         }
@@ -708,6 +720,17 @@ public class Mappings {
         }

         @Override
+        public ObjectConverter.Writer<?> findObjectConverterWriter() {
+            for (final AccessMode.Reader w : delegates) {
+                final ObjectConverter.Writer<?> objectConverter =
w.findObjectConverterWriter();
+                if (objectConverter != null) {
+                    return objectConverter;
+                }
+            }
+            return null;
+        }
+
+        @Override
         public Type getType() {
             return VIRTUAL_TYPE;
         }
@@ -767,6 +790,17 @@ public class Mappings {
         }

         @Override
+        public ObjectConverter.Reader<?> findObjectConverterReader() {
+            for (final AccessMode.Writer w : delegates) {
+                final ObjectConverter.Reader<?> objectConverter =
w.findObjectConverterReader();
+                if (objectConverter != null) {
+                    return objectConverter;
+                }
+            }
+            return null;
+        }
+
+        @Override
         public Type getType() {
             return VIRTUAL_TYPE;
         }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
index 5869f4d..03ce47e 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/ObjectConverter.java
@@ -28,10 +28,20 @@ import java.lang.reflect.Type;
  * An example would be to convert a custom Project POJO, like Dog.class
  * to it's JSON representation
  *
- * @param <T>
  */
-public interface ObjectConverter<T> extends MapperConverter {
-    void writeJson(T instance, MappingGenerator jsonbGenerator);
+public final class ObjectConverter {
+    private ObjectConverter() {
+        // no-op
+    }

-    T fromJson(JsonObject jsonObject, Type targetType, MappingParser
parser);
+    public interface Writer<T> extends MapperConverter {
+        void writeJson(T instance, MappingGenerator jsonbGenerator);
+    }
+
+    public interface Reader<T> extends MapperConverter {
+        T fromJson(JsonObject jsonObject, Type targetType, MappingParser
parser);
+    }
+
+    public interface Codec<T> extends ObjectConverter.Writer<T>,
ObjectConverter.Reader<T> {
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
index 0e667d4..f47e0d0 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java
@@ -19,6 +19,7 @@
 package org.apache.johnzon.mapper.access;

 import org.apache.johnzon.mapper.Adapter;
+import org.apache.johnzon.mapper.ObjectConverter;

 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
@@ -36,10 +37,12 @@ public interface AccessMode {

     interface Writer extends DecoratedType {
         void write(Object instance, Object value);
+        ObjectConverter.Reader<?> findObjectConverterReader();
     }

     interface Reader extends DecoratedType {
         Object read(Object instance);
+        ObjectConverter.Writer<?> findObjectConverterWriter();
     }

     interface Factory {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
index 37d92cc..0bb6a4f 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAccessMode.java
@@ -21,6 +21,7 @@ package org.apache.johnzon.mapper.access;
 import org.apache.johnzon.mapper.Adapter;
 import org.apache.johnzon.mapper.JohnzonProperty;
 import org.apache.johnzon.mapper.MapperException;
+import org.apache.johnzon.mapper.ObjectConverter;

 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
@@ -149,6 +150,11 @@ public class FieldAccessMode extends BaseAccessMode {
                 throw new MapperException(e);
             }
         }
+
+        @Override
+        public ObjectConverter.Reader<?> findObjectConverterReader() {
+            return null;
+        }
     }

     public static class FieldReader extends FieldDecoratedType  implements
Reader {
@@ -166,6 +172,11 @@ public class FieldAccessMode extends BaseAccessMode {
         }

         @Override
+        public ObjectConverter.Writer<?> findObjectConverterWriter() {
+            return null;
+        }
+
+        @Override
         public Type getType() {
             return type;
         }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
index 7fc224a..0e4d9e7 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
@@ -19,6 +19,7 @@
 package org.apache.johnzon.mapper.access;

 import org.apache.johnzon.mapper.Adapter;
+import org.apache.johnzon.mapper.ObjectConverter;

 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
@@ -122,6 +123,12 @@ public class FieldAndMethodAccessMode extends
BaseAccessMode {
         public Object read(final Object instance) {
             return reader.read(instance);
         }
+
+        @Override
+        public ObjectConverter.Writer<?> findObjectConverterWriter() {
+            final ObjectConverter.Writer<?> objectConverter =
Reader.class.cast(type1).findObjectConverterWriter();
+            return objectConverter == null ?
reader.findObjectConverterWriter() : objectConverter;
+        }
     }

     public static final class CompositeWriter extends
CompositeDecoratedType implements Writer {
@@ -136,5 +143,11 @@ public class FieldAndMethodAccessMode extends
BaseAccessMode {
         public void write(final Object instance, final Object value) {
             writer.write(instance, value);
         }
+
+        @Override
+        public ObjectConverter.Reader<?> findObjectConverterReader() {
+            final ObjectConverter.Reader<?> objectConverter =
Writer.class.cast(type1).findObjectConverterReader();
+            return objectConverter == null ?
writer.findObjectConverterReader() : objectConverter;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
index 894d03e..4309c28 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
@@ -21,6 +21,7 @@ package org.apache.johnzon.mapper.access;
 import org.apache.johnzon.mapper.Adapter;
 import org.apache.johnzon.mapper.JohnzonProperty;
 import org.apache.johnzon.mapper.MapperException;
+import org.apache.johnzon.mapper.ObjectConverter;

 import java.beans.IntrospectionException;
 import java.beans.Introspector;
@@ -153,6 +154,11 @@ public class MethodAccessMode extends BaseAccessMode {
                 throw new MapperException(e);
             }
         }
+
+        @Override
+        public ObjectConverter.Reader<?> findObjectConverterReader() {
+            return null;
+        }
     }

     public static class MethodReader extends MethodDecoratedType
implements Reader {
@@ -168,6 +174,11 @@ public class MethodAccessMode extends BaseAccessMode {
                 throw new MapperException(e);
             }
         }
+
+        @Override
+        public ObjectConverter.Writer<?> findObjectConverterWriter() {
+            return null;
+        }
     }

     private class MethodGetterAsWriter extends MethodReader implements
Writer {
@@ -188,5 +199,10 @@ public class MethodAccessMode extends BaseAccessMode {
                 }
             }
         }
+
+        @Override
+        public ObjectConverter.Reader<?> findObjectConverterReader() {
+            return null;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
index 7f5bac2..52a3eeb 100644
---
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
+++
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperConfigTest.java
@@ -36,14 +36,14 @@ public class MapperConfigTest {
     @Test
     public void testFindObjectConverterConverterForSpecificClass() {

-        ObjectConverter<ClassWithoutSupertypes> theConverter = new
TheConverter<ClassWithoutSupertypes>();
+        ObjectConverter.Codec<ClassWithoutSupertypes> theConverter = new
TheConverter<ClassWithoutSupertypes>();

-        Map<Class<?>, ObjectConverter<?>> converterMap = new
HashMap<Class<?>, ObjectConverter<?>>(1);
+        Map<Class<?>, ObjectConverter.Codec<?>> converterMap = new
HashMap<Class<?>, ObjectConverter.Codec<?>>(1);
         converterMap.put(ClassWithoutSupertypes.class, theConverter);

         MapperConfig config = createConfig(converterMap);

-        ObjectConverter converter =
config.findObjectConverter(ClassWithoutSupertypes.class);
+        ObjectConverter.Reader converter =
config.findObjectConverterReader(ClassWithoutSupertypes.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(theConverter, converter);
     }
@@ -51,11 +51,11 @@ public class MapperConfigTest {
     @Test
     public void testFindObjectConverterConverterForInterface() {

-        ObjectConverter<TheInterface> theConverter = new
TheConverter<TheInterface>();
+        ObjectConverter.Codec<TheInterface> theConverter = new
TheConverter<TheInterface>();

-        MapperConfig config = createConfig(Collections.<Class<?>,
ObjectConverter<?>>singletonMap(TheInterface.class, theConverter));
+        MapperConfig config = createConfig(Collections.<Class<?>,
ObjectConverter.Codec<?>>singletonMap(TheInterface.class, theConverter));

-        ObjectConverter converter =
config.findObjectConverter(ClassForTheInterface.class);
+        ObjectConverter.Writer converter =
config.findObjectConverterWriter(ClassForTheInterface.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(theConverter, converter);
     }
@@ -63,11 +63,11 @@ public class MapperConfigTest {
     @Test
     public void testFindObjectConverterConverterOnlyForSuperclass() {

-        ObjectConverter<ClassForTheInterface> theConverter = new
TheConverter<ClassForTheInterface>();
+        ObjectConverter.Codec<ClassForTheInterface> theConverter = new
TheConverter<ClassForTheInterface>();

-        MapperConfig config = createConfig(Collections.<Class<?>,
ObjectConverter<?>>singletonMap(ClassForTheInterface.class, theConverter));
+        MapperConfig config = createConfig(Collections.<Class<?>,
ObjectConverter.Codec<?>>singletonMap(ClassForTheInterface.class,
theConverter));

-        ObjectConverter converter =
config.findObjectConverter(ExtendingClassForTheInterface.class);
+        ObjectConverter.Reader converter =
config.findObjectConverterReader(ExtendingClassForTheInterface.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(theConverter, converter);
     }
@@ -75,36 +75,40 @@ public class MapperConfigTest {
     @Test
     public void testFindObjectConverterConverterForInterfaceAndClass() {

-        ObjectConverter<TheInterface> interfaceConverter = new
TheConverter<TheInterface>();
-        ObjectConverter<ClassForTheInterface> theConverter = new
TheConverter<ClassForTheInterface>();
+        ObjectConverter.Codec<TheInterface> interfaceConverter = new
TheConverter<TheInterface>();
+        ObjectConverter.Codec<ClassForTheInterface> theConverter = new
TheConverter<ClassForTheInterface>();

-        Map<Class<?>, ObjectConverter<?>> converterMap = new
HashMap<Class<?>, ObjectConverter<?>>(2);
+        Map<Class<?>, ObjectConverter.Codec<?>> converterMap = new
HashMap<Class<?>, ObjectConverter.Codec<?>>(2);
         converterMap.put(TheInterface.class, interfaceConverter);
         converterMap.put(ClassForTheInterface.class, theConverter);

         MapperConfig config = createConfig(converterMap);

-        ObjectConverter converter =
config.findObjectConverter(ClassForTheInterface.class);
-        Assert.assertNotNull(converter);
-        Assert.assertEquals(theConverter, converter);
+        {
+            ObjectConverter.Reader converter =
config.findObjectConverterReader(ClassForTheInterface.class);
+            Assert.assertNotNull(converter);
+            Assert.assertEquals(theConverter, converter);
+        }

-        converter =
config.findObjectConverter(ExtendingClassForTheInterface.class);
-        Assert.assertNotNull(converter);
-        Assert.assertEquals(theConverter, converter);
+        {
+            ObjectConverter.Writer converter =
config.findObjectConverterWriter(ExtendingClassForTheInterface.class);
+            Assert.assertNotNull(converter);
+            Assert.assertEquals(theConverter, converter);
+        }
     }

     @Test
     public void testFindObjectConverterConverterForMoreInterfaces() {

-        ObjectConverter<TheInterface> firstConverter = new
TheConverter<TheInterface>();
-        ObjectConverter<TheSecondInterface> secondConverter = new
TheConverter<TheSecondInterface>();
+        ObjectConverter.Codec<TheInterface> firstConverter = new
TheConverter<TheInterface>();
+        ObjectConverter.Codec<TheSecondInterface> secondConverter = new
TheConverter<TheSecondInterface>();

-        Map<Class<?>, ObjectConverter<?>> converterMap = new
HashMap<Class<?>, ObjectConverter<?>>(2);
+        Map<Class<?>, ObjectConverter.Codec<?>> converterMap = new
HashMap<Class<?>, ObjectConverter.Codec<?>>(2);
         converterMap.put(TheInterface.class, firstConverter);
         converterMap.put(TheSecondInterface.class, secondConverter);
         MapperConfig config = createConfig(converterMap);

-        ObjectConverter converter =
config.findObjectConverter(ClassWithTwoInterfaces.class);
+        ObjectConverter.Writer converter =
config.findObjectConverterWriter(ClassWithTwoInterfaces.class);
         Assert.assertNotNull(converter);

 Assert.assertEquals(converterMap.get(ClassWithTwoInterfaces.class.getInterfaces()[0]),
converter);
     }
@@ -114,40 +118,44 @@ public class MapperConfigTest {

         TheAbstractConverter<ClassForTheInterface> theConverter = new
TheAbstractConverter<ClassForTheInterface>() {};

-        MapperConfig config = createConfig(Collections.<Class<?>,
ObjectConverter<?>>singletonMap(ClassForTheInterface.class, theConverter));
+        MapperConfig config = createConfig(Collections.<Class<?>,
ObjectConverter.Codec<?>>singletonMap(ClassForTheInterface.class,
theConverter));

-        ObjectConverter converter =
config.findObjectConverter(ClassForTheInterface.class);
-        Assert.assertNotNull(converter);
-        Assert.assertEquals(theConverter, converter);
+        {
+            ObjectConverter.Writer converter =
config.findObjectConverterWriter(ClassForTheInterface.class);
+            Assert.assertNotNull(converter);
+            Assert.assertEquals(theConverter, converter);
+        }

-        converter =
config.findObjectConverter(ExtendingClassForTheInterface.class);
-        Assert.assertNotNull(converter);
-        Assert.assertEquals(theConverter, converter);
+        {
+            ObjectConverter.Writer converter =
config.findObjectConverterWriter(ExtendingClassForTheInterface.class);
+            Assert.assertNotNull(converter);
+            Assert.assertEquals(theConverter, converter);
+        }
     }

     @Test
     public void testfindObjectConverterConverterForObject() {
         TheConverter<Object> theConverter = new TheConverter<Object>();

-        MapperConfig config = createConfig(Collections.<Class<?>,
ObjectConverter<?>>singletonMap(Object.class, theConverter));
+        MapperConfig config = createConfig(Collections.<Class<?>,
ObjectConverter.Codec<?>>singletonMap(Object.class, theConverter));

-        ObjectConverter converter =
config.findObjectConverter(ClassForTheInterface.class);
+        ObjectConverter.Reader converter =
config.findObjectConverterReader(ClassForTheInterface.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(theConverter, converter);

-        converter = config.findObjectConverter(TheInterface.class);
+        converter = config.findObjectConverterReader(TheInterface.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(theConverter, converter);

-        converter =
config.findObjectConverter(InterfaceExtendingTwoInterfaces.class);
+        converter =
config.findObjectConverterReader(InterfaceExtendingTwoInterfaces.class);
         Assert.assertNotNull(converter);
         Assert.assertEquals(theConverter, converter);
     }


-    private MapperConfig createConfig(Map<Class<?>, ObjectConverter<?>>
converter) {
+    private MapperConfig createConfig(Map<Class<?>,
ObjectConverter.Codec<?>> converter) {
         return new MapperConfig(new ConcurrentHashMap<AdapterKey,
Adapter<?, ?>>(0),
-                                converter,
+                                Map.class.cast(converter),
Map.class.cast(converter),
                                 -1,
                                 true,
                                 true,
@@ -173,7 +181,7 @@ public class MapperConfigTest {
     private interface InterfaceExtendingTwoInterfaces extends
TheInterface, TheSecondInterface {}


-    private static class TheConverter<T> implements ObjectConverter<T>{
+    private static class TheConverter<T> implements
ObjectConverter.Codec<T>{
         @Override
         public void writeJson(T instance, MappingGenerator jsonbGenerator)
{
             // dummy
@@ -186,7 +194,7 @@ public class MapperConfigTest {
         }
     }

-    private static abstract class TheAbstractConverter<T extends
TheInterface> implements ObjectConverter<T> {
+    private static abstract class TheAbstractConverter<T extends
TheInterface> implements ObjectConverter.Codec<T> {
         @Override
         public void writeJson(T instance, MappingGenerator jsonbGenerator)
{
             // dummy

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
index c14094e..510672d 100644
---
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
+++
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
@@ -348,7 +348,7 @@ public class ObjectConverterWithAnnotationTest {
         TRIATHLON
     }

-    public static class BikeConverter implements ObjectConverter<Bike> {
+    public static class BikeConverter implements
ObjectConverter.Codec<Bike> {

         public static final List<String> MANUFACTURERS =
Arrays.asList("Specialized / S-Works", "Canyon", "Trek", "Scott");


http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
----------------------------------------------------------------------
diff --git
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
index 88b03a8..b003ac2 100644
---
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
+++
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectTypeTest.java
@@ -160,11 +160,11 @@ public class ObjectTypeTest {
     }


-    public static class TestWithTypeConverter implements
ObjectConverter<Dog> {
+    public static class TestWithTypeConverter implements
ObjectConverter.Codec<Dog> {
         @Override
         public void writeJson(Dog instance, MappingGenerator
mappingGenerator) {
             mappingGenerator.getJsonGenerator().write("//javaType",
instance.getClass().getName());
-            mappingGenerator.writeObject(instance);
+            mappingGenerator.writeObject(instance,
mappingGenerator.getJsonGenerator());
         }

         @Override
@@ -287,7 +287,7 @@ public class ObjectTypeTest {
     }


-    public static class DBAccessPoodleConverter implements
ObjectConverter<Poodle> {
+    public static class DBAccessPoodleConverter implements
ObjectConverter.Codec<Poodle> {

         public static final String POODLE_1_NAME = "Poodle1";
         public static final String POODLE_2_NAME = "Poodle2";

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java
----------------------------------------------------------------------
diff --git a/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java
b/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java
index 717cb15..597c88c 100644
--- a/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java
+++ b/jsonb-api/src/main/java/javax/json/bind/JsonbConfig.java
@@ -21,6 +21,8 @@ package javax.json.bind;
 import javax.json.bind.adapter.JsonbAdapter;
 import javax.json.bind.config.PropertyNamingStrategy;
 import javax.json.bind.config.PropertyVisibilityStrategy;
+import javax.json.bind.serializer.JsonbDeserializer;
+import javax.json.bind.serializer.JsonbSerializer;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Locale;
@@ -41,6 +43,8 @@ public class JsonbConfig {
     public static final String BINARY_DATA_STRATEGY =
"jsonb.binary-data-strategy";
     public static final String DATE_FORMAT = "jsonb.date-format";
     public static final String LOCALE = "jsonb.locale";
+    public static final String SERIALIZERS = "jsonb.serializers";
+    public static final String DESERIALIZERS = "jsonb.derializers";

     public final JsonbConfig withDateFormat(final String dateFormat, final
Locale locale) {
         return setProperty(DATE_FORMAT, dateFormat).setProperty(LOCALE,
locale != null ? locale : Locale.getDefault());
@@ -102,4 +106,12 @@ public class JsonbConfig {
     public final JsonbConfig withBinaryDataStrategy(final String
binaryDataStrategy) {
         return setProperty(BINARY_DATA_STRATEGY, binaryDataStrategy);
     }
+
+    public final JsonbConfig withSerializers(final JsonbSerializer...
serializers) {
+        return setProperty(SERIALIZERS, serializers);
+    }
+
+    public final JsonbConfig withDeserializers(final JsonbDeserializer...
deserializers) {
+        return setProperty(DESERIALIZERS, deserializers);
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeDeserializer.java
----------------------------------------------------------------------
diff --git
a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeDeserializer.java
b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeDeserializer.java
new file mode 100644
index 0000000..ad8fba2
--- /dev/null
+++
b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeDeserializer.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.json.bind.annotation;
+
+import javax.json.bind.serializer.JsonbDeserializer;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ANNOTATION_TYPE, FIELD, METHOD})
+public @interface JsonbTypeDeserializer {
+    Class<? extends JsonbDeserializer> value();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeSerializer.java
----------------------------------------------------------------------
diff --git
a/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeSerializer.java
b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeSerializer.java
new file mode 100644
index 0000000..f2efdda
--- /dev/null
+++
b/jsonb-api/src/main/java/javax/json/bind/annotation/JsonbTypeSerializer.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.json.bind.annotation;
+
+import javax.json.bind.serializer.JsonbSerializer;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+
+@JsonbAnnotation
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ANNOTATION_TYPE, FIELD, METHOD})
+public @interface JsonbTypeSerializer {
+    Class<? extends JsonbSerializer> value();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/serializer/DeserializationContext.java
----------------------------------------------------------------------
diff --git
a/jsonb-api/src/main/java/javax/json/bind/serializer/DeserializationContext.java
b/jsonb-api/src/main/java/javax/json/bind/serializer/DeserializationContext.java
new file mode 100644
index 0000000..05952fb
--- /dev/null
+++
b/jsonb-api/src/main/java/javax/json/bind/serializer/DeserializationContext.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.json.bind.serializer;
+
+import javax.json.stream.JsonParser;
+import java.lang.reflect.Type;
+
+public interface DeserializationContext {
+    /**
+     * JsonParser cursor is at KEY_NAME event.
+     */
+    <T> T deserialize(Class<T> clazz, JsonParser parser);
+
+    <T> T deserialize(Type type, JsonParser parser);
+
+    <T> T convertDefault(Class<T> clazz, String value);
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbDeserializer.java
----------------------------------------------------------------------
diff --git
a/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbDeserializer.java
b/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbDeserializer.java
new file mode 100644
index 0000000..1f4de04
--- /dev/null
+++
b/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbDeserializer.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.json.bind.serializer;
+
+import javax.json.stream.JsonParser;
+import java.lang.reflect.Type;
+
+public interface JsonbDeserializer<T> {
+    /**
+     * JsonParser is at START_OBJECT event.
+     */
+    T deserialize(JsonParser parser, DeserializationContext ctx, Type
rtType);
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbSerializer.java
----------------------------------------------------------------------
diff --git
a/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbSerializer.java
b/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbSerializer.java
new file mode 100644
index 0000000..6b487a8
--- /dev/null
+++
b/jsonb-api/src/main/java/javax/json/bind/serializer/JsonbSerializer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.json.bind.serializer;
+
+import javax.json.stream.JsonGenerator;
+
+public interface JsonbSerializer<T> {
+    void serialize(T obj, JsonGenerator generator, SerializationContext
ctx);
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/745668a8/jsonb-api/src/main/java/javax/json/bind/serializer/SerializationContext.java
----------------------------------------------------------------------
diff --git
a/jsonb-api/src/main/java/javax/json/bind/serializer/SerializationContext.java
b/jsonb-api/src/main/java/javax/json/bind/serializer/SerializationContext.java
new file mode 100644
index 0000000..f26cd1c
--- /dev/null
+++
b/jsonb-api/src/main/java/javax/json/bind/serializer/SerializationContext.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package javax.json.bind.serializer;
+
+import javax.json.stream.JsonGenerator;
+
+public interface SerializationContext {
+    <T> void serialize(String key, T object, JsonGenerator generator);
+
+    <T> void serialize(T object, JsonGenerator generator);
+
+    <T> String convertDefault(T obj, JsonGenerator generator);
+}