This is an automated email from the ASF dual-hosted git repository.

rmannibucau pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/johnzon.git

commit c8e233e2f3c54037b8aa5d5d9bf165b550cc9641
Author: Romain Manni-Bucau <rmannibu...@gmail.com>
AuthorDate: Sun Jun 20 16:28:42 2021 +0200

    [JOHNZON-349] trying to not do reflection until we know we can, dedup 
annotation case
---
 .../converter/JsonbOffsetDateTimeConverter.java    | 42 +++++++++
 .../org/apache/johnzon/jsonb/CdiAdapterTest.java   | 99 +++++++++++++++++-----
 .../jsonschema/JsonSchemaValidatorFactory.java     | 11 ++-
 .../johnzon/jsonschema/regex/JavascriptRegex.java  |  3 +-
 .../java/org/apache/johnzon/mapper/Mapper.java     | 42 +++------
 .../org/apache/johnzon/mapper/MapperConfig.java    |  4 +-
 .../johnzon/mapper/MappingGeneratorImpl.java       | 66 +++++++++------
 .../apache/johnzon/mapper/MappingParserImpl.java   | 86 +++++++++----------
 .../java/org/apache/johnzon/mapper/Mappings.java   | 19 ++---
 .../mapper/internal/JsonPointerTracker.java        | 15 +++-
 .../apache/johnzon/mapper/CircularObjectsTest.java | 20 +++--
 .../mapper/internal/JsonPointerTrackerTest.java    |  2 +-
 pom.xml                                            |  2 +-
 13 files changed, 258 insertions(+), 153 deletions(-)

diff --git 
a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbOffsetDateTimeConverter.java
 
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbOffsetDateTimeConverter.java
new file mode 100644
index 0000000..a78c1ac
--- /dev/null
+++ 
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/converter/JsonbOffsetDateTimeConverter.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.jsonb.converter;
+
+import javax.json.bind.annotation.JsonbDateFormat;
+import java.time.Instant;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+
+public class JsonbOffsetDateTimeConverter extends 
JsonbDateConverterBase<OffsetDateTime> {
+    private static final ZoneId UTC = ZoneId.of("UTC");
+
+    public JsonbOffsetDateTimeConverter(final JsonbDateFormat dateFormat) {
+        super(dateFormat);
+    }
+
+    @Override
+    public String toString(final OffsetDateTime instance) {
+        return formatter == null ? instance.toString() : 
instance.format(formatter);
+    }
+
+    @Override
+    public OffsetDateTime fromString(final String text) {
+        return formatter == null ? 
OffsetDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong(text)), UTC) : 
OffsetDateTime.parse(text, formatter);
+    }
+}
diff --git 
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/CdiAdapterTest.java 
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/CdiAdapterTest.java
index d071541..2ef3742 100644
--- a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/CdiAdapterTest.java
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/CdiAdapterTest.java
@@ -18,55 +18,112 @@
  */
 package org.apache.johnzon.jsonb;
 
+import org.apache.johnzon.jsonb.cdi.JohnzonCdiExtension;
 import org.apache.webbeans.config.WebBeansContext;
 import org.apache.webbeans.config.WebBeansFinder;
+import org.apache.webbeans.corespi.DefaultSingletonService;
+import org.apache.webbeans.corespi.scanner.xbean.CdiArchive;
 import org.apache.webbeans.corespi.se.DefaultScannerService;
 import org.apache.webbeans.lifecycle.StandaloneLifeCycle;
 import org.apache.webbeans.proxy.OwbNormalScopeProxy;
+import org.apache.webbeans.service.ClassLoaderProxyService;
+import org.apache.webbeans.spi.BeanArchiveService;
 import org.apache.webbeans.spi.ContainerLifecycle;
+import org.apache.webbeans.spi.DefiningClassService;
+import org.apache.webbeans.spi.LoaderService;
+import org.apache.webbeans.spi.ResourceInjectionService;
 import org.apache.webbeans.spi.ScannerService;
+import org.apache.webbeans.spi.api.ResourceReference;
 import org.apache.webbeans.util.WebBeansUtil;
-import org.apache.xbean.finder.AnnotationFinder;
-import org.apache.xbean.finder.archive.ClassesArchive;
+import org.apache.webbeans.xml.DefaultBeanArchiveInformation;
 import org.junit.Test;
 
 import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.spi.Extension;
 import javax.inject.Inject;
 import javax.json.bind.Jsonb;
 import javax.json.bind.JsonbBuilder;
 import javax.json.bind.adapter.JsonbAdapter;
 import javax.json.bind.annotation.JsonbTypeAdapter;
+import java.lang.annotation.Annotation;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 
-import static java.util.Collections.singletonMap;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 public class CdiAdapterTest {
     @Test
-    public void run() {
-        WebBeansFinder.clearInstances(WebBeansUtil.getCurrentClassLoader());
+    public void run() throws Exception {
+        final ClassLoader currentClassLoader = 
WebBeansUtil.getCurrentClassLoader();
+        WebBeansFinder.clearInstances(currentClassLoader);
+        final Map<Class<?>, Object> services = new HashMap<>();
+        services.put(ScannerService.class, new DefaultScannerService() {
+            @Override
+            protected void configure() {
+                initFinder();
+                final DefaultBeanArchiveInformation information = new 
DefaultBeanArchiveInformation("file://foo");
+                
information.setBeanDiscoveryMode(BeanArchiveService.BeanDiscoveryMode.ALL);
+                try {
+                    archive.classesByUrl().put(information.getBdaUrl(), new 
CdiArchive.FoundClasses(
+                            URI.create(information.getBdaUrl()).toURL(), 
asList(
+                            Service.class.getName(), 
ModelAdapter.class.getName()),
+                            information));
+                } catch (final MalformedURLException e) {
+                    throw new IllegalStateException(e);
+                }
+            }
+        });
+        services.put(ResourceInjectionService.class, new 
ResourceInjectionService() {
+            @Override
+            public void injectJavaEEResources(final Object 
managedBeanInstance) {
+                System.out.println();
+            }
+
+            @Override
+            public <X, T extends Annotation> X getResourceReference(final 
ResourceReference<X, T> resourceReference) {
+                return null;
+            }
+
+            @Override
+            public void clear() {
+                // no-op
+            }
+        });
+        services.put(LoaderService.class, new LoaderService() {
+            @Override
+            public <T> List<T> load(final Class<T> serviceType, final 
ClassLoader loader) {
+                if (Extension.class == serviceType) {
+                    return singletonList(serviceType.cast(new 
JohnzonCdiExtension()));
+                }
+                return Collections.emptyList();
+            }
+
+            @Override
+            public <T> List<T> load(final Class<T> serviceType) {
+                return emptyList();
+            }
+        });
+        final Properties properties = new Properties();
+        properties.setProperty(DefiningClassService.class.getName(), 
ClassLoaderProxyService.class.getName());
+        final WebBeansContext webBeansContext = new WebBeansContext(services, 
properties);
+        
DefaultSingletonService.class.cast(WebBeansFinder.getSingletonService()).register(
+                currentClassLoader, webBeansContext);
         final ContainerLifecycle testLifecycle = new StandaloneLifeCycle();
-        new WebBeansContext(singletonMap(
-                ScannerService.class, new DefaultScannerService() {
-                    @Override
-                    protected AnnotationFinder initFinder() {
-                        return new AnnotationFinder(new 
ClassesArchive(Service.class, ModelAdapter.class));
-                    }
-                }), new Properties());
         testLifecycle.startApplication(null);
-        try {
-            Jsonb jsonb = JsonbBuilder.create();
+        try (final Jsonb jsonb = JsonbBuilder.create()) {
             assertEquals("{\"model\":\"5\"}", jsonb.toJson(new Root(new 
Model(5))));
-            try {
-                AutoCloseable.class.cast(jsonb).close();
-            } catch (final Exception e) {
-                fail(e.getMessage());
-            }
         } finally {
             testLifecycle.stopApplication(null);
-            
WebBeansFinder.clearInstances(WebBeansUtil.getCurrentClassLoader());
+            WebBeansFinder.clearInstances(currentClassLoader);
         }
     }
 
diff --git 
a/johnzon-jsonschema/src/main/java/org/apache/johnzon/jsonschema/JsonSchemaValidatorFactory.java
 
b/johnzon-jsonschema/src/main/java/org/apache/johnzon/jsonschema/JsonSchemaValidatorFactory.java
index 2fe4e27..14103bc 100644
--- 
a/johnzon-jsonschema/src/main/java/org/apache/johnzon/jsonschema/JsonSchemaValidatorFactory.java
+++ 
b/johnzon-jsonschema/src/main/java/org/apache/johnzon/jsonschema/JsonSchemaValidatorFactory.java
@@ -36,6 +36,7 @@ import java.util.stream.StreamSupport;
 import javax.json.JsonObject;
 import javax.json.JsonValue;
 
+import org.apache.johnzon.jsonschema.regex.JavaRegex;
 import org.apache.johnzon.jsonschema.regex.JavascriptRegex;
 import org.apache.johnzon.jsonschema.spi.ValidationContext;
 import org.apache.johnzon.jsonschema.spi.ValidationExtension;
@@ -76,7 +77,15 @@ public class JsonSchemaValidatorFactory implements 
AutoCloseable {
     private final List<ValidationExtension> extensions = new ArrayList<>();
 
     // js is closer to default and actually most used in the industry
-    private final AtomicReference<Function<String, Predicate<CharSequence>>> 
regexFactory = new AtomicReference<>(JavascriptRegex::new);
+    private final AtomicReference<Function<String, Predicate<CharSequence>>> 
regexFactory = new AtomicReference<>(this::newRegexFactory);
+
+    private Predicate<CharSequence> newRegexFactory(final String regex) {
+        try {
+            return new JavascriptRegex(regex);
+        } catch (final RuntimeException re) {
+            return new JavaRegex(regex);
+        }
+    }
 
     public JsonSchemaValidatorFactory() {
         extensions.addAll(createDefaultValidations());
diff --git 
a/johnzon-jsonschema/src/main/java/org/apache/johnzon/jsonschema/regex/JavascriptRegex.java
 
b/johnzon-jsonschema/src/main/java/org/apache/johnzon/jsonschema/regex/JavascriptRegex.java
index 9b83389..6ec93cf 100644
--- 
a/johnzon-jsonschema/src/main/java/org/apache/johnzon/jsonschema/regex/JavascriptRegex.java
+++ 
b/johnzon-jsonschema/src/main/java/org/apache/johnzon/jsonschema/regex/JavascriptRegex.java
@@ -18,12 +18,11 @@
  */
 package org.apache.johnzon.jsonschema.regex;
 
-import java.util.function.Predicate;
-
 import javax.script.Bindings;
 import javax.script.ScriptEngine;
 import javax.script.ScriptEngineManager;
 import javax.script.ScriptException;
+import java.util.function.Predicate;
 
 public class JavascriptRegex implements Predicate<CharSequence> {
 
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 b74c105..022eaee 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
@@ -114,8 +114,7 @@ public class Mapper implements Closeable {
 
     public <T> void writeArray(final Collection<T> object, final Writer 
stream) {
         try (final JsonGenerator generator = 
generatorFactory.createGenerator(stream(stream))) {
-            boolean dedup = Boolean.TRUE.equals(config.isDeduplicateObjects());
-            writeObject(object, generator, null, dedup ? new 
JsonPointerTracker(null, "/") : null);
+            writeObject(object, generator, null, config.isDeduplicateObjects() 
? JsonPointerTracker.ROOT : null);
         }
     }
 
@@ -125,8 +124,7 @@ public class Mapper implements Closeable {
 
     public <T> void writeIterable(final Iterable<T> object, final Writer 
stream) {
         try (final JsonGenerator generator = 
generatorFactory.createGenerator(stream(stream))) {
-            boolean dedup = Boolean.TRUE.equals(config.isDeduplicateObjects());
-            writeObject(object, generator, null, dedup ? new 
JsonPointerTracker(null, "/") : null);
+            writeObject(object, generator, null, config.isDeduplicateObjects() 
? JsonPointerTracker.ROOT : null);
         }
     }
 
@@ -162,8 +160,7 @@ public class Mapper implements Closeable {
             return provider.createValue(BigInteger.class.cast(object));
         }
         final JsonObjectGenerator objectGenerator = new 
JsonObjectGenerator(builderFactory);
-        writeObject(object, objectGenerator, null,
-                isDedup(object.getClass()) ? new JsonPointerTracker(null, "/") 
: null);
+        writeObject(object, objectGenerator, null, null);
         return objectGenerator.getResult();
     }
 
@@ -192,8 +189,7 @@ public class Mapper implements Closeable {
     }
 
     public void writeObjectWithGenerator(final Object object, final 
JsonGenerator generator) {
-        writeObject(object, generator, null,
-                isDedup(object.getClass()) ? new JsonPointerTracker(null, "/") 
: null);
+        writeObject(object, generator, null, null);
     }
 
     public void writeObject(final Object object, final OutputStream stream) {
@@ -205,9 +201,10 @@ public class Mapper implements Closeable {
         writeObject(object, new OutputStreamWriter(stream, charset));
     }
 
-    private void writeObject(final Object object, final JsonGenerator 
generator, final Collection<String> ignored, JsonPointerTracker jsonPointer) {
-        final MappingGeneratorImpl mappingGenerator = new 
MappingGeneratorImpl(config, generator, mappings, jsonPointer != null);
-        mappingGenerator.doWriteObject(object, generator, true, ignored, 
jsonPointer);
+    private void writeObject(final Object object, final JsonGenerator 
generator, final Collection<String> ignored,
+                             final JsonPointerTracker tracker) {
+        final MappingGeneratorImpl mappingGenerator = new 
MappingGeneratorImpl(config, generator, mappings);
+        mappingGenerator.doWriteObject(object, generator, true, ignored, 
tracker);
     }
 
     public String writeArrayAsString(final Collection<?> instance) {
@@ -263,7 +260,7 @@ public class Mapper implements Closeable {
             public void close() {
                 // no-op
             }
-        }, isDedup(clazz)).readObject(clazz);
+        }, null).readObject(clazz);
     }
 
     public <T> T readObject(final String string, final Type clazz) {
@@ -370,26 +367,7 @@ public class Mapper implements Closeable {
 
 
     private <T> T mapObject(final Type clazz, final JsonReader reader) {
-        return new MappingParserImpl(config, mappings, reader, 
isDedup(clazz)).readObject(clazz);
-    }
-
-    private boolean isDedup(final Type clazz) {
-        if (clazz instanceof Class &&
-                JsonValue.class != clazz && JsonStructure.class != clazz &&
-                JsonObject.class != clazz && JsonArray.class != clazz) {
-            Boolean dedup = config.isDeduplicateObjects();
-            if (dedup == null) {
-                // TODO: never call it more than once per clazz, should be 
done after once ClassMapping is obtained, not here!
-                //       -> revisit 
org.apache.johnzon.mapper.Mappings.findOrCreateClassMapping (isPrimitive should 
drop)
-                //       -> revisit 
org.apache.johnzon.mapper.access.FieldAccessMode.isIgnored(java.lang.String, 
java.lang.Class<?>)
-                Mappings.ClassMapping classMapping = 
mappings.findOrCreateClassMapping(clazz);
-                if (classMapping != null) {
-                    dedup = classMapping.isDeduplicateObjects();
-                }
-            }
-            return dedup != null ? dedup : false;
-        }
-        return false;
+        return new MappingParserImpl(config, mappings, reader, 
null).readObject(clazz);
     }
 
 
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 eea1716..4d8bceb 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
@@ -412,8 +412,8 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig 
implements Cloneable {
         return useBigDecimalForFloats;
     }
 
-    public Boolean isDeduplicateObjects() {
-        return deduplicateObjects;
+    public boolean isDeduplicateObjects() {
+        return Boolean.TRUE.equals(deduplicateObjects);
     }
 
     public boolean isSupportEnumContainerDeserialization() {
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 d4d103c..bdfba2a 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 static java.util.Collections.emptyList;
+import static java.util.Collections.emptyMap;
 import static java.util.stream.Collectors.toList;
 
 import org.apache.johnzon.mapper.internal.JsonPointerTracker;
@@ -45,19 +46,12 @@ 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, Boolean isDeduplicateObjects) {
+    MappingGeneratorImpl(MapperConfig config, JsonGenerator jsonGenerator, 
final Mappings mappings) {
         this.config = config;
         this.generator = jsonGenerator;
         this.mappings = mappings;
-
-        this.isDeduplicateObjects = isDeduplicateObjects;
-
-        this.jsonPointers = isDeduplicateObjects ?  new HashMap<>() : 
Collections.emptyMap();
     }
 
     @Override
@@ -76,7 +70,7 @@ public class MappingGeneratorImpl implements MappingGenerator 
{
             try {
                 if (Map.class.isInstance(object)) {
                     writeValue(Map.class, false, false, false, false, true, 
null, key, object,
-                            null, emptyList(), isDeduplicateObjects ? new 
JsonPointerTracker(null, "/") : null, generator);
+                            null, emptyList(), isDedup() ? 
JsonPointerTracker.ROOT : null, generator);
                 } else if(writePrimitives(key, objectClass, object, 
generator)) {
                     // no-op
                 } else if (Enum.class.isAssignableFrom(objectClass)) {
@@ -85,10 +79,10 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
                     generator.write(key, adaptedValue);
                 } else if (objectClass.isArray()) {
                     writeValue(Map.class, false, false, true, false, false, 
null, key, object,
-                            null, emptyList(), isDeduplicateObjects ? new 
JsonPointerTracker(null, "/") : null, generator);
+                            null, emptyList(), isDedup() ? 
JsonPointerTracker.ROOT : null, generator);
                 } else if (Iterable.class.isInstance(object)) {
                     writeValue(Map.class, false, false, false, true, false, 
null, key, object,
-                            null, emptyList(), isDeduplicateObjects ? new 
JsonPointerTracker(null, "/") : null, generator);
+                            null, emptyList(), isDedup() ? 
JsonPointerTracker.ROOT : null, generator);
                 } else {
                     final ObjectConverter.Writer objectConverter = 
config.findObjectConverterWriter(objectClass);
                     if (objectConverter != null) {
@@ -98,7 +92,7 @@ public class MappingGeneratorImpl implements MappingGenerator 
{
                         dynamicMappingGenerator.flushIfNeeded();
                     } else {
                         writeValue(objectClass, false, false, false, false, 
false, null, key, object,
-                                null, emptyList(), isDeduplicateObjects ? new 
JsonPointerTracker(null, "/") : null, generator);
+                                null, emptyList(), isDedup() ? 
JsonPointerTracker.ROOT : null, generator);
                     }
                 }
             } catch (final InvocationTargetException | IllegalAccessException 
e) {
@@ -115,11 +109,15 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
         } else if (object instanceof JsonValue) {
             generator.write((JsonValue) object);
         } else {
-            doWriteObject(object, generator, false, null, isDeduplicateObjects 
? new JsonPointerTracker(null, "/") : null);
+            doWriteObject(object, generator, false, null, isDedup() ? 
JsonPointerTracker.ROOT : null);
         }
         return this;
     }
 
+    private boolean isDedup() {
+        return config.isDeduplicateObjects() || (jsonPointers != null && 
jsonPointers != Collections.<Object, String>emptyMap());
+    }
+
     public void doWriteObject(Object object, JsonGenerator generator, boolean 
writeBody, final Collection<String> ignoredProperties,
                               JsonPointerTracker jsonPointer) {
 
@@ -184,6 +182,14 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
                     dynamicMappingGenerator.flushIfNeeded();
                 }
             } else {
+                if (classMapping == null) { // will be created anyway now so 
force it and if it has an adapter respect it
+                    final Mappings.ClassMapping mapping = 
mappings.findOrCreateClassMapping(objectClass);
+                    if (mapping != null && mapping.adapter != null) {
+                        final Object result = mapping.adapter.from(object);
+                        doWriteObject(result, generator, writeBody, 
ignoredProperties, jsonPointer);
+                        return;
+                    }
+                }
                 if (writeBody) {
                     generator.writeStartObject();
                 }
@@ -345,17 +351,23 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
     private boolean doWriteObjectBody(final Object object, final 
Collection<String> ignored,
                                       final JsonPointerTracker jsonPointer, 
final JsonGenerator generator)
             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) {
             throw new MapperException("No mapping for " + 
objectClass.getName());
         }
 
+        if (jsonPointers == null) {
+            if (classMapping.deduplicateObjects || 
config.isDeduplicateObjects()) {
+                jsonPointers = new HashMap<>();
+                jsonPointers.putIfAbsent(object, jsonPointer == null ? "/" : 
jsonPointer.toString());
+            } else {
+                jsonPointers = emptyMap();
+            }
+        } else if (isDedup()) {
+            jsonPointers.putIfAbsent(object, jsonPointer == null ? "/" : 
jsonPointer.toString());
+        }
+
         if (classMapping.writer != null) {
             final DynamicMappingGenerator gen = new 
DynamicMappingGenerator.SkipEnclosingWriteEnd(this, null, generator);
             classMapping.writer.writeJson(object, gen);
@@ -409,7 +421,7 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
                         val,
                         getter.objectConverter,
                         getter.ignoreNested,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, getterEntry.getKey()) : null,
+                        isDedup() ? new JsonPointerTracker(jsonPointer, 
getterEntry.getKey()) : null,
                         generator);
             }
         }
@@ -527,7 +539,7 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
         generator.writeStartArray(key);
         while (iterator.hasNext()) {
             final Object o = iterator.next();
-            String valJsonPointer = jsonPointers.get(o);
+            String valJsonPointer = jsonPointers == null ? null : 
jsonPointers.get(o);
             if (valJsonPointer != null) {
                 // write JsonPointer instead of the original object
                 writePrimitives(valJsonPointer);
@@ -544,7 +556,7 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
                     dynamicMappingGenerator.flushIfNeeded();
                 } else {
                     writeItem(itemConverter != null ? itemConverter.from(o) : 
o, ignoredProperties,
-                            isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null);
+                            isDedup() ? new JsonPointerTracker(jsonPointer, i) 
: null);
                 }
             }
             i++;
@@ -648,21 +660,23 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
             Object[] oArrayValue = (Object[]) arrayValue;
             for (int i = 0; i < length; i++) {
                 final Object o = oArrayValue[i];
-                writeItem(itemConverter != null ? itemConverter.from(o) : o, 
ignoredProperties, null);
+                writeItem(itemConverter != null ? itemConverter.from(o) : o, 
ignoredProperties,
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null);
             }
         } else {
             // must be object arrays
             for (int i = 0; i < length; i++) {
                 Object[] oArrayValue = (Object[]) arrayValue;
                 final Object o = oArrayValue[i];
-                String valJsonPointer = jsonPointers.get(o);
+                String valJsonPointer = jsonPointers == null ? null : 
jsonPointers.get(o);
                 if (valJsonPointer != null) {
                     // write the JsonPointer as String natively
                     generator.write(valJsonPointer);
                 } else if (o instanceof JsonValue) {
                     generator.write((JsonValue) o);
                 } else {
-                    writeItem(itemConverter != null ? itemConverter.from(o) : 
o, ignoredProperties, isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null);
+                    writeItem(itemConverter != null ? itemConverter.from(o) : 
o, ignoredProperties,
+                            isDedup() ? new JsonPointerTracker(jsonPointer, i) 
: null);
                 }
             }
         }
@@ -682,7 +696,7 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
                     writeArray(o.getClass(), null, null, o, ignoredProperties, 
jsonPointer);
                 }
             } else {
-                String valJsonPointer = jsonPointers.get(o);
+                String valJsonPointer = jsonPointers == null ? null : 
jsonPointers.get(o);
                 if (valJsonPointer != null) {
                     // write the JsonPointer instead
                     generator.write(valJsonPointer);
@@ -706,7 +720,7 @@ public class MappingGeneratorImpl implements 
MappingGenerator {
                     if (t == null) {
                         generator.writeNull();
                     } else {
-                        writeItem(t, ignoredProperties, isDeduplicateObjects ? 
new JsonPointerTracker(jsonPointer, i) : null);
+                        writeItem(t, ignoredProperties, isDedup() ? new 
JsonPointerTracker(jsonPointer, i) : null);
                     }
                 }
                 i++;
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 80ca4ad..e376e87 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
@@ -98,7 +98,6 @@ public class MappingParserImpl implements MappingParser {
 
     private final MapperConfig config;
     private final Mappings mappings;
-    private final boolean isDeduplicateObjects;
 
     private final JsonReader jsonReader;
 
@@ -110,19 +109,10 @@ public class MappingParserImpl implements MappingParser {
     private Map<String, Object> jsonPointers;
 
 
-    public MappingParserImpl(MapperConfig config, Mappings mappings, 
JsonReader jsonReader, boolean isDeduplicateObjects) {
+    public MappingParserImpl(MapperConfig config, Mappings mappings, 
JsonReader jsonReader, Map<String, Object> jsonPointers) {
         this.config = config;
         this.mappings = mappings;
-
         this.jsonReader = jsonReader;
-
-        this.isDeduplicateObjects = isDeduplicateObjects;
-
-        if (isDeduplicateObjects) {
-            jsonPointers = new HashMap<>();
-        } else {
-            jsonPointers = Collections.emptyMap();
-        }
     }
 
 
@@ -150,8 +140,7 @@ public class MappingParserImpl implements MappingParser {
         if (JsonObject.class.isInstance(jsonValue)) {
             return (T) buildObject(
                     targetType, JsonObject.class.cast(jsonValue), 
applyObjectConverter,
-                    isDeduplicateObjects ? new JsonPointerTracker(null, "/") : 
null,
-                    skippedConverters);
+                    null, skippedConverters);
         }
         if (JsonString.class.isInstance(jsonValue)) {
             if ((targetType == String.class || targetType == Object.class)) {
@@ -222,7 +211,7 @@ public class MappingParserImpl implements MappingParser {
                 if (asClass.isArray()) {
                     final Class componentType = asClass.getComponentType();
                     return (T) buildArrayWithComponentType(jsonArray, 
componentType, config.findAdapter(componentType),
-                            isDeduplicateObjects ? new 
JsonPointerTracker(null, "/") : null, Object.class);
+                            isDedup() ? JsonPointerTracker.ROOT : null, 
Object.class);
                 }
                 if (Collection.class.isAssignableFrom(asClass)) {
                     return readObject(jsonValue, new 
JohnzonParameterizedType(asClass, Object.class), applyObjectConverter, 
skippedConverters);
@@ -238,11 +227,11 @@ public class MappingParserImpl implements MappingParser {
 
                 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);
+                        null, isDedup() ? JsonPointerTracker.ROOT : null, 
Object.class);
             }
             if (Object.class == targetType) {
                 return (T) new 
ArrayList(asList(Object[].class.cast(buildArrayWithComponentType(jsonArray, 
Object.class, null,
-                        isDeduplicateObjects ? new JsonPointerTracker(null, 
"/") : null, Object.class))));
+                        isDedup() ? JsonPointerTracker.ROOT : null, 
Object.class))));
             }
         }
         if (NULL == valueType) {
@@ -258,6 +247,9 @@ public class MappingParserImpl implements MappingParser {
         throw new IllegalArgumentException("Unsupported " + jsonValue + " for 
type " + targetType);
     }
 
+    private boolean isDedup() {
+        return jsonPointers != Collections.<String, Object>emptyMap();
+    }
 
     private Object buildObject(final Type inType, final JsonObject object, 
final boolean applyObjectConverter,
                                final JsonPointerTracker jsonPointer, final 
Collection<Class<?>> skippedConverters) {
@@ -389,8 +381,15 @@ public class MappingParserImpl implements MappingParser {
             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);
+        if (jsonPointers == null) {
+            if (classMapping.deduplicateObjects || 
config.isDeduplicateObjects()) {
+                jsonPointers = new HashMap<>();
+                jsonPointers.put(jsonPointer == null ? "/" : 
jsonPointer.toString(), t);
+            } else {
+                jsonPointers = Collections.emptyMap();
+            }
+        } else if (isDedup()) {
+            jsonPointers.put(jsonPointer == null ? "/" : 
jsonPointer.toString(), t);
         }
 
         for (final Map.Entry<String, JsonValue> jsonEntry : object.entrySet()) 
{
@@ -428,7 +427,7 @@ public class MappingParserImpl implements MappingParser {
                 final Object convertedValue = toValue(
                         existingInstance, jsonValue, value.converter, 
value.itemConverter,
                         value.paramType, value.objectConverter,
-                        new JsonPointerTracker(jsonPointer, 
jsonEntry.getKey()), inType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, 
jsonEntry.getKey()) : null, inType);
                 if (convertedValue != null) {
                     setterMethod.write(t, convertedValue);
                 }
@@ -442,7 +441,7 @@ public class MappingParserImpl implements MappingParser {
                         classMapping.anySetter.invoke(t, key,
                                 toValue(null, entry.getValue(), null, null,
                                         
classMapping.anySetter.getGenericParameterTypes()[1], null,
-                                isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, entry.getKey()) : null, type));
+                                isDedup() ? new 
JsonPointerTracker(jsonPointer, entry.getKey()) : null, type));
                     } catch (final IllegalAccessException e) {
                         throw new IllegalStateException(e);
                     } catch (final InvocationTargetException e) {
@@ -457,7 +456,7 @@ public class MappingParserImpl implements MappingParser {
                     .filter(it -> 
!classMapping.setters.containsKey(it.getKey()))
                     .collect(toMap(Map.Entry::getKey, e -> toValue(null, 
e.getValue(), null, null,
                             
ParameterizedType.class.cast(classMapping.anyField.getGenericType()).getActualTypeArguments()[1],
 null,
-                            isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, e.getKey()) : null, tRef))));
+                            isDedup() ? new JsonPointerTracker(jsonPointer, 
e.getKey()) : null, tRef))));
             } catch (final IllegalAccessException e) {
                 throw new IllegalStateException(e);
             }
@@ -724,16 +723,15 @@ 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 (isDedup() && !String.class.equals(type)) {
+                    Object o = jsonPointers == null ? null : 
jsonPointers.get(string);
                     if (o != null) {
                         return o;
                     }
                 }
                 return convertTo(type, string);
-            } else {
-                return itemConverter.to(string);
             }
+            return itemConverter.to(string);
         }
 
         throw new MapperException("Unable to parse " + jsonValue + " to " + 
type);
@@ -810,7 +808,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (boolean) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -820,7 +818,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (byte) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -830,7 +828,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (char) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -840,7 +838,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (short) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -850,7 +848,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (int) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -860,7 +858,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (long) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -870,7 +868,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (float) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -880,7 +878,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (double) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -892,7 +890,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (Boolean) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -902,7 +900,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (Byte) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -912,7 +910,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (Character) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -922,7 +920,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (Short) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -932,7 +930,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (Integer) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -942,7 +940,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (Long) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -952,7 +950,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (Float) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -962,7 +960,7 @@ public class MappingParserImpl implements MappingParser {
             int i = 0;
             for (final JsonValue value : jsonArray) {
                 array[i] = (Double) toObject(null, value, componentType, 
itemConverter,
-                        isDeduplicateObjects ? new 
JsonPointerTracker(jsonPointer, i) : null, rootType);
+                        isDedup() ? new JsonPointerTracker(jsonPointer, i) : 
null, rootType);
                 i++;
             }
             return array;
@@ -973,7 +971,7 @@ public class MappingParserImpl implements MappingParser {
         int i = 0;
         for (final JsonValue value : jsonArray) {
             Array.set(array, i, toObject(null, value, componentType, 
itemConverter,
-                    isDeduplicateObjects ? new JsonPointerTracker(jsonPointer, 
i) : null, rootType));
+                    isDedup() ? new JsonPointerTracker(jsonPointer, i) : null, 
rootType));
             i++;
         }
         return array;
@@ -1009,7 +1007,7 @@ public class MappingParserImpl implements MappingParser {
             collection.add(JsonValue.NULL.equals(value)
                     ? null
                     : toValue(null, value, null, itemConverter, mapping.arg, 
objectConverter,
-                    isDeduplicateObjects ? new JsonPointerTracker(jsonPointer, 
i) : null, rootType));
+                    isDedup() ? new JsonPointerTracker(jsonPointer, i) : null, 
rootType));
             i++;
         }
 
@@ -1045,7 +1043,7 @@ public class MappingParserImpl implements MappingParser {
                     mapping.factory.getParameterItemConverter()[i],
                     parameterType,
                     mapping.factory.getObjectConverter()[i],
-                    isDeduplicateObjects ? new JsonPointerTracker(jsonPointer, 
paramName) : null,
+                    isDedup() ? new JsonPointerTracker(jsonPointer, paramName) 
: null,
                     mapping.clazz); //X TODO ObjectConverter in 
@JohnzonConverter with Constructors!
             if (objects[i] == null) {
                 objects[i] = getPrimitiveDefault(parameterType);
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 23141be..686f285 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
@@ -76,10 +76,7 @@ public class Mappings {
         public final Field anyField;
         public final Method mapAdder;
         public final Class<?> mapAdderType;
-
-
-        private Boolean deduplicateObjects;
-        private boolean deduplicationEvaluated = false;
+        public boolean deduplicateObjects;
 
         protected ClassMapping(final Class<?> clazz, final AccessMode.Factory 
factory,
                                final Map<String, Getter> getters, final 
Map<String, Setter> setters,
@@ -99,17 +96,15 @@ public class Mappings {
             this.anyField = anyField;
             this.mapAdder = mapAdder;
             this.mapAdderType = mapAdder == null ? null : 
mapAdder.getParameterTypes()[1];
+            this.deduplicateObjects = isDeduplicateObjects();
         }
 
-        public Boolean isDeduplicateObjects() {
-            if (!deduplicationEvaluated) {
-                JohnzonDeduplicateObjects jdo = 
clazz.getAnnotation(JohnzonDeduplicateObjects.class);
-                if (jdo != null){
-                    deduplicateObjects = jdo.value();
-                }
-                deduplicationEvaluated = true;
+        private Boolean isDeduplicateObjects() {
+            final JohnzonDeduplicateObjects jdo = 
clazz.getAnnotation(JohnzonDeduplicateObjects.class);
+            if (jdo != null){
+                return jdo.value();
             }
-            return deduplicateObjects;
+            return false;
         }
 
     }
diff --git 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/JsonPointerTracker.java
 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/JsonPointerTracker.java
index 201a609..fe376c0 100644
--- 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/JsonPointerTracker.java
+++ 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/JsonPointerTracker.java
@@ -27,6 +27,13 @@ import org.apache.johnzon.core.JsonPointerUtil;
  * For use in recursive generator and parser method calls to defer string 
operations.
  */
 public class JsonPointerTracker {
+    public static final JsonPointerTracker ROOT = new JsonPointerTracker(null, 
null) {
+        @Override
+        public String toString() {
+            return "/";
+        }
+    };
+
     private final JsonPointerTracker parent;
     private final String currentNode;
 
@@ -55,13 +62,13 @@ public class JsonPointerTracker {
     public String toString() {
         if (jsonPointer == null) {
             if (parent != null) {
-                if (parent.parent == null) {
+                jsonPointer = (parent != ROOT ? parent + "/" : "/") + 
JsonPointerUtil.encode(currentNode);
+            } else {
+                if (currentNode != null) {
                     jsonPointer = "/" + JsonPointerUtil.encode(currentNode);
                 } else {
-                    jsonPointer = parent.toString() + "/" + 
JsonPointerUtil.encode(currentNode);
+                    jsonPointer = "/";
                 }
-            } else {
-                jsonPointer = "/";
             }
         }
 
diff --git 
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/CircularObjectsTest.java
 
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/CircularObjectsTest.java
index b4c8af6..98665a0 100644
--- 
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/CircularObjectsTest.java
+++ 
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/CircularObjectsTest.java
@@ -20,6 +20,7 @@ package org.apache.johnzon.mapper;
 
 import java.io.StringReader;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.List;
 
 import org.junit.Test;
@@ -42,13 +43,13 @@ public class CircularObjectsTest {
         john.setMarriedTo(marry);
         marry.setMarriedTo(john);
 
-        Mapper mapper = new 
MapperBuilder().setAccessModeName("field").setDeduplicateObjects(true).build();
+        Mapper mapper = new MapperBuilder()
+                .setAccessModeName("field")
+                .setDeduplicateObjects(true)
+                .setAttributeOrder(Comparator.naturalOrder())
+                .build();
         String ser = mapper.writeObjectAsString(john);
-
-        assertNotNull(ser);
-        assertTrue(ser.contains("\"name\":\"John\""));
-        assertTrue(ser.contains("\"marriedTo\":\"/\""));
-        assertTrue(ser.contains("\"name\":\"Marry\""));
+        
assertEquals("{\"kids\":[],\"marriedTo\":{\"kids\":[],\"marriedTo\":\"/\",\"name\":\"Marry\"},\"name\":\"John\"}",
 ser);
 
         // and now de-serialise it back
         Person john2 = mapper.readObject(ser, Person.class);
@@ -164,7 +165,12 @@ public class CircularObjectsTest {
         sue.setFather(karl);
         sue.setMother(andrea);
 
-        Mapper mapper = new 
MapperBuilder().setAccessModeName("field").setDeduplicateObjects(true).build();
+        Mapper mapper = new MapperBuilder()
+                .setAccessModeName("field")
+                .setDeduplicateObjects(true)
+                .setAttributeOrder(Comparator.naturalOrder())
+                .setPretty(true)
+                .build();
 
         // test deep array
         Person[] people = new Person[4];
diff --git 
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/internal/JsonPointerTrackerTest.java
 
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/internal/JsonPointerTrackerTest.java
index 1bcc7f6..15df6d7 100644
--- 
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/internal/JsonPointerTrackerTest.java
+++ 
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/internal/JsonPointerTrackerTest.java
@@ -26,7 +26,7 @@ public class JsonPointerTrackerTest {
 
     @Test
     public void testJsonPointerTracker() {
-        JsonPointerTracker jptRoot = new JsonPointerTracker(null, "/");
+        JsonPointerTracker jptRoot = JsonPointerTracker.ROOT;
 
         Assert.assertEquals("/", jptRoot.toString());
 
diff --git a/pom.xml b/pom.xml
index b5f776f..4699bc6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,7 +49,7 @@
     <checkstyle.version>2.15</checkstyle.version> <!-- checkstyle > 2.15 
version do not support java 6 -->
     <!-- JVM values for surefire plugin -->
     <surefire.jvm.params>-Xms1024m -Xmx2048m 
-Dfile.encoding=UTF-8</surefire.jvm.params>
-    <owb.version>2.0.20</owb.version>
+    <owb.version>2.0.23</owb.version>
   </properties>
 
   <modules>

Reply via email to