http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonDeduplicateObjects.java
----------------------------------------------------------------------
diff --git 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonDeduplicateObjects.java
 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonDeduplicateObjects.java
new file mode 100644
index 0000000..cf95596
--- /dev/null
+++ 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonDeduplicateObjects.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.mapper;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark an Object to leverage object deduplication without having
+ * to explicitly enable it in the Mapper or JsonB Builder.
+ *
+ * The feature only gets activated if this annotation is available
+ * on the root object to be serialised/deserialised.
+ *
+ * @see MapperBuilder#setDeduplicateObjects(boolean)
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface JohnzonDeduplicateObjects {
+    boolean value() default true;
+}

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonIgnoreNested.java
----------------------------------------------------------------------
diff --git 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonIgnoreNested.java
 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonIgnoreNested.java
new file mode 100644
index 0000000..f1d16a7
--- /dev/null
+++ 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonIgnoreNested.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.mapper;
+
+import java.lang.annotation.Retention;
+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;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Only used during serialization for now.
+ */
+@Target({ METHOD, FIELD, ANNOTATION_TYPE })
+@Retention(RUNTIME)
+public @interface JohnzonIgnoreNested {
+    /**
+     * @return the array of properties to avoid in the nested type.
+     */
+    String[] properties() default {};
+}

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/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 58aed8b..0dc8a3c 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
@@ -18,6 +18,7 @@
  */
 package org.apache.johnzon.mapper;
 
+import org.apache.johnzon.mapper.internal.JsonPointerTracker;
 import org.apache.johnzon.mapper.reflection.JohnzonCollectionType;
 
 import javax.json.JsonException;
@@ -63,7 +64,7 @@ public class Mapper implements Closeable {
         this.mappings = new Mappings(config);
         this.readerHandler = ReaderHandler.create(readerFactory);
         this.closeables = closeables;
-        this.charset = config.getEncoding() == null ? null : 
config.getEncoding();
+        this.charset = config.getEncoding();
     }
 
 
@@ -84,8 +85,14 @@ public class Mapper implements Closeable {
     }
 
     public <T> void writeArray(final Collection<T> object, final Writer 
stream) {
-        JsonGenerator generator = 
generatorFactory.createGenerator(stream(stream));
-        writeObject(object, generator);
+        final JsonGenerator generator = 
generatorFactory.createGenerator(stream(stream));
+
+        try {
+            boolean dedup = Boolean.TRUE.equals(config.isDeduplicateObjects());
+            writeObject(object, generator, null, dedup ? new 
JsonPointerTracker(null, "/") : null);
+        } finally {
+            generator.close();
+        }
     }
 
     public <T> void writeIterable(final Iterable<T> object, final OutputStream 
stream) {
@@ -93,8 +100,13 @@ public class Mapper implements Closeable {
     }
 
     public <T> void writeIterable(final Iterable<T> object, final Writer 
stream) {
-        JsonGenerator generator = 
generatorFactory.createGenerator(stream(stream));
-        writeObject(object, generator);
+        final JsonGenerator generator = 
generatorFactory.createGenerator(stream(stream));
+        try {
+            boolean dedup = Boolean.TRUE.equals(config.isDeduplicateObjects());
+            writeObject(object, generator, null, dedup ? new 
JsonPointerTracker(null, "/") : null);
+        } finally {
+            generator.close();
+        }
     }
 
     public void writeObject(final Object object, final Writer stream) {
@@ -125,24 +137,12 @@ public class Mapper implements Closeable {
         }
 
         final JsonGenerator generator = 
generatorFactory.createGenerator(stream(stream));
-        writeObject(object, generator);
-    }
-
-    public void writeObject(final Object object, final OutputStream stream) {
-        final JsonGenerator generator = 
generatorFactory.createGenerator(stream(stream), config.getEncoding());
-        writeObject(object, generator);
-    }
-
-    private void writeObject(final Object object, final JsonGenerator 
generator) {
-        MappingGeneratorImpl mappingGenerator = new 
MappingGeneratorImpl(config, generator, mappings);
-
         RuntimeException originalException = null;
         try {
-            mappingGenerator.doWriteObject(object, generator, true);
+            writeObject(object, generator);
         } catch (RuntimeException e) {
             originalException = e;
         } finally {
-
             try {
                 generator.close();
             } catch (JsonException e) {
@@ -154,7 +154,38 @@ public class Mapper implements Closeable {
                 }
             }
         }
+    }
+
 
+    private void writeObject(final Object object, final JsonGenerator 
generator) {
+            writeObject(object, generator, null,
+                    isDeduplicateObjects(object.getClass()) ? new 
JsonPointerTracker(null, "/") : null);
+    }
+
+    private boolean isDeduplicateObjects(Class<?> rootType) {
+        Boolean dedup = config.isDeduplicateObjects();
+        if (dedup == null) {
+            Mappings.ClassMapping classMapping = 
mappings.findOrCreateClassMapping(rootType);
+            if (classMapping != null) {
+                dedup = classMapping.isDeduplicateObjects();
+            }
+        }
+
+        return dedup != null ? dedup : false;
+    }
+
+    public void writeObject(final Object object, final OutputStream stream) {
+        Charset charset = config.getEncoding();
+        if (charset == null) {
+            writeObject(object, new OutputStreamWriter(stream));
+        } else {
+            writeObject(object, new OutputStreamWriter(stream));
+        }
+    }
+
+    private void writeObject(final Object object, final JsonGenerator 
generator, final Collection<String> ignored, JsonPointerTracker jsonPointer) {
+        MappingGeneratorImpl mappingGenerator = new 
MappingGeneratorImpl(config, generator, mappings, jsonPointer != null);
+        mappingGenerator.doWriteObject(object, generator, true, ignored, 
jsonPointer);
     }
 
     public String writeArrayAsString(final Collection<?> instance) {
@@ -181,15 +212,33 @@ public class Mapper implements Closeable {
     }
 
     public <T> T readObject(final Reader stream, final Type clazz) {
-        return mapObject(clazz, readerFactory.createReader(stream(stream)));
+        final JsonReader reader = readerFactory.createReader(stream(stream));
+        try {
+            return mapObject(clazz, reader);
+        } finally {
+            reader.close();
+        }
     }
 
     public <T> T readObject(final InputStream stream, final Type clazz) {
-        return mapObject(clazz, charset == null ? 
readerFactory.createReader(stream(stream)): 
readerFactory.createReader(stream(stream), charset));
+        final JsonReader reader = charset == null ? 
readerFactory.createReader(stream(stream)) : readerFactory.createReader(
+                stream(stream), charset);
+
+        try {
+            return mapObject(clazz, reader);
+        } finally {
+            reader.close();
+        }
     }
 
     public <T> Collection<T> readCollection(final InputStream stream, final 
ParameterizedType genericType) {
-        return mapObject(genericType, charset == null ? 
readerFactory.createReader(stream(stream)): 
readerFactory.createReader(stream(stream), charset));
+        final JsonReader reader = charset == null ? 
readerFactory.createReader(stream(stream)): 
readerFactory.createReader(stream(stream), charset);
+
+        try {
+            return mapObject(genericType, reader);
+        } finally {
+            reader.close();
+        }
     }
 
     public <T> T readJohnzonCollection(final InputStream stream, final 
JohnzonCollectionType<T> genericType) {
@@ -201,27 +250,51 @@ public class Mapper implements Closeable {
     }
 
     public <T> Collection<T> readCollection(final Reader stream, final 
ParameterizedType genericType) {
-        return mapObject(genericType, 
readerFactory.createReader(stream(stream)));
+        final JsonReader reader = readerFactory.createReader(stream(stream));
+
+        try {
+            return mapObject(genericType, reader);
+        } finally {
+            reader.close();
+        }
     }
 
     public <T> T[] readArray(final Reader stream, final Class<T> clazz) {
         final JsonReader reader = readerFactory.createReader(stream(stream));
-        return (T[]) mapArray(clazz, reader);
+
+        try {
+            return (T[]) mapArray(clazz, reader);
+        } finally {
+            reader.close();
+        }
     }
 
     public <T> T readTypedArray(final InputStream stream, final Class<?> 
elementType, final Class<T> arrayType) {
         final JsonReader reader = charset == null ? 
readerFactory.createReader(stream(stream)): 
readerFactory.createReader(stream(stream), charset);
-        return arrayType.cast(mapArray(elementType, reader));
+        try {
+            return arrayType.cast(mapArray(elementType, reader));
+        } finally {
+            reader.close();
+        }
     }
 
     public <T> T readTypedArray(final Reader stream, final Class<?> 
elementType, final Class<T> arrayType) {
         final JsonReader reader = readerFactory.createReader(stream(stream));
-        return arrayType.cast(mapArray(elementType, reader));
+
+        try {
+            return arrayType.cast(mapArray(elementType, reader));
+        } finally {
+            reader.close();
+        }
     }
 
     public <T> T[] readArray(final InputStream stream, final Class<T> clazz) {
         final JsonReader reader = charset == null ? 
readerFactory.createReader(stream(stream)): 
readerFactory.createReader(stream(stream), charset);
-        return (T[]) mapArray(clazz, reader);
+        try {
+            return (T[]) mapArray(clazz, reader);
+        } finally {
+            reader.close();
+        }
     }
 
     private Object mapArray(final Class<?> clazz, final JsonReader reader) {
@@ -230,7 +303,11 @@ public class Mapper implements Closeable {
 
 
     private <T> T mapObject(final Type clazz, final JsonReader reader) {
-        return new MappingParserImpl(config, mappings, 
reader).readObject(clazz);
+        boolean dedup = false;
+        if (clazz instanceof Class) {
+            dedup = isDeduplicateObjects((Class) clazz);
+        }
+        return new MappingParserImpl(config, mappings, reader, 
dedup).readObject(clazz);
     }
 
 
@@ -242,10 +319,6 @@ public class Mapper implements Closeable {
         return !config.isClose() ? noClose(stream) : stream;
     }
 
-    private OutputStream stream(final OutputStream stream) {
-        return !config.isClose() ? noClose(stream) : stream;
-    }
-
     private InputStream stream(final InputStream stream) {
         return !config.isClose() ? noClose(stream) : stream;
     }

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/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 b3e57eb..387f3e6 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
@@ -107,6 +107,7 @@ public class MapperBuilder {
     private int maxSize = -1;
     private int bufferSize = -1;
     private String bufferStrategy;
+    private boolean autoAdjustStringBuffers;
     private Comparator<String> attributeOrder = null;
     private boolean supportConstructors;
     private boolean useGetterForCollections;
@@ -129,6 +130,10 @@ public class MapperBuilder {
     private Map<Class<?>, ObjectConverter.Writer<?>> objectConverterWriters = 
new HashMap<Class<?>, ObjectConverter.Writer<?>>();
     private Map<Class<?>, String[]> ignoredForFields = new HashMap<Class<?>, 
String[]>();
     private boolean primitiveConverters;
+    private boolean failOnUnknownProperties;
+    private SerializeValueFilter serializeValueFilter;
+    private boolean useBigDecimalForFloats;
+    private Boolean deduplicateObjects = null;
 
     public Mapper build() {
         if (readerFactory == null || generatorFactory == null) {
@@ -155,6 +160,9 @@ public class MapperBuilder {
             if (bufferSize > 0) {
                 config.put(JsonParserFactoryImpl.BUFFER_LENGTH, bufferSize);
             }
+            if (autoAdjustStringBuffers) {
+                config.put("org.apache.johnzon.auto-adjust-buffer", true);
+            }
             if (readerFactory == null) {
                 readerFactory = provider.createReaderFactory(config);
             }
@@ -215,10 +223,16 @@ public class MapperBuilder {
                         version, close,
                         skipNull, skipEmptyArray,
                         treatByteArrayAsBase64, treatByteArrayAsBase64URL, 
readAttributeBeforeWrite,
-                        accessMode, encoding, attributeOrder, 
enforceQuoteString),
+                        accessMode, encoding, attributeOrder, 
enforceQuoteString, failOnUnknownProperties,
+                        serializeValueFilter, useBigDecimalForFloats, 
deduplicateObjects),
                 closeables);
     }
 
+    public MapperBuilder setFailOnUnknownProperties(final boolean 
failOnUnknownProperties) {
+        this.failOnUnknownProperties = failOnUnknownProperties;
+        return this;
+    }
+
     public MapperBuilder addCloseable(final Closeable closeable) {
         closeables.add(closeable);
         return this;
@@ -389,4 +403,56 @@ public class MapperBuilder {
         this.primitiveConverters = val;
         return this;
     }
+
+    public MapperBuilder setSerializeValueFilter(final SerializeValueFilter 
serializeValueFilter) {
+        this.serializeValueFilter = serializeValueFilter;
+        return this;
+    }
+
+    public MapperBuilder setUseBigDecimalForFloats(final boolean 
useBigDecimalForFloats) {
+        this.useBigDecimalForFloats = useBigDecimalForFloats;
+        return this;
+    }
+
+    public MapperBuilder setAutoAdjustStringBuffers(final boolean 
autoAdjustStringBuffers) {
+        this.autoAdjustStringBuffers = autoAdjustStringBuffers;
+        return this;
+    }
+
+    /**
+     * If any non-primitive Java Object gets serialised more than just one 
time,
+     * then we write a JsonPointer to the first occurrence instead.
+     *
+     * This will effectively also avoid endless loops in data with cycles!
+     *
+     * An example: Assume you have a Person with a name 'Sarah' and her 
daughter,
+     * a Person with the name 'Clemens' both stored in a JSON array.
+     * Given the Java Code:
+     * <pre>
+     * Person sarah = new Person("Sarah");
+     * Person clemens = new Person("Clemens");
+     * clemens.setMother(sarah);
+     * Person[] family = new Person[]{sarah, clemens};
+     * </pre>
+     * Transformed to JSON this will now look like the following:
+     * <pre>
+     * [{"name":"Sarah"},{"name":"Clemens","mother":"/0"}]
+     * </pre>
+     * That means instead of serialising 'mother' as full object we will
+     * now only store a JsonPointer to the Person 'Sarah'.
+     *
+     * When deserialised back Johnzon will automatically de-reference the 
JsonPointer
+     * back to the correct instance.
+     *
+     * Possible values:
+     * <ul>
+     *     <li>{@code true}: deduplicate objects</li>
+     *     <li>{@code false}: do <b>not</b> deduplicate objects</li>
+     *     <li>{@code null}: dedupliate based on the {@link 
JohnzonDeduplicateObjects} annotation. This is the default</li>
+     * </ul>
+     */
+    public MapperBuilder setDeduplicateObjects(Boolean deduplicateObjects) {
+        this.deduplicateObjects = deduplicateObjects;
+        return this;
+    }
 }

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/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 efb38f6..3cbb97e 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
@@ -63,6 +63,10 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig 
implements Cloneable {
     private final Map<Class<?>, ObjectConverter.Reader<?>> 
objectConverterReaders;
     private final Comparator<String> attributeOrder;
     private final boolean enforceQuoteString;
+    private final boolean failOnUnknown;
+    private final SerializeValueFilter serializeValueFilter;
+    private final boolean useBigDecimalForFloats;
+    private final Boolean deduplicateObjects;
 
     private final Map<Class<?>, ObjectConverter.Writer<?>> 
objectConverterWriterCache;
     private final Map<Class<?>, ObjectConverter.Reader<?>> 
objectConverterReaderCache;
@@ -78,7 +82,10 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig 
implements Cloneable {
                         final boolean readAttributeBeforeWrite,
                         final AccessMode accessMode, final Charset encoding,
                         final Comparator<String> attributeOrder,
-                        final boolean enforceQuoteString) {
+                        final boolean enforceQuoteString, final boolean 
failOnUnknown,
+                        final SerializeValueFilter serializeValueFilter,
+                        final boolean useBigDecimalForFloats,
+                        final Boolean deduplicateObjects) {
     //CHECKSTYLE:ON
         this.objectConverterWriters = objectConverterWriters;
         this.objectConverterReaders = objectConverterReaders;
@@ -94,9 +101,24 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig 
implements Cloneable {
         this.adapters = adapters;
         this.attributeOrder = attributeOrder;
         this.enforceQuoteString = enforceQuoteString;
+        this.failOnUnknown = failOnUnknown;
+
+        this.serializeValueFilter = serializeValueFilter != null ? 
serializeValueFilter : new SerializeValueFilter() {
+            @Override
+            public boolean shouldIgnore(String name, Object value) {
+                return false;
+            }
+        };
 
         this.objectConverterWriterCache = new HashMap<Class<?>, 
ObjectConverter.Writer<?>>(objectConverterWriters.size());
         this.objectConverterReaderCache = new HashMap<Class<?>, 
ObjectConverter.Reader<?>>(objectConverterReaders.size());
+        this.useBigDecimalForFloats = useBigDecimalForFloats;
+        this.deduplicateObjects = deduplicateObjects;
+    }
+
+
+    public SerializeValueFilter getSerializeValueFilter() {
+        return serializeValueFilter;
     }
 
     public Adapter findAdapter(final Type aClass) {
@@ -104,6 +126,12 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig 
implements Cloneable {
         if (converter != null) {
             return converter;
         }
+        /* could be an option but doesnt fit well our old converters
+        final Adapter<?, ?> reverseConverter = adapters.get(new 
AdapterKey(String.class, aClass));
+        if (reverseConverter != null) {
+            return new ReversedAdapter<>(reverseConverter);
+        }
+        */
         if (Class.class.isInstance(aClass)) {
             final Class<?> clazz = Class.class.cast(aClass);
             if (clazz.isEnum()) {
@@ -220,6 +248,10 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig 
implements Cloneable {
         return converter;
     }
 
+    public boolean isFailOnUnknown() {
+        return failOnUnknown;
+    }
+
     public int getVersion() {
         return version;
     }
@@ -275,4 +307,12 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig 
implements Cloneable {
     public boolean isEnforceQuoteString() {
         return enforceQuoteString;
     }
+
+    public boolean isUseBigDecimalForFloats() {
+        return useBigDecimalForFloats;
+    }
+
+    public Boolean isDeduplicateObjects() {
+        return deduplicateObjects;
+    }
 }

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/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 38b5315..827404c 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
@@ -19,6 +19,7 @@
 package org.apache.johnzon.mapper;
 
 import org.apache.johnzon.mapper.internal.AdapterKey;
+import org.apache.johnzon.mapper.internal.JsonPointerTracker;
 
 import javax.json.JsonValue;
 import javax.json.stream.JsonGenerator;
@@ -28,18 +29,27 @@ import java.lang.reflect.InvocationTargetException;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 
 public class MappingGeneratorImpl implements MappingGenerator {
     private final MapperConfig config;
     private final JsonGenerator generator;
     private final Mappings mappings;
+    
+    private final Boolean isDeduplicateObjects;
+    private Map<Object, String> jsonPointers;
 
 
-    MappingGeneratorImpl(MapperConfig config, JsonGenerator jsonGenerator, 
final Mappings mappings) {
+    MappingGeneratorImpl(MapperConfig config, JsonGenerator jsonGenerator, 
final Mappings mappings, Boolean isDeduplicateObjects) {
         this.config = config;
         this.generator = jsonGenerator;
         this.mappings = mappings;
+
+        this.isDeduplicateObjects = isDeduplicateObjects;
+
+        this.jsonPointers = isDeduplicateObjects ?  new HashMap<Object, 
String>() : Collections.<Object, String>emptyMap();
     }
 
     @Override
@@ -54,12 +64,13 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
         } else if (object instanceof JsonValue) {
             generator.write((JsonValue) object);
         } else {
-            doWriteObject(object, generator, false);
+            doWriteObject(object, generator, false, null, isDeduplicateObjects 
? new JsonPointerTracker(null, "/") : null);
         }
         return this;
     }
 
-    public void doWriteObject(Object object, JsonGenerator generator, boolean 
writeBody) {
+    public void doWriteObject(Object object, JsonGenerator generator, boolean 
writeBody, final Collection<String> ignoredProperties, JsonPointerTracker 
jsonPointer) {
+
         try {
             if (object instanceof Map) {
                 if (writeBody) {
@@ -85,7 +96,7 @@ public class MappingGeneratorImpl implements MappingGenerator 
{
             }
 
             if (object instanceof Iterable) {
-                doWriteIterable((Iterable) object);
+                doWriteIterable((Iterable) object, ignoredProperties, 
jsonPointer);
                 return;
             }
 
@@ -97,7 +108,7 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
             if (writeBody && objectConverter != null) {
                 objectConverter.writeJson(object, this);
             } else {
-                doWriteObjectBody(object);
+                doWriteObjectBody(object, ignoredProperties, jsonPointer);
             }
 
             if (writeBody) {
@@ -125,14 +136,9 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
             }
 
             final Class<?> valueClass = value.getClass();
-            final boolean primitive = Mappings.isPrimitive(valueClass);
-            final boolean clazz = mappings.getClassMapping(valueClass) != null;
-            final boolean array = clazz || primitive ? false : 
valueClass.isArray();
-            final boolean collection = clazz || primitive || array ? false : 
Collection.class.isAssignableFrom(valueClass);
-            final boolean map = clazz || primitive || array || collection ? 
false : Map.class.isAssignableFrom(valueClass);
-            writeValue(valueClass,
-                    primitive, array, collection, map, itemConverter,
-                    key == null ? "null" : key.toString(), value, null);
+            writeValue(valueClass, true,
+                    false, false, false, false, itemConverter,
+                    key == null ? "null" : key.toString(), value, null, null, 
null);
         }
         return generator;
     }
@@ -224,7 +230,13 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
     }
 
 
-    private void doWriteObjectBody(final Object object) throws 
IllegalAccessException, InvocationTargetException {
+    private void doWriteObjectBody(final Object object, final 
Collection<String> ignored, JsonPointerTracker jsonPointer)
+            throws IllegalAccessException, InvocationTargetException {
+
+        if (jsonPointer != null) {
+            jsonPointers.put(object, jsonPointer.toString());
+        }
+
         final Class<?> objectClass = object.getClass();
         final Mappings.ClassMapping classMapping = 
mappings.findOrCreateClassMapping(objectClass);
         if (classMapping == null) {
@@ -236,12 +248,15 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
             return;
         }
         if (classMapping.adapter != null) {
-            doWriteObjectBody(classMapping.adapter.to(object));
+            doWriteObjectBody(classMapping.adapter.to(object), ignored, 
jsonPointer);
             return;
         }
 
         for (final Map.Entry<String, Mappings.Getter> getterEntry : 
classMapping.getters.entrySet()) {
             final Mappings.Getter getter = getterEntry.getValue();
+            if (ignored != null && ignored.contains(getterEntry.getKey())) {
+                continue;
+            }
             if (getter.version >= 0 && config.getVersion() >= getter.version) {
                 continue;
             }
@@ -263,12 +278,24 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
 
             final Object val = getter.converter == null ? value : 
getter.converter.from(value);
 
-            writeValue(val.getClass(),
-                    getter.primitive, getter.array,
-                    getter.collection, getter.map,
-                    getter.itemConverter,
-                    getterEntry.getKey(),
-                    val, getter.objectConverter);
+            String valJsonPointer = jsonPointers.get(val);
+            if (valJsonPointer != null) {
+                // write the JsonPointer instead
+                generator.write(getterEntry.getKey(), valJsonPointer);
+            } else {
+                writeValue(val.getClass(),
+                        getter.dynamic,
+                        getter.primitive,
+                        getter.array,
+                        getter.collection,
+                        getter.map,
+                        getter.itemConverter,
+                        getterEntry.getKey(),
+                        val,
+                        getter.objectConverter,
+                        getter.ignoreNested,
+                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, getterEntry.getKey()) : null);
+            }
         }
 
         // @JohnzonAny doesn't respect comparator since it is a map and not 
purely in the model we append it after and
@@ -281,13 +308,21 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
         }
     }
 
-    private void writeValue(final Class<?> type,
+    //CHECKSTYLE:OFF
+    private void writeValue(final Class<?> type, final boolean dynamic,
                             final boolean primitive, final boolean array,
                             final boolean collection, final boolean map,
                             final Adapter itemConverter,
                             final String key, final Object value,
-                            final ObjectConverter.Writer objectConverter) 
throws InvocationTargetException, IllegalAccessException {
-        if (array) {
+                            final ObjectConverter.Writer objectConverter,
+                            final Collection<String> ignoredProperties,
+                            final JsonPointerTracker jsonPointer)
+            throws InvocationTargetException, IllegalAccessException {
+        //CHECKSTYLE:ON
+        if (config.getSerializeValueFilter().shouldIgnore(key, value)) {
+            return;
+        }
+        if (array || (dynamic && type.isArray())) {
             final int length = Array.getLength(value);
             if (length == 0 && config.isSkipEmptyArray()) {
                 return;
@@ -306,25 +341,46 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
             generator.writeStartArray(key);
             for (int i = 0; i < length; i++) {
                 final Object o = Array.get(value, i);
-                writeItem(itemConverter != null ? itemConverter.from(o) : o);
+                String valJsonPointer = jsonPointers.get(o);
+                if (valJsonPointer != null) {
+                    writePrimitives(valJsonPointer);
+                } else {
+                    writeItem(itemConverter != null ? itemConverter.from(o) : 
o, ignoredProperties, isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null);
+                }
             }
             generator.writeEnd();
-            return;
-        } else if (collection) {
+        } else if (collection || (dynamic && 
Collection.class.isAssignableFrom(type))) {
             generator.writeStartArray(key);
+            int i = 0;
             for (final Object o : Collection.class.cast(value)) {
-                writeItem(itemConverter != null ? itemConverter.from(o) : o);
+                String valJsonPointer = jsonPointers.get(o);
+                if (valJsonPointer != null) {
+                    // write JsonPointer instead of the original object
+                    writePrimitives(valJsonPointer);
+                } else {
+                    ObjectConverter.Writer objectConverterToUse = 
objectConverter;
+                    if (o != null && objectConverterToUse == null) {
+                        objectConverterToUse = 
config.findObjectConverterWriter(o.getClass());
+                    }
+
+                    if (objectConverterToUse != null) {
+                        generator.writeStartObject();
+                        objectConverterToUse.writeJson(o, this);
+                        generator.writeEnd();
+                    } else {
+                        writeItem(itemConverter != null ? 
itemConverter.from(o) : o, ignoredProperties,
+                                isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null);
+                    }
+                }
+                i++;
             }
             generator.writeEnd();
-            return;
-        } else if (map) {
+        } else if (map || (dynamic && Map.class.isAssignableFrom(type))) {
             generator.writeStartObject(key);
             writeMapBody((Map<?, ?>) value, itemConverter);
             generator.writeEnd();
-            return;
-        } else if (primitive) {
+        } else if (primitive || (dynamic && Mappings.isPrimitive(type))) {
             writePrimitives(key, type, value);
-            return;
         } else {
             final Adapter converter = config.findAdapter(type);
             if (converter != null) {
@@ -332,10 +388,9 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
                 if (writePrimitives(key, adapted.getClass(), adapted)) {
                     return;
                 }
-                writeValue(String.class, true, false, false, false, null, key, 
adapted, null);
+                writeValue(String.class, true, true, false, false, false, 
null, key, adapted, null, ignoredProperties, jsonPointer);
                 return;
             } else {
-
                 ObjectConverter.Writer objectConverterToUse = objectConverter;
                 if (objectConverterToUse == null) {
                     objectConverterToUse = 
config.findObjectConverterWriter(type);
@@ -352,16 +407,18 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
                 return;
             }
             generator.writeStartObject(key);
-            doWriteObjectBody(value);
+            doWriteObjectBody(value, ignoredProperties, jsonPointer);
             generator.writeEnd();
         }
     }
 
-    private void writeItem(final Object o) {
-        if (!writePrimitives(o)) {
+    private void writeItem(final Object o, final Collection<String> 
ignoredProperties, JsonPointerTracker jsonPointer) {
+        if (o == null) {
+            generator.writeNull();
+        } else if (!writePrimitives(o)) {
             if (Collection.class.isInstance(o)) {
-                doWriteIterable(Collection.class.cast(o));
-            } else if (o != null && o.getClass().isArray()) {
+                doWriteIterable(Collection.class.cast(o), ignoredProperties, 
jsonPointer);
+            } else if (o.getClass().isArray()) {
                 final int length = Array.getLength(o);
                 if (length > 0 || !config.isSkipEmptyArray()) {
                     generator.writeStartArray();
@@ -370,24 +427,29 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
                         if (t == null) {
                             generator.writeNull();
                         } else {
-                            writeItem(t);
+                            writeItem(t, ignoredProperties, 
isDeduplicateObjects ? new JsonPointerTracker(jsonPointer, i) : null);
                         }
                     }
                     generator.writeEnd();
                 }
-            } else if (o == null) {
-                generator.writeNull();
             } else {
-                doWriteObject(o, generator, true);
+                String valJsonPointer = jsonPointers.get(o);
+                if (valJsonPointer != null) {
+                    // write the JsonPointer instead
+                    generator.write(valJsonPointer);
+                } else {
+                    doWriteObject(o, generator, true, ignoredProperties, 
jsonPointer);
+                }
             }
         }
     }
 
-    private <T> void doWriteIterable(final Iterable<T> object) {
+    private <T> void doWriteIterable(final Iterable<T> object, final 
Collection<String> ignoredProperties, JsonPointerTracker jsonPointer) {
         if (object == null) {
             generator.writeStartArray().writeEnd();
         } else {
             generator.writeStartArray();
+            int i = 0;
             for (final T t : object) {
                 if (JsonValue.class.isInstance(t)) {
                     generator.write(JsonValue.class.cast(t));
@@ -395,9 +457,10 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
                     if (t == null) {
                         generator.writeNull();
                     } else {
-                        writeItem(t);
+                        writeItem(t, ignoredProperties, isDeduplicateObjects ? 
new JsonPointerTracker(jsonPointer, i) : null);
                     }
                 }
+                i++;
             }
             generator.writeEnd();
         }

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/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 e731b8f..a15fd2a 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
@@ -18,13 +18,13 @@
  */
 package org.apache.johnzon.mapper;
 
-import org.apache.johnzon.core.JsonLongImpl;
 import org.apache.johnzon.core.JsonReaderImpl;
 import org.apache.johnzon.mapper.access.AccessMode;
 import org.apache.johnzon.mapper.converter.CharacterConverter;
 import org.apache.johnzon.mapper.converter.EnumConverter;
 import org.apache.johnzon.mapper.internal.AdapterKey;
 import org.apache.johnzon.mapper.internal.ConverterAdapter;
+import org.apache.johnzon.mapper.internal.JsonPointerTracker;
 import org.apache.johnzon.mapper.reflection.JohnzonParameterizedType;
 
 import javax.json.JsonArray;
@@ -35,6 +35,7 @@ import javax.json.JsonString;
 import javax.json.JsonStructure;
 import javax.json.JsonValue;
 import javax.xml.bind.DatatypeConverter;
+
 import java.lang.reflect.Array;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -46,6 +47,7 @@ import java.math.BigInteger;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Deque;
 import java.util.EnumMap;
 import java.util.EnumSet;
@@ -79,7 +81,6 @@ import static javax.json.JsonValue.ValueType.TRUE;
  */
 public class MappingParserImpl implements MappingParser {
 
-    private static final Adapter<Object, String> FALLBACK_CONVERTER = new 
ConverterAdapter<Object>(new FallbackConverter());
     private static final JohnzonParameterizedType ANY_LIST = new 
JohnzonParameterizedType(List.class, Object.class);
     private static final CharacterConverter CHARACTER_CONVERTER = new 
CharacterConverter(); // this one is particular, share the logic
 
@@ -88,18 +89,34 @@ public class MappingParserImpl implements MappingParser {
 
     private final MapperConfig config;
     private final Mappings mappings;
+    private final boolean isDeduplicateObjects;
 
     private final JsonReader jsonReader;
 
+    /**
+     * Used for de-referencing JsonPointers during deserialisation.
+     * key: JsonPointer
+     * value: already deserialised Object
+     */
+    private Map<String, Object> jsonPointers;
 
 
-    public MappingParserImpl(MapperConfig config, Mappings mappings, 
JsonReader jsonReader) {
+    public MappingParserImpl(MapperConfig config, Mappings mappings, 
JsonReader jsonReader, boolean isDeduplicateObjects) {
         this.config = config;
         this.mappings = mappings;
 
         this.jsonReader = jsonReader;
 
         reverseAdaptersRegistry = new ConcurrentHashMap<Adapter<?, ?>, 
AdapterKey>(config.getAdapters().size());
+
+
+        this.isDeduplicateObjects = isDeduplicateObjects;
+
+        if (isDeduplicateObjects) {
+            jsonPointers = new HashMap<String, Object>();
+        } else {
+            jsonPointers = Collections.emptyMap();
+        }
     }
 
 
@@ -130,7 +147,7 @@ public class MappingParserImpl implements MappingParser {
             return (T) jsonValue;
         }
         if (JsonObject.class.isInstance(jsonValue)) {
-            return (T) buildObject(targetType, 
JsonObject.class.cast(jsonValue), applyObjectConverter);
+            return (T) buildObject(targetType, 
JsonObject.class.cast(jsonValue), applyObjectConverter, isDeduplicateObjects ? 
new JsonPointerTracker(null, "/") : null);
         }
         if (JsonString.class.isInstance(jsonValue) && (targetType == 
String.class || targetType == Object.class)) {
             return (T) JsonString.class.cast(jsonValue).getString();
@@ -158,19 +175,25 @@ public class MappingParserImpl implements MappingParser {
             JsonArray jsonArray = (JsonArray) jsonValue;
 
             if (Class.class.isInstance(targetType) && ((Class) 
targetType).isArray()) {
-                return (T) buildArrayWithComponentType(jsonArray, ((Class) 
targetType).getComponentType(), null);
+                final Class componentType = ((Class) 
targetType).getComponentType();
+                return (T) buildArrayWithComponentType(jsonArray, 
componentType, config.findAdapter(componentType),
+                        isDeduplicateObjects ? new JsonPointerTracker(null, 
"/") : null, Object.class);
             }
             if (ParameterizedType.class.isInstance(targetType)) {
 
-                final Mappings.CollectionMapping mapping = 
mappings.findCollectionMapping((ParameterizedType) targetType);
+                final ParameterizedType pt = (ParameterizedType) targetType;
+                final Mappings.CollectionMapping mapping = 
mappings.findCollectionMapping(pt, Object.class);
                 if (mapping == null) {
                     throw new UnsupportedOperationException("type " + 
targetType + " not supported");
                 }
 
-                return (T) mapCollection(mapping, jsonArray, null);
+                final Type arg = pt.getActualTypeArguments()[0];
+                return (T) mapCollection(mapping, jsonArray, 
Class.class.isInstance(arg) ? config.findAdapter(Class.class.cast(arg)) : null,
+                        null, isDeduplicateObjects ? new 
JsonPointerTracker(null, "/") : null, Object.class);
             }
             if (Object.class == targetType) {
-                return (T) new 
ArrayList(asList(Object[].class.cast(buildArrayWithComponentType(jsonArray, 
Object.class, null))));
+                return (T) new 
ArrayList(asList(Object[].class.cast(buildArrayWithComponentType(jsonArray, 
Object.class, null,
+                        isDeduplicateObjects ? new JsonPointerTracker(null, 
"/") : null, Object.class))));
             }
         }
         if (JsonValue.NULL.equals(jsonValue)) {
@@ -186,13 +209,13 @@ public class MappingParserImpl implements MappingParser {
     }
 
 
-    private Object buildObject(final Type inType, final JsonObject object, 
final boolean applyObjectConverter) {
+    private Object buildObject(final Type inType, final JsonObject object, 
final boolean applyObjectConverter, JsonPointerTracker jsonPointer) {
         Type type = inType;
         if (inType == Object.class) {
             type = new JohnzonParameterizedType(Map.class, String.class, 
Object.class);
         }
 
-        if (applyObjectConverter && !(type instanceof 
JohnzonParameterizedType)) {
+        if (applyObjectConverter && !(type instanceof ParameterizedType)) {
 
             if (!(type instanceof Class)) {
                 throw new MapperException("ObjectConverters are only supported 
for Classes not Types");
@@ -217,7 +240,7 @@ public class MappingParserImpl implements MappingParser {
                     if (LinkedHashMap.class == raw) {
                         map = new LinkedHashMap();
                     } else if (SortedMap.class.isAssignableFrom(raw) || 
NavigableMap.class == raw || TreeMap.class == raw) {
-                        map = new TreeMap();
+                        map = config.getAttributeOrder() == null ? new 
TreeMap() : new TreeMap(config.getAttributeOrder());
                     } else if (ConcurrentMap.class.isAssignableFrom(raw)) {
                         map = new ConcurrentHashMap(object.size());
                     } else if (EnumMap.class.isAssignableFrom(raw)) {
@@ -241,22 +264,11 @@ public class MappingParserImpl implements MappingParser {
                         for (final Map.Entry<String, JsonValue> value : 
object.entrySet()) {
                             final JsonValue jsonValue = value.getValue();
                             if (JsonNumber.class.isInstance(jsonValue) && any) 
{
-                                final JsonNumber number = 
JsonNumber.class.cast(jsonValue);
-                                if (JsonLongImpl.class.isInstance(number)) {
-                                    final int integer = number.intValue();
-                                    final long asLong = number.longValue();
-                                    if (integer == asLong) {
-                                        map.put(value.getKey(), integer);
-                                    } else {
-                                        map.put(value.getKey(), asLong);
-                                    }
-                                } else {
-                                    map.put(value.getKey(), 
!number.isIntegral() ? number.bigDecimalValue() : number.intValue());
-                                }
+                                map.put(value.getKey(), 
toNumberValue(JsonNumber.class.cast(jsonValue)));
                             } else if (JsonString.class.isInstance(jsonValue) 
&& any) {
                                 map.put(value.getKey(), 
JsonString.class.cast(jsonValue).getString());
                             } else {
-                                map.put(convertTo(keyType, value.getKey()), 
toObject(null, jsonValue, fieldArgTypes[1], null));
+                                map.put(convertTo(keyType, value.getKey()), 
toObject(null, jsonValue, fieldArgTypes[1], null, jsonPointer, Object.class));
                             }
                         }
                         return map;
@@ -265,7 +277,7 @@ public class MappingParserImpl implements MappingParser {
             } else if (Map.class == type || HashMap.class == type || 
LinkedHashMap.class == type) {
                 final LinkedHashMap<String, Object> map = new 
LinkedHashMap<String, Object>();
                 for (final Map.Entry<String, JsonValue> value : 
object.entrySet()) {
-                    map.put(value.getKey(), toObject(null, value.getValue(), 
Object.class, null));
+                    map.put(value.getKey(), toObject(null, value.getValue(), 
Object.class, null, jsonPointer, Object.class));
                 }
                 return map;
             }
@@ -287,8 +299,25 @@ public class MappingParserImpl implements MappingParser {
             throw new MapperException(classMapping.clazz + " not 
instantiable");
         }
 
-        final Object t = classMapping.factory.getParameterTypes().length == 0 ?
-                classMapping.factory.create(null) : 
classMapping.factory.create(createParameters(classMapping, object));
+        if (config.isFailOnUnknown()) {
+            if (!classMapping.setters.keySet().containsAll(object.keySet())) {
+                throw new MapperException("(fail on unknown properties): " + 
new HashSet<String>(object.keySet()) {{
+                    removeAll(classMapping.setters.keySet());
+                }});
+            }
+        }
+
+        Object t;
+        if (classMapping.factory.getParameterTypes().length == 0) {
+            t = classMapping.factory.create(null);
+        } else {
+            t = classMapping.factory.create(createParameters(classMapping, 
object, jsonPointer));
+        }
+        // store the new object under it's jsonPointer in case it gets 
referenced later
+        if (isDeduplicateObjects) {
+            jsonPointers.put(jsonPointer.toString(), t);
+        }
+
         for (final Map.Entry<String, Mappings.Setter> setter : 
classMapping.setters.entrySet()) {
             final JsonValue jsonValue = object.get(setter.getKey());
             final Mappings.Setter value = setter.getValue();
@@ -315,7 +344,8 @@ public class MappingParserImpl implements MappingParser {
                         }
                     }
                 }
-                final Object convertedValue = toValue(existingInstance, 
jsonValue, value.converter, value.itemConverter, value.paramType, 
value.objectConverter);
+                final Object convertedValue = toValue(existingInstance, 
jsonValue, value.converter, value.itemConverter, value.paramType, 
value.objectConverter,
+                        new JsonPointerTracker(jsonPointer, setter.getKey()), 
inType);
                 if (convertedValue != null) {
                     setterMethod.write(t, convertedValue);
                 }
@@ -326,7 +356,8 @@ public class MappingParserImpl implements MappingParser {
                 final String key = entry.getKey();
                 if (!classMapping.setters.containsKey(key)) {
                     try {
-                        classMapping.anySetter.invoke(t, key, toValue(null, 
entry.getValue(), null, null, Object.class, null));
+                        classMapping.anySetter.invoke(t, key, toValue(null, 
entry.getValue(), null, null, Object.class, null,
+                                isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, entry.getKey()) : null, type));
                     } catch (final IllegalAccessException e) {
                         throw new IllegalStateException(e);
                     } catch (final InvocationTargetException e) {
@@ -339,7 +370,25 @@ public class MappingParserImpl implements MappingParser {
         return t;
     }
 
-    private Object convertTo(final Adapter converter, final JsonValue 
jsonValue) {
+    private Number toNumberValue(JsonNumber jsonNumber) {
+        if (jsonNumber.isIntegral()) {
+            final int intValue = jsonNumber.intValue();
+            final long longValue = jsonNumber.longValue();
+            if (intValue == longValue) {
+                return intValue;
+            } else {
+                return longValue;
+            }
+        } else {
+            if (config.isUseBigDecimalForFloats()) {
+                return jsonNumber.bigDecimalValue();
+            } else {
+                return jsonNumber.doubleValue();
+            }
+        }
+    }
+
+    private Object convertTo(final Adapter converter, final JsonValue 
jsonValue, JsonPointerTracker jsonPointer) {
         if (jsonValue.getValueType() == JsonValue.ValueType.OBJECT) {
 
             //X TODO maybe we can put this into MapperConfig?
@@ -350,7 +399,7 @@ public class MappingParserImpl implements MappingParser {
             final Object param;
             try {
                 Type to = adapterKey.getTo();
-                param = buildObject(to, JsonObject.class.cast(jsonValue), to 
instanceof Class);
+                param = buildObject(to, JsonObject.class.cast(jsonValue), to 
instanceof Class, jsonPointer);
             } catch (final Exception e) {
                 throw new MapperException(e);
             }
@@ -421,7 +470,8 @@ public class MappingParserImpl implements MappingParser {
 
 
     private Object toObject(final Object baseInstance, final JsonValue 
jsonValue,
-                            final Type type, final Adapter itemConverter) {
+                            final Type type, final Adapter itemConverter, 
final JsonPointerTracker jsonPointer,
+                            final Type rootType) {
         if (jsonValue == null || JsonValue.NULL.equals(jsonValue)) {
             return null;
         }
@@ -436,7 +486,10 @@ public class MappingParserImpl implements MappingParser {
             throw new MapperException("Unable to parse " + jsonValue + " to 
boolean");
         }
 
-        if(config.isTreatByteArrayAsBase64() && jsonValue.getValueType() == 
JsonValue.ValueType.STRING && (type == byte[].class /*|| type == 
Byte[].class*/)) {
+        if (config.isTreatByteArrayAsBase64() && jsonValue.getValueType() == 
JsonValue.ValueType.STRING && (type == byte[].class /*|| type == 
Byte[].class*/)) {
+            return 
DatatypeConverter.parseBase64Binary(((JsonString)jsonValue).getString());
+        }
+        if (config.isTreatByteArrayAsBase64URL() && jsonValue.getValueType() 
== JsonValue.ValueType.STRING && (type == byte[].class /*|| type == 
Byte[].class*/)) {
             return 
DatatypeConverter.parseBase64Binary(((JsonString)jsonValue).getString());
         }
 
@@ -448,11 +501,7 @@ public class MappingParserImpl implements MappingParser {
                 return false;
             }
             if (JsonNumber.class.isInstance(jsonValue)) {
-                final JsonNumber jsonNumber = JsonNumber.class.cast(jsonValue);
-                if(jsonNumber.isIntegral()) {
-                    return jsonNumber.intValue();
-                }
-                return jsonNumber.doubleValue();
+                return toNumberValue(JsonNumber.class.cast(jsonValue));
             }
         }
 
@@ -468,13 +517,14 @@ public class MappingParserImpl implements MappingParser {
             final Object object = buildObject(
                     baseInstance != null ? baseInstance.getClass() : (
                             typedAdapter ? 
TypeAwareAdapter.class.cast(itemConverter).getTo() : type),
-                    JsonObject.class.cast(jsonValue), type instanceof Class);
+                    JsonObject.class.cast(jsonValue), type instanceof Class,
+                    jsonPointer);
             return typedAdapter ? itemConverter.to(object) : object;
         } else if (JsonArray.class.isInstance(jsonValue)) {
             if (JsonArray.class == type || JsonStructure.class == type) {
                 return jsonValue;
             }
-            return buildArray(type, JsonArray.class.cast(jsonValue), 
itemConverter);
+            return buildArray(type, JsonArray.class.cast(jsonValue), 
itemConverter, null, jsonPointer, rootType);
         } else if (JsonNumber.class.isInstance(jsonValue)) {
             if (JsonNumber.class == type) {
                 return jsonValue;
@@ -520,6 +570,13 @@ public class MappingParserImpl implements MappingParser {
 
             final String string = JsonString.class.cast(jsonValue).getString();
             if (itemConverter == null) {
+                // check whether we have a jsonPointer to a previously 
deserialised object
+                if (!String.class.equals(type)) {
+                    Object o = jsonPointers.get(string);
+                    if (o != null) {
+                        return o;
+                    }
+                }
                 return convertTo(Class.class.cast(type), string);
             } else {
                 return itemConverter.to(string);
@@ -529,40 +586,46 @@ public class MappingParserImpl implements MappingParser {
         throw new MapperException("Unable to parse " + jsonValue + " to " + 
type);
     }
 
-    private Object buildArray(final Type type, final JsonArray jsonArray, 
final Adapter itemConverter) {
+    private Object buildArray(final Type type, final JsonArray jsonArray, 
final Adapter itemConverter,
+                              final ObjectConverter.Reader objectConverter,
+                              final JsonPointerTracker jsonPointer, final Type 
rootType) {
         if (Class.class.isInstance(type)) {
             final Class clazz = Class.class.cast(type);
             if (clazz.isArray()) {
                 final Class<?> componentType = clazz.getComponentType();
-                return buildArrayWithComponentType(jsonArray, componentType, 
itemConverter);
+                return buildArrayWithComponentType(jsonArray, componentType, 
itemConverter, jsonPointer, rootType);
             }
         }
 
         if (ParameterizedType.class.isInstance(type)) {
-            final Mappings.CollectionMapping mapping = 
mappings.findCollectionMapping(ParameterizedType.class.cast(type));
+            final Mappings.CollectionMapping mapping = 
mappings.findCollectionMapping(ParameterizedType.class.cast(type), rootType);
             if (mapping != null) {
-                return mapCollection(mapping, jsonArray, itemConverter);
+                return mapCollection(mapping, jsonArray, itemConverter, 
objectConverter, jsonPointer, rootType);
             }
         }
 
         if (Object.class == type) {
-            return buildArray(ANY_LIST, jsonArray, null);
+            return buildArray(ANY_LIST, jsonArray, null, null, jsonPointer, 
rootType);
         }
 
         throw new UnsupportedOperationException("type " + type + " not 
supported");
     }
 
-    private Object buildArrayWithComponentType(final JsonArray jsonArray, 
final Class<?> componentType, final Adapter itemConverter) {
+    private Object buildArrayWithComponentType(final JsonArray jsonArray, 
final Class<?> componentType, final Adapter itemConverter,
+                                               final JsonPointerTracker 
jsonPointer, final Type rootType) {
         final Object array = Array.newInstance(componentType, 
jsonArray.size());
         int i = 0;
         for (final JsonValue value : jsonArray) {
-            Array.set(array, i++, toObject(null, value, componentType, 
itemConverter));
+            Array.set(array, i, toObject(null, value, componentType, 
itemConverter,
+                    isDeduplicateObjects ? new JsonPointerTracker(jsonPointer, 
i) : null, rootType));
+            i++;
         }
         return array;
     }
 
     private <T> Collection<T> mapCollection(final Mappings.CollectionMapping 
mapping, final JsonArray jsonArray,
-                                            final Adapter itemConverter) {
+                                            final Adapter itemConverter, 
ObjectConverter.Reader objectConverter,
+                                            final JsonPointerTracker 
jsonPointer, final Type rootType) {
         final Collection collection;
 
         if (SortedSet.class == mapping.raw || NavigableSet.class == 
mapping.raw || TreeSet.class == mapping.raw) {
@@ -583,8 +646,13 @@ public class MappingParserImpl implements MappingParser {
             throw new IllegalStateException("not supported collection type: " 
+ mapping.raw.getName());
         }
 
+        int i = 0;
         for (final JsonValue value : jsonArray) {
-            collection.add(JsonValue.NULL.equals(value) ? null : 
toObject(null, value, mapping.arg, itemConverter));
+            collection.add(JsonValue.NULL.equals(value)
+                    ? null
+                    : toValue(null, value, null, itemConverter, mapping.arg, 
objectConverter,
+                    isDeduplicateObjects ? new JsonPointerTracker(jsonPointer, 
i) : null, rootType));
+            i++;
         }
 
         if (EnumSet.class == mapping.raw) {
@@ -593,7 +661,7 @@ public class MappingParserImpl implements MappingParser {
             } else if (collection.size() == 1) {
                 return 
Collection.class.cast(EnumSet.of(Enum.class.cast(collection.iterator().next())));
             } else {
-                final List<Enum<?>> list = List.class.cast(collection);
+                final List<Enum> list = List.class.cast(collection);
                 return Collection.class.cast(EnumSet.of(list.get(0), 
list.subList(1, list.size()).toArray(new Enum[list.size() - 1])));
             }
         }
@@ -602,38 +670,51 @@ public class MappingParserImpl implements MappingParser {
     }
 
 
-    private Object[] createParameters(final Mappings.ClassMapping mapping, 
final JsonObject object) {
+    private Object[] createParameters(final Mappings.ClassMapping mapping, 
final JsonObject object, JsonPointerTracker jsonPointer) {
         final int length = mapping.factory.getParameterTypes().length;
         final Object[] objects = new Object[length];
 
         for (int i = 0; i < length; i++) {
 
+            String paramName = mapping.factory.getParameterNames()[i];
             objects[i] = toValue(null,
-                                 
object.get(mapping.factory.getParameterNames()[i]),
-                                 mapping.factory.getParameterConverter()[i],
-                                 
mapping.factory.getParameterItemConverter()[i],
-                                 mapping.factory.getParameterTypes()[i],
-                                 null); //X TODO ObjectConverter in 
@JOhnzonConverter with Constructors!
+                    object.get(paramName),
+                    mapping.factory.getParameterConverter()[i],
+                    mapping.factory.getParameterItemConverter()[i],
+                    mapping.factory.getParameterTypes()[i],
+                    mapping.factory.getObjectConverter()[i],
+                    isDeduplicateObjects ? new JsonPointerTracker(jsonPointer, 
paramName) : null,
+                    mapping.clazz); //X TODO ObjectConverter in 
@JohnzonConverter with Constructors!
         }
 
         return objects;
     }
 
     private Object toValue(final Object baseInstance, final JsonValue 
jsonValue, final Adapter converter,
-                           final Adapter itemConverter, final Type type, final 
ObjectConverter.Reader objectConverter) {
+                           final Adapter itemConverter, final Type type, final 
ObjectConverter.Reader objectConverter,
+                           final JsonPointerTracker jsonPointer, final Type 
rootType) {
 
         if (objectConverter != null) {
 
             if (jsonValue instanceof JsonObject) {
                 return objectConverter.fromJson((JsonObject) jsonValue, type, 
this);
+            } else if (jsonValue instanceof JsonArray) {
+                return buildArray(type, (JsonArray) jsonValue, itemConverter, 
objectConverter, jsonPointer, rootType);
             } else {
                 throw new UnsupportedOperationException("Array handling with 
ObjectConverter currently not implemented");
             }
         }
 
-        return converter == null ? toObject(baseInstance, jsonValue, type, 
itemConverter)
-                                 : jsonValue.getValueType() == 
JsonValue.ValueType.STRING ? 
converter.to(JsonString.class.cast(jsonValue).getString())
-                                                                               
           : convertTo(converter, jsonValue);
+        try {
+            return converter == null ? toObject(baseInstance, jsonValue, type, 
itemConverter, jsonPointer, rootType)
+                    : jsonValue.getValueType() == JsonValue.ValueType.STRING ? 
converter.to(JsonString.class.cast(jsonValue).getString())
+                    : convertTo(converter, jsonValue, jsonPointer);
+        } catch (Exception e) {
+            if (e instanceof MapperException) {
+                throw (MapperException) e;
+            }
+            throw new MapperException(e);
+        }
     }
 
 
@@ -678,8 +759,8 @@ public class MappingParserImpl implements MappingParser {
             }
         }
         if (converter == null) {
-            config.getAdapters().putIfAbsent(new AdapterKey(String.class, 
aClass), FALLBACK_CONVERTER);
-            return FALLBACK_CONVERTER.to(text);
+            throw new MapperException("Missing a Converter for type " + aClass 
+ " to convert the JSON String '" +
+                    text + "' . Please register a custom converter for it.");
         }
         return converter.to(text);
     }
@@ -703,21 +784,6 @@ public class MappingParserImpl implements MappingParser {
         return null;
     }
 
-
-    private static class FallbackConverter implements Converter<Object> {
-        @Override
-        public String toString(final Object instance) {
-            return instance.toString();
-        }
-
-        @Override
-        public Object fromString(final String text) {
-            throw new MapperException("Using fallback converter, " +
-                                      "this only works in write mode but not 
in read. Please register a custom converter to do so.");
-        }
-    }
-
-
     /**
      * Internal class to suppress {@link ObjectConverter} lookup if and only if
      * the {@link JsonValue} is the same refernece than the lookup was done 
before.

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/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 7dd016c..08845fe 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
@@ -24,6 +24,7 @@ import 
org.apache.johnzon.mapper.converter.DateWithCopyConverter;
 import org.apache.johnzon.mapper.converter.EnumConverter;
 import org.apache.johnzon.mapper.internal.AdapterKey;
 import org.apache.johnzon.mapper.internal.ConverterAdapter;
+import org.apache.johnzon.mapper.reflection.Generics;
 import org.apache.johnzon.mapper.reflection.JohnzonParameterizedType;
 
 import java.lang.annotation.Annotation;
@@ -37,6 +38,7 @@ import java.util.Collection;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.Deque;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -52,6 +54,7 @@ import java.util.concurrent.ConcurrentMap;
 
 import static java.util.Arrays.asList;
 import static org.apache.johnzon.mapper.reflection.Converters.matches;
+import static org.apache.johnzon.mapper.reflection.Generics.resolve;
 
 public class Mappings {
     public static class ClassMapping {
@@ -65,6 +68,9 @@ public class Mappings {
         public final Getter anyGetter;
         public final Method anySetter;
 
+        private Boolean deduplicateObjects;
+        private boolean deduplicationEvaluated = false;
+
         protected ClassMapping(final Class<?> clazz, final AccessMode.Factory 
factory,
                                final Map<String, Getter> getters, final 
Map<String, Setter> setters,
                                final Adapter<?, ?> adapter,
@@ -80,6 +86,18 @@ public class Mappings {
             this.anyGetter = anyGetter;
             this.anySetter = anySetter;
         }
+
+        public Boolean isDeduplicateObjects() {
+            if (!deduplicationEvaluated) {
+                JohnzonDeduplicateObjects jdo = 
((Class<JohnzonDeduplicateObjects>) 
clazz).getAnnotation(JohnzonDeduplicateObjects.class);
+                if (jdo != null){
+                    deduplicateObjects = jdo.value();
+                }
+                deduplicationEvaluated = true;
+            }
+            return deduplicateObjects;
+        }
+
     }
 
     public static class CollectionMapping {
@@ -100,22 +118,26 @@ public class Mappings {
         public final Adapter converter;
         public final Adapter itemConverter;
         public final ObjectConverter.Writer objectConverter;
+        public final boolean dynamic;
         public final boolean primitive;
         public final boolean array;
         public final boolean map;
         public final boolean collection;
+        public final Collection<String> ignoreNested;
 
-        public Getter(final AccessMode.Reader reader,
+        public Getter(final AccessMode.Reader reader, final boolean dynamic,
                       final boolean primitive, final boolean array,
                       final boolean collection, final boolean map,
                       final MapperConverter converter,
                       final ObjectConverter.Writer providedObjectConverter,
-                      final int version) {
+                      final int version, final String[] ignoreNested) {
             this.reader = reader;
             this.version = version;
+            this.dynamic = dynamic;
             this.array = array;
             this.collection = collection;
             this.primitive = primitive;
+            this.ignoreNested = ignoreNested == null || ignoreNested.length == 
0 ? null : new HashSet<String>(asList(ignoreNested));
 
             Adapter theConverter = null;
             Adapter theItemConverter = null;
@@ -238,10 +260,10 @@ public class Mappings {
         this.config = config;
     }
 
-    public CollectionMapping findCollectionMapping(final ParameterizedType 
genericType) {
+    public CollectionMapping findCollectionMapping(final ParameterizedType 
genericType, final Type enclosingType) {
         CollectionMapping collectionMapping = collections.get(genericType);
         if (collectionMapping == null) {
-            collectionMapping = createCollectionMapping(genericType);
+            collectionMapping = createCollectionMapping(genericType, 
enclosingType);
             if (collectionMapping == null) {
                 return null;
             }
@@ -253,7 +275,7 @@ public class Mappings {
         return collectionMapping;
     }
 
-    private <T> CollectionMapping createCollectionMapping(final 
ParameterizedType aType) {
+    private <T> CollectionMapping createCollectionMapping(final 
ParameterizedType aType, final Type root) {
         final Type[] fieldArgTypes = aType.getActualTypeArguments();
         final Type raw = aType.getRawType();
         if (fieldArgTypes.length == 1 && Class.class.isInstance(raw)) {
@@ -263,6 +285,8 @@ public class Mappings {
                 collectionType = List.class;
             } else if (SortedSet.class.isAssignableFrom(r)) {
                 collectionType = SortedSet.class;
+            } else if (EnumSet.class.isAssignableFrom(r)) {
+                collectionType = EnumSet.class;
             } else if (Set.class.isAssignableFrom(r)) {
                 collectionType = Set.class;
             } else if (Deque.class.isAssignableFrom(r)) {
@@ -275,7 +299,8 @@ public class Mappings {
                 return null;
             }
 
-            final CollectionMapping mapping = new 
CollectionMapping(isPrimitive(fieldArgTypes[0]), collectionType, 
fieldArgTypes[0]);
+            final CollectionMapping mapping = new 
CollectionMapping(isPrimitive(fieldArgTypes[0]), collectionType,
+                    Generics.resolve(fieldArgTypes[0], 
Class.class.isInstance(root) ? Class.class.cast(root) : null));
             collections.putIfAbsent(aType, mapping);
             return mapping;
         }
@@ -353,13 +378,13 @@ public class Mappings {
             final JohnzonVirtualObjects virtualObjects = 
clazz.getAnnotation(JohnzonVirtualObjects.class);
             if (virtualObjects != null) {
                 for (final JohnzonVirtualObject virtualObject : 
virtualObjects.value()) {
-                    handleVirtualObject(virtualFields, virtualObject, getters, 
setters, readers, writers, copyDate);
+                    handleVirtualObject(virtualFields, virtualObject, getters, 
setters, readers, writers, copyDate, clazz);
                 }
             }
 
             final JohnzonVirtualObject virtualObject = 
clazz.getAnnotation(JohnzonVirtualObject.class);
             if (virtualObject != null) {
-                handleVirtualObject(virtualFields, virtualObject, getters, 
setters, readers, writers, copyDate);
+                handleVirtualObject(virtualFields, virtualObject, getters, 
setters, readers, writers, copyDate, clazz);
             }
         }
 
@@ -368,7 +393,7 @@ public class Mappings {
             if (virtualFields.contains(key)) {
                 continue;
             }
-            addGetterIfNeeded(getters, key, reader.getValue(), copyDate);
+            addGetterIfNeeded(getters, key, reader.getValue(), copyDate, 
clazz);
         }
 
         for (final Map.Entry<String, AccessMode.Writer> writer : 
writers.entrySet()) {
@@ -376,7 +401,7 @@ public class Mappings {
             if (virtualFields.contains(key)) {
                 continue;
             }
-            addSetterIfNeeded(setters, key, writer.getValue(), copyDate);
+            addSetterIfNeeded(setters, key, writer.getValue(), copyDate, 
clazz);
         }
 
         final Method anyGetter = accessMode.findAnyGetter(clazz);
@@ -387,7 +412,7 @@ public class Mappings {
                 accessMode.findWriter(clazz),
                 anyGetter != null ? new Getter(
                         new MethodAccessMode.MethodReader(anyGetter, 
anyGetter.getReturnType()),
-                        false, false, false, true, null, null, -1) : null,
+                        false,false, false, false, true, null, null, -1, null) 
: null,
                 accessMode.findAnySetter(clazz));
 
         accessMode.afterParsed(clazz);
@@ -416,7 +441,8 @@ public class Mappings {
     private void addSetterIfNeeded(final Map<String, Setter> setters,
                                    final String key,
                                    final AccessMode.Writer value,
-                                   final boolean copyDate) {
+                                   final boolean copyDate,
+                                   final Class<?> rootClass) {
         final JohnzonIgnore writeIgnore = 
value.getAnnotation(JohnzonIgnore.class);
         if (writeIgnore == null || writeIgnore.minVersion() >= 0) {
             if (key.equals("metaClass")) {
@@ -425,7 +451,7 @@ public class Mappings {
             final Type param = value.getType();
             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,
+                    value, isPrimitive(param), returnType != null && 
returnType.isArray(), resolve(param, rootClass),
                     findConverter(copyDate, value), 
value.findObjectConverterReader(),
                     writeIgnore != null ? writeIgnore.minVersion() : -1);
             setters.put(key, setter);
@@ -435,19 +461,22 @@ public class Mappings {
     private void addGetterIfNeeded(final Map<String, Getter> getters,
                                    final String key,
                                    final AccessMode.Reader value,
-                                   final boolean copyDate) {
+                                   final boolean copyDate,
+                                   final Class<?> rootClass) {
         final JohnzonIgnore readIgnore = 
value.getAnnotation(JohnzonIgnore.class);
+        final JohnzonIgnoreNested ignoreNested = 
value.getAnnotation(JohnzonIgnoreNested.class);
         if (readIgnore == null || readIgnore.minVersion() >= 0) {
             final Class<?> returnType = 
Class.class.isInstance(value.getType()) ? Class.class.cast(value.getType()) : 
null;
             final ParameterizedType pt = 
ParameterizedType.class.isInstance(value.getType()) ? 
ParameterizedType.class.cast(value.getType()) : null;
-            final Getter getter = new Getter(value, isPrimitive(returnType),
+            final Getter getter = new Getter(value, returnType == 
Object.class, isPrimitive(returnType),
                     returnType != null && returnType.isArray(),
                     (pt != null && 
Collection.class.isAssignableFrom(Class.class.cast(pt.getRawType())))
                             || (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), 
value.findObjectConverterWriter(),
-                    readIgnore != null ? readIgnore.minVersion() : -1);
+                    readIgnore != null ? readIgnore.minVersion() : -1,
+                    ignoreNested != null ? ignoreNested.properties() : null);
             getters.put(key, getter);
         }
     }
@@ -459,7 +488,8 @@ public class Mappings {
                                      final Map<String, Setter> setters,
                                      final Map<String, AccessMode.Reader> 
readers,
                                      final Map<String, AccessMode.Writer> 
writers,
-                                     final boolean copyDate) {
+                                     final boolean copyDate,
+                                     final Class<?> rootClazz) {
         final String[] path = o.path();
         if (path.length < 1) {
             throw new IllegalArgumentException("@JohnzonVirtualObject need a 
path");
@@ -479,13 +509,13 @@ public class Mappings {
             if (f.read()) {
                 final AccessMode.Reader reader = readers.get(name);
                 if (reader != null) {
-                    addGetterIfNeeded(objectGetters, name, reader, copyDate);
+                    addGetterIfNeeded(objectGetters, name, reader, copyDate, 
rootClazz);
                 }
             }
             if (f.write()) {
                 final AccessMode.Writer writer = writers.get(name);
                 if (writer != null) {
-                    addSetterIfNeeded(objectSetters, name, writer, copyDate);
+                    addSetterIfNeeded(objectSetters, name, writer, copyDate, 
rootClazz);
                 }
             }
         }
@@ -494,7 +524,8 @@ 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, 
null, -1));
+        getters.put(key, new Getter(getter == null ? newReader :
+                new CompositeReader(getter.reader, newReader), false, false, 
false, false, true, null, null, -1, null));
 
         final Setter newSetter = setters.get(key);
         final MapUnwrapperWriter newWriter = new 
MapUnwrapperWriter(objectSetters, path);
@@ -531,13 +562,6 @@ public class Mappings {
 
             if (Date.class.isAssignableFrom(type) && copyDate) {
                 converter = new 
DateWithCopyConverter(Adapter.class.cast(adapters.get(new 
AdapterKey(Date.class, String.class))));
-            } else if (type.isEnum()) {
-                final AdapterKey key = new AdapterKey(String.class, type);
-                converter = adapters.get(key); // first ensure user didnt 
override it
-                if (converter == null) {
-                    converter = new ConverterAdapter(new EnumConverter(type));
-                    adapters.put(key, (Adapter<?, ?>) converter);
-                }
             } else {
                 for (final Map.Entry<AdapterKey, Adapter<?, ?>> adapterEntry : 
adapters.entrySet()) {
                     if (adapterEntry.getKey().getFrom() == 
adapterEntry.getKey().getTo()) { // String -> String
@@ -555,6 +579,14 @@ public class Mappings {
                     }
                 }
             }
+            if (converter == null && type.isEnum()) {
+                final AdapterKey key = new AdapterKey(String.class, type);
+                converter = adapters.get(key); // first ensure user didnt 
override it
+                if (converter == null) {
+                    converter = new ConverterAdapter(new EnumConverter(type));
+                    adapters.put(key, (Adapter<?, ?>) converter);
+                }
+            }
         }
         return converter;
     }

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/SerializeValueFilter.java
----------------------------------------------------------------------
diff --git 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/SerializeValueFilter.java
 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/SerializeValueFilter.java
new file mode 100644
index 0000000..e29fd52
--- /dev/null
+++ 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/SerializeValueFilter.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.mapper;
+
+public interface SerializeValueFilter {
+    /**
+     * @param name the attribute name if set.
+     * @param value the value which will get serialized.
+     * @return true if the value should be ignored and not serialized.
+     */
+    boolean shouldIgnore(String name, Object value);
+}

http://git-wip-us.apache.org/repos/asf/johnzon/blob/76fe13de/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 8575aa3..4d590bf 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
@@ -52,6 +52,7 @@ public interface AccessMode {
         String[] getParameterNames();
         Adapter<?, ?>[] getParameterConverter();
         Adapter<?, ?>[] getParameterItemConverter();
+        ObjectConverter.Codec<?>[] getObjectConverter();
     }
 
     Factory findFactory(Class<?> clazz);

Reply via email to