You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by st...@apache.org on 2017/09/24 14:26:21 UTC
johnzon git commit: JOHNZON-135 deserialise JsonPointers back to
previously mapped objects
Repository: johnzon
Updated Branches:
refs/heads/master 0091f2019 -> 0f693d825
JOHNZON-135 deserialise JsonPointers back to previously mapped objects
Project: http://git-wip-us.apache.org/repos/asf/johnzon/repo
Commit: http://git-wip-us.apache.org/repos/asf/johnzon/commit/0f693d82
Tree: http://git-wip-us.apache.org/repos/asf/johnzon/tree/0f693d82
Diff: http://git-wip-us.apache.org/repos/asf/johnzon/diff/0f693d82
Branch: refs/heads/master
Commit: 0f693d8257ea70d13517bbacc1e92a499aa3df6f
Parents: 0091f20
Author: Mark Struberg <st...@apache.org>
Authored: Sun Sep 24 15:29:08 2017 +0200
Committer: Mark Struberg <st...@apache.org>
Committed: Sun Sep 24 16:25:52 2017 +0200
----------------------------------------------------------------------
.../johnzon/mapper/MappingParserImpl.java | 86 +++++++----
.../mapper/internal/JsonPointerTracker.java | 60 ++++++++
.../johnzon/mapper/CircularExceptionTest.java | 36 -----
.../johnzon/mapper/CircularObjectsTest.java | 153 +++++++++++++++++++
.../mapper/internal/JsonPointerTrackerTest.java | 39 +++++
5 files changed, 307 insertions(+), 67 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/johnzon/blob/0f693d82/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 7e3d574..4d111db 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
@@ -23,6 +23,7 @@ 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;
@@ -89,6 +90,13 @@ public class MappingParserImpl implements MappingParser {
private final JsonReader jsonReader;
+ /**
+ * Used for de-referencing JsonPointers during deserialisation.
+ * key: JsonPointer
+ * value: already deserialised Object
+ */
+ private Map<String, Object> jsonPointers = new HashMap<>();
+
public MappingParserImpl(MapperConfig config, Mappings mappings, JsonReader jsonReader) {
this.config = config;
@@ -123,7 +131,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, new JsonPointerTracker(null, "/"));
}
if (JsonString.class.isInstance(jsonValue) && (targetType == String.class || targetType == Object.class)) {
return (T) JsonString.class.cast(jsonValue).getString();
@@ -152,7 +160,7 @@ public class MappingParserImpl implements MappingParser {
if (Class.class.isInstance(targetType) && ((Class) targetType).isArray()) {
final Class componentType = ((Class) targetType).getComponentType();
- return (T) buildArrayWithComponentType(jsonArray, componentType, config.findAdapter(componentType));
+ return (T) buildArrayWithComponentType(jsonArray, componentType, config.findAdapter(componentType), new JsonPointerTracker(null, "/"));
}
if (ParameterizedType.class.isInstance(targetType)) {
@@ -163,10 +171,10 @@ 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);
+ return (T) mapCollection(mapping, jsonArray, Class.class.isInstance(arg) ? config.findAdapter(Class.class.cast(arg)) : null, new JsonPointerTracker(null, "/"));
}
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, new JsonPointerTracker(null, "/")))));
}
}
if (JsonValue.NULL.equals(jsonValue)) {
@@ -182,7 +190,7 @@ 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);
@@ -241,7 +249,7 @@ public class MappingParserImpl implements MappingParser {
} 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));
}
}
return map;
@@ -250,7 +258,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));
}
return map;
}
@@ -280,8 +288,15 @@ public class MappingParserImpl implements MappingParser {
}
}
- final Object t = classMapping.factory.getParameterTypes().length == 0 ?
- classMapping.factory.create(null) : classMapping.factory.create(createParameters(classMapping, object));
+ 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
+ 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();
@@ -308,7 +323,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()));
if (convertedValue != null) {
setterMethod.write(t, convertedValue);
}
@@ -319,7 +335,7 @@ 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, new JsonPointerTracker(jsonPointer, entry.getKey())));
} catch (final IllegalAccessException e) {
throw new IllegalStateException(e);
} catch (final InvocationTargetException e) {
@@ -350,7 +366,7 @@ public class MappingParserImpl implements MappingParser {
}
}
- private Object convertTo(final Adapter converter, final JsonValue jsonValue) {
+ 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?
@@ -361,7 +377,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);
}
@@ -432,7 +448,7 @@ 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, JsonPointerTracker jsonPointer) {
if (jsonValue == null || JsonValue.NULL.equals(jsonValue)) {
return null;
}
@@ -475,13 +491,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, jsonPointer);
} else if (JsonNumber.class.isInstance(jsonValue)) {
if (JsonNumber.class == type) {
return jsonValue;
@@ -527,7 +544,13 @@ public class MappingParserImpl implements MappingParser {
final String string = JsonString.class.cast(jsonValue).getString();
if (itemConverter == null) {
- return convertTo(Class.class.cast(type), string);
+ // check whether we have a jsonPointer to a previously deserialised object
+ Object o = jsonPointers.get(string);
+ if (o != null) {
+ return o;
+ } else {
+ return convertTo(Class.class.cast(type), string);
+ }
} else {
return itemConverter.to(string);
}
@@ -536,40 +559,40 @@ 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 JsonPointerTracker jsonPointer) {
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);
}
}
if (ParameterizedType.class.isInstance(type)) {
final Mappings.CollectionMapping mapping = mappings.findCollectionMapping(ParameterizedType.class.cast(type));
if (mapping != null) {
- return mapCollection(mapping, jsonArray, itemConverter);
+ return mapCollection(mapping, jsonArray, itemConverter, jsonPointer);
}
}
if (Object.class == type) {
- return buildArray(ANY_LIST, jsonArray, null);
+ return buildArray(ANY_LIST, jsonArray, null, jsonPointer);
}
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, JsonPointerTracker jsonPointer) {
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, jsonPointer));
}
return array;
}
private <T> Collection<T> mapCollection(final Mappings.CollectionMapping mapping, final JsonArray jsonArray,
- final Adapter itemConverter) {
+ final Adapter itemConverter, JsonPointerTracker jsonPointer) {
final Collection collection;
if (SortedSet.class == mapping.raw || NavigableSet.class == mapping.raw || TreeSet.class == mapping.raw) {
@@ -591,7 +614,7 @@ public class MappingParserImpl implements MappingParser {
}
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 : toObject(null, value, mapping.arg, itemConverter, jsonPointer));
}
if (EnumSet.class == mapping.raw) {
@@ -609,25 +632,26 @@ 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]),
+ object.get(paramName),
mapping.factory.getParameterConverter()[i],
mapping.factory.getParameterItemConverter()[i],
mapping.factory.getParameterTypes()[i],
- null); //X TODO ObjectConverter in @JOhnzonConverter with Constructors!
+ null, new JsonPointerTracker(jsonPointer, paramName)); //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, JsonPointerTracker jsonPointer) {
if (objectConverter != null) {
@@ -638,9 +662,9 @@ public class MappingParserImpl implements MappingParser {
}
}
- return converter == null ? toObject(baseInstance, jsonValue, type, itemConverter)
+ return converter == null ? toObject(baseInstance, jsonValue, type, itemConverter, jsonPointer)
: jsonValue.getValueType() == JsonValue.ValueType.STRING ? converter.to(JsonString.class.cast(jsonValue).getString())
- : convertTo(converter, jsonValue);
+ : convertTo(converter, jsonValue, jsonPointer);
}
http://git-wip-us.apache.org/repos/asf/johnzon/blob/0f693d82/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/JsonPointerTracker.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..9aa713e
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/JsonPointerTracker.java
@@ -0,0 +1,60 @@
+/*
+ * 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.internal;
+
+/**
+ * Internal class to easily collect information about the 'depth' of a json object
+ * without having to eagerly construct it.
+ *
+ * For use in recursive generator and parser method calls to defer string operations.
+ */
+public class JsonPointerTracker {
+ private final JsonPointerTracker parent;
+ private final String currentNode;
+
+ private String jsonPointer;
+
+
+ /**
+ * @param parent or {@code null} if this is the root object
+ * @param currentNode the name of the attribute or "/" for the root object
+ */
+ public JsonPointerTracker(JsonPointerTracker parent, String currentNode) {
+ this.parent = parent;
+ this.currentNode = currentNode;
+ }
+
+ @Override
+ public String toString() {
+ if (jsonPointer == null) {
+ if (parent != null) {
+ if (parent.parent == null) {
+ jsonPointer = "/" + currentNode;
+ } else {
+ jsonPointer = parent.toString() + "/" + currentNode;
+ }
+ } else {
+ jsonPointer = "/";
+ }
+ }
+
+ return jsonPointer;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/johnzon/blob/0f693d82/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/CircularExceptionTest.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/CircularExceptionTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/CircularExceptionTest.java
index 17fe5f7..d6da4cb 100644
--- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/CircularExceptionTest.java
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/CircularExceptionTest.java
@@ -18,7 +18,6 @@
*/
package org.apache.johnzon.mapper;
-import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.assertTrue;
@@ -34,39 +33,4 @@ public class CircularExceptionTest {
assertTrue(serialized.contains("\"stackTrace\":[{"));
}
- @Test
- public void testCyclicPerson() {
- Person john = new Person("John");
- Person marry = new Person("Marry");
-
- john.setMarriedTo(marry);
- marry.setMarriedTo(john);
-
- String ser = new MapperBuilder().setAccessModeName("field").build().writeObjectAsString(john);
- Assert.assertNotNull(ser);
- assertTrue(ser.contains("\"name\":\"John\""));
- assertTrue(ser.contains("\"marriedTo\":\"/\""));
- assertTrue(ser.contains("\"name\":\"Marry\""));
- }
-
- public static class Person {
- private final String name;
- private Person marriedTo;
-
- public Person(String name) {
- this.name = name;
- }
-
- public String getName() {
- return name;
- }
-
- public Person getMarriedTo() {
- return marriedTo;
- }
-
- public void setMarriedTo(Person marriedTo) {
- this.marriedTo = marriedTo;
- }
- }
}
http://git-wip-us.apache.org/repos/asf/johnzon/blob/0f693d82/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/CircularObjectsTest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..272cd45
--- /dev/null
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/CircularObjectsTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.util.ArrayList;
+import java.util.List;
+
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test serialising objects which contain the same Object multiple times,
+ * sometimes even with cycles.
+ */
+public class CircularObjectsTest {
+
+ @Test
+ public void testSimpleCyclicPerson() {
+ Person john = new Person("John");
+ Person marry = new Person("Marry");
+
+ john.setMarriedTo(marry);
+ marry.setMarriedTo(john);
+
+ Mapper mapper = new MapperBuilder().setAccessModeName("field").build();
+ String ser = mapper.writeObjectAsString(john);
+
+ assertNotNull(ser);
+ assertTrue(ser.contains("\"name\":\"John\""));
+ assertTrue(ser.contains("\"marriedTo\":\"/\""));
+ assertTrue(ser.contains("\"name\":\"Marry\""));
+
+ // and now de-serialise it back
+ Person john2 = mapper.readObject(ser, Person.class);
+ assertNotNull(john2);
+ assertEquals("John", john2.getName());
+
+ Person marry2 = john2.getMarriedTo();
+ assertNotNull(marry2);
+ assertEquals("Marry", marry2.getName());
+
+ assertEquals(john2, marry2.getMarriedTo());
+ }
+
+ @Test
+ public void testComplexCyclicPerson() {
+ Person karl = new Person("Karl");
+ Person andrea = new Person("Andrea");
+ Person lu = new Person("Lu");
+ Person sue = new Person("Sue");
+
+ karl.setMarriedTo(andrea);
+ karl.getKids().add(lu);
+ karl.getKids().add(sue);
+
+ andrea.setMarriedTo(karl);
+ andrea.getKids().add(lu);
+ andrea.getKids().add(sue);
+
+ lu.setFather(karl);
+ lu.setMother(andrea);
+
+ sue.setFather(karl);
+ sue.setMother(andrea);
+
+ Mapper mapper = new MapperBuilder().setAccessModeName("field").build();
+ String karlJson = mapper.writeObjectAsString(karl);
+ Person karl2 = mapper.readObject(karlJson, Person.class);
+ assertEquals("Karl", karl2.getName());
+ assertEquals("Andrea", karl2.getMarriedTo().getName());
+ assertEquals(karl2, karl2.getMarriedTo().getMarriedTo());
+ assertEquals(2, karl2.getKids().size());
+ assertEquals("Lu", karl2.getKids().get(0).getName());
+ assertEquals("Sue", karl2.getKids().get(1).getName());
+ assertEquals(2, karl2.getMarriedTo().getKids().size());
+ assertEquals("Lu", karl2.getMarriedTo().getKids().get(0).getName());
+ assertEquals("Sue", karl2.getMarriedTo().getKids().get(1).getName());
+ }
+
+ public static class Person {
+ private String name;
+ private Person marriedTo;
+ private Person mother;
+ private Person father;
+ private List<Person> kids = new ArrayList<>();
+
+ public Person() {
+ }
+
+ public Person(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Person getMarriedTo() {
+ return marriedTo;
+ }
+
+ public void setMarriedTo(Person marriedTo) {
+ this.marriedTo = marriedTo;
+ }
+
+ public Person getMother() {
+ return mother;
+ }
+
+ public void setMother(Person mother) {
+ this.mother = mother;
+ }
+
+ public Person getFather() {
+ return father;
+ }
+
+ public void setFather(Person father) {
+ this.father = father;
+ }
+
+ public List<Person> getKids() {
+ return kids;
+ }
+
+ public void setKids(List<Person> kids) {
+ this.kids = kids;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/johnzon/blob/0f693d82/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/internal/JsonPointerTrackerTest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..1bcc7f6
--- /dev/null
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/internal/JsonPointerTrackerTest.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.internal;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class JsonPointerTrackerTest {
+
+
+ @Test
+ public void testJsonPointerTracker() {
+ JsonPointerTracker jptRoot = new JsonPointerTracker(null, "/");
+
+ Assert.assertEquals("/", jptRoot.toString());
+
+ JsonPointerTracker jptAttrL1 = new JsonPointerTracker(jptRoot, "attrL1");
+ JsonPointerTracker jptAttrL2 = new JsonPointerTracker(jptAttrL1, "attrL2");
+
+ Assert.assertEquals("/attrL1/attrL2", jptAttrL2.toString());
+ Assert.assertEquals("/attrL1", jptAttrL1.toString());
+ }
+}