Repository: johnzon Updated Branches: refs/heads/master 0f693d825 -> b722755ae
JOHNZON-135 write and read much more complex cyclic data Project: http://git-wip-us.apache.org/repos/asf/johnzon/repo Commit: http://git-wip-us.apache.org/repos/asf/johnzon/commit/b722755a Tree: http://git-wip-us.apache.org/repos/asf/johnzon/tree/b722755a Diff: http://git-wip-us.apache.org/repos/asf/johnzon/diff/b722755a Branch: refs/heads/master Commit: b722755aea7e04bcf3b4bba7f5b8f7f830d50a71 Parents: 0f693d8 Author: Mark Struberg <[email protected]> Authored: Sun Sep 24 22:16:03 2017 +0200 Committer: Mark Struberg <[email protected]> Committed: Sun Sep 24 22:16:03 2017 +0200 ---------------------------------------------------------------------- .../johnzon/jsonb/JohnzonIgnoreNestedTest.java | 32 +++++----- .../java/org/apache/johnzon/mapper/Mapper.java | 13 ++-- .../johnzon/mapper/MappingGeneratorImpl.java | 63 ++++++++++---------- .../johnzon/mapper/MappingParserImpl.java | 15 +++-- .../mapper/internal/JsonPointerTracker.java | 15 ++++- .../johnzon/mapper/CircularObjectsTest.java | 41 +++++++++---- .../johnzon/mapper/JohnzonIgnoreNestedTest.java | 31 ++++------ 7 files changed, 119 insertions(+), 91 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/johnzon/blob/b722755a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonIgnoreNestedTest.java ---------------------------------------------------------------------- diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonIgnoreNestedTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonIgnoreNestedTest.java index fb36804..5f1718d 100644 --- a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonIgnoreNestedTest.java +++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonIgnoreNestedTest.java @@ -34,36 +34,32 @@ public class JohnzonIgnoreNestedTest { final To to = new To(); to.name = "to"; - final From from = new From(); + final Person from = new Person(); from.name = "from"; + from.street = "blastreet 1"; + from.description = "gets ignored"; + + to.person = from; + to.persons = singletonList(from); - to.from = from; - to.froms = singletonList(from); - from.to = to; - from.tos = singletonList(to); final Jsonb jsonb = JsonbProvider.provider().create().build(); - assertEquals("{\"from\":{\"name\":\"from\"},\"froms\":[{\"name\":\"from\"}],\"name\":\"to\"}", jsonb.toJson(to)); - assertEquals("{\"name\":\"from\",\"to\":{\"name\":\"to\"},\"tos\":[{\"name\":\"to\"}]}", jsonb.toJson(from)); + assertEquals("{\"name\":\"to\",\"person\":{\"name\":\"from\"},\"persons\":[\"/person\"]}", jsonb.toJson(to)); } public static class To { public String name; - @JohnzonIgnoreNested(properties = {"to", "tos"}) - public From from; + @JohnzonIgnoreNested(properties = {"street", "description"}) + public Person person; - @JohnzonIgnoreNested(properties = {"to", "tos"}) - public Collection<From> froms; + @JohnzonIgnoreNested(properties = {"street", "description"}) + public Collection<Person> persons; } - public static class From { + public static class Person { public String name; - - @JohnzonIgnoreNested(properties = {"from", "froms"}) - public To to; - - @JohnzonIgnoreNested(properties = {"from", "froms"}) - public Collection<To> tos; + public String street; + public String description; } } http://git-wip-us.apache.org/repos/asf/johnzon/blob/b722755a/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 b245e96..a369b2b 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; @@ -85,7 +86,7 @@ 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, null); + writeObject(object, generator, null, new JsonPointerTracker(null, "/")); } public <T> void writeIterable(final Iterable<T> object, final OutputStream stream) { @@ -94,7 +95,7 @@ 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, null); + writeObject(object, generator, null, new JsonPointerTracker(null, "/")); } public void writeObject(final Object object, final Writer stream) { @@ -125,20 +126,20 @@ public class Mapper implements Closeable { } final JsonGenerator generator = generatorFactory.createGenerator(stream(stream)); - writeObject(object, generator, null); + writeObject(object, generator, null, new JsonPointerTracker(null, "/")); } public void writeObject(final Object object, final OutputStream stream) { final JsonGenerator generator = generatorFactory.createGenerator(stream(stream), config.getEncoding()); - writeObject(object, generator, null); + writeObject(object, generator, null, new JsonPointerTracker(null, "/")); } - private void writeObject(final Object object, final JsonGenerator generator, final Collection<String> ignored) { + private void writeObject(final Object object, final JsonGenerator generator, final Collection<String> ignored, JsonPointerTracker jsonPointer) { MappingGeneratorImpl mappingGenerator = new MappingGeneratorImpl(config, generator, mappings); Throwable originalException = null; try { - mappingGenerator.doWriteObject(object, generator, true, ignored); + mappingGenerator.doWriteObject(object, generator, true, ignored, jsonPointer); } catch (final Error | RuntimeException e) { originalException = e; } finally { http://git-wip-us.apache.org/repos/asf/johnzon/blob/b722755a/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 f23344c..6d73dfa 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java @@ -18,8 +18,8 @@ */ package org.apache.johnzon.mapper; -import org.apache.johnzon.core.JsonPointerUtil; import org.apache.johnzon.mapper.internal.AdapterKey; +import org.apache.johnzon.mapper.internal.JsonPointerTracker; import javax.json.JsonValue; import javax.json.stream.JsonGenerator; @@ -57,12 +57,12 @@ public class MappingGeneratorImpl implements MappingGenerator { } else if (object instanceof JsonValue) { generator.write((JsonValue) object); } else { - doWriteObject(object, generator, false, null); + doWriteObject(object, generator, false, null, new JsonPointerTracker(null, "/")); } return this; } - public void doWriteObject(Object object, JsonGenerator generator, boolean writeBody, final Collection<String> ignoredProperties) { + public void doWriteObject(Object object, JsonGenerator generator, boolean writeBody, final Collection<String> ignoredProperties, JsonPointerTracker jsonPointer) { try { if (object instanceof Map) { @@ -89,7 +89,7 @@ public class MappingGeneratorImpl implements MappingGenerator { } if (object instanceof Iterable) { - doWriteIterable((Iterable) object, ignoredProperties); + doWriteIterable((Iterable) object, ignoredProperties, new JsonPointerTracker(null, "/")); return; } @@ -101,7 +101,7 @@ public class MappingGeneratorImpl implements MappingGenerator { if (writeBody && objectConverter != null) { objectConverter.writeJson(object, this); } else { - doWriteObjectBody(object, ignoredProperties, "/"); + doWriteObjectBody(object, ignoredProperties, jsonPointer); } if (writeBody) { @@ -228,11 +228,11 @@ public class MappingGeneratorImpl implements MappingGenerator { } - private void doWriteObjectBody(final Object object, final Collection<String> ignored, String jsonPointer) + private void doWriteObjectBody(final Object object, final Collection<String> ignored, JsonPointerTracker jsonPointer) throws IllegalAccessException, InvocationTargetException { if (jsonPointer != null) { - jsonPointers.put(object, jsonPointer); + jsonPointers.put(object, jsonPointer.toString()); } final Class<?> objectClass = object.getClass(); @@ -246,7 +246,7 @@ public class MappingGeneratorImpl implements MappingGenerator { return; } if (classMapping.adapter != null) { - doWriteObjectBody(classMapping.adapter.to(object), ignored, null); + doWriteObjectBody(classMapping.adapter.to(object), ignored, jsonPointer); return; } @@ -291,7 +291,7 @@ public class MappingGeneratorImpl implements MappingGenerator { val, getter.objectConverter, getter.ignoreNested, - nestJsonPointer(jsonPointer, getterEntry.getKey())); + new JsonPointerTracker(jsonPointer, getterEntry.getKey())); } } @@ -305,17 +305,6 @@ public class MappingGeneratorImpl implements MappingGenerator { } } - private String nestJsonPointer(String jsonPointer, String attribName) { - if (jsonPointer == null) { - return null; - } - if (jsonPointer.length() == 1) { - // the root element - return jsonPointer + attribName; - } else { - return jsonPointer + "/" + JsonPointerUtil.encode(attribName); - } - } private void writeValue(final Class<?> type, final boolean primitive, final boolean array, @@ -324,7 +313,7 @@ public class MappingGeneratorImpl implements MappingGenerator { final String key, final Object value, final ObjectConverter.Writer objectConverter, final Collection<String> ignoredProperties, - final String jsonPointer) + final JsonPointerTracker jsonPointer) throws InvocationTargetException, IllegalAccessException { if (config.getSerializeValueFilter().shouldIgnore(key, value)) { return; @@ -348,14 +337,26 @@ 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, ignoredProperties); + String valJsonPointer = jsonPointers.get(o); + if (valJsonPointer != null) { + writePrimitives(valJsonPointer); + } else { + writeItem(itemConverter != null ? itemConverter.from(o) : o, ignoredProperties, new JsonPointerTracker(jsonPointer, i)); + } } generator.writeEnd(); return; } else if (collection) { generator.writeStartArray(key); + int i = 0; for (final Object o : Collection.class.cast(value)) { - writeItem(itemConverter != null ? itemConverter.from(o) : o, ignoredProperties); + String valJsonPointer = jsonPointers.get(o); + if (valJsonPointer != null) { + writePrimitives(valJsonPointer); + } else { + writeItem(itemConverter != null ? itemConverter.from(o) : o, ignoredProperties, new JsonPointerTracker(jsonPointer, i)); + } + i++; } generator.writeEnd(); return; @@ -374,7 +375,7 @@ public class MappingGeneratorImpl implements MappingGenerator { if (writePrimitives(key, adapted.getClass(), adapted)) { return; } - writeValue(String.class, true, false, false, false, null, key, adapted, null, ignoredProperties, null); + writeValue(String.class, true, false, false, false, null, key, adapted, null, ignoredProperties, jsonPointer); return; } else { @@ -399,10 +400,10 @@ public class MappingGeneratorImpl implements MappingGenerator { } } - private void writeItem(final Object o, final Collection<String> ignoredProperties) { + private void writeItem(final Object o, final Collection<String> ignoredProperties, JsonPointerTracker jsonPointer) { if (!writePrimitives(o)) { if (Collection.class.isInstance(o)) { - doWriteIterable(Collection.class.cast(o), ignoredProperties); + doWriteIterable(Collection.class.cast(o), ignoredProperties, jsonPointer); } else if (o != null && o.getClass().isArray()) { final int length = Array.getLength(o); if (length > 0 || !config.isSkipEmptyArray()) { @@ -412,7 +413,7 @@ public class MappingGeneratorImpl implements MappingGenerator { if (t == null) { generator.writeNull(); } else { - writeItem(t, ignoredProperties); + writeItem(t, ignoredProperties, new JsonPointerTracker(jsonPointer, i)); } } generator.writeEnd(); @@ -420,16 +421,17 @@ public class MappingGeneratorImpl implements MappingGenerator { } else if (o == null) { generator.writeNull(); } else { - doWriteObject(o, generator, true, ignoredProperties); + doWriteObject(o, generator, true, ignoredProperties, jsonPointer); } } } - private <T> void doWriteIterable(final Iterable<T> object, final Collection<String> ignoredProperties) { + 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)); @@ -437,9 +439,10 @@ public class MappingGeneratorImpl implements MappingGenerator { if (t == null) { generator.writeNull(); } else { - writeItem(t, ignoredProperties); + writeItem(t, ignoredProperties, new JsonPointerTracker(jsonPointer, i)); } } + i++; } generator.writeEnd(); } http://git-wip-us.apache.org/repos/asf/johnzon/blob/b722755a/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 4d111db..074cc02 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 @@ -545,12 +545,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 - Object o = jsonPointers.get(string); - if (o != null) { - return o; - } else { - return convertTo(Class.class.cast(type), string); + 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); } @@ -613,8 +614,10 @@ 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, jsonPointer)); + collection.add(JsonValue.NULL.equals(value) ? null : toObject(null, value, mapping.arg, itemConverter, new JsonPointerTracker(jsonPointer, i))); + i++; } if (EnumSet.class == mapping.raw) { http://git-wip-us.apache.org/repos/asf/johnzon/blob/b722755a/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 index 9aa713e..201a609 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 @@ -18,6 +18,8 @@ */ package org.apache.johnzon.mapper.internal; +import org.apache.johnzon.core.JsonPointerUtil; + /** * Internal class to easily collect information about the 'depth' of a json object * without having to eagerly construct it. @@ -40,14 +42,23 @@ public class JsonPointerTracker { this.currentNode = currentNode; } + /** + * For Arrays and Lists. + * @param jsonPointer + * @param i current counter number + */ + public JsonPointerTracker(JsonPointerTracker jsonPointer, int i) { + this(jsonPointer, Integer.toString(i)); + } + @Override public String toString() { if (jsonPointer == null) { if (parent != null) { if (parent.parent == null) { - jsonPointer = "/" + currentNode; + jsonPointer = "/" + JsonPointerUtil.encode(currentNode); } else { - jsonPointer = parent.toString() + "/" + currentNode; + jsonPointer = parent.toString() + "/" + JsonPointerUtil.encode(currentNode); } } else { jsonPointer = "/"; http://git-wip-us.apache.org/repos/asf/johnzon/blob/b722755a/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 index 272cd45..af0414a 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 @@ -24,6 +24,7 @@ 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.assertNull; import static org.junit.Assert.assertTrue; /** @@ -82,17 +83,35 @@ public class CircularObjectsTest { 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()); + + { + // test karl + 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()); + } + + { + // test Sue + String sueJson = mapper.writeObjectAsString(sue); + Person sue2 = mapper.readObject(sueJson, Person.class); + + assertEquals("Sue", sue2.getName()); + assertNull(sue2.getMarriedTo()); + assertEquals("Andrea", sue2.getMother().getName()); + assertEquals("Karl", sue2.getFather().getName()); + + assertEquals(sue2.getMother().getKids().get(0), sue2.getFather().getKids().get(0)); + assertEquals(sue2.getMother().getKids().get(1), sue2.getFather().getKids().get(1)); + } } public static class Person { http://git-wip-us.apache.org/repos/asf/johnzon/blob/b722755a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/JohnzonIgnoreNestedTest.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/JohnzonIgnoreNestedTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/JohnzonIgnoreNestedTest.java index 986c744..1c914d0 100644 --- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/JohnzonIgnoreNestedTest.java +++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/JohnzonIgnoreNestedTest.java @@ -32,36 +32,31 @@ public class JohnzonIgnoreNestedTest { final To to = new To(); to.name = "to"; - final From from = new From(); + final Person from = new Person(); from.name = "from"; + from.street = "blastreet 1"; + from.description = "gets ignored"; - to.from = from; - to.froms = singletonList(from); - from.to = to; - from.tos = singletonList(to); + to.person = from; + to.persons = singletonList(from); final Mapper mapper = new MapperBuilder().setAttributeOrder(Comparator.naturalOrder()).build(); - assertEquals("{\"from\":{\"name\":\"from\"},\"froms\":[{\"name\":\"from\"}],\"name\":\"to\"}", mapper.writeObjectAsString(to)); - assertEquals("{\"name\":\"from\",\"to\":{\"name\":\"to\"},\"tos\":[{\"name\":\"to\"}]}", mapper.writeObjectAsString(from)); + assertEquals("{\"name\":\"to\",\"person\":{\"name\":\"from\"},\"persons\":[\"/person\"]}", mapper.writeObjectAsString(to)); } public static class To { public String name; - @JohnzonIgnoreNested(properties = {"to", "tos"}) - public From from; + @JohnzonIgnoreNested(properties = {"street", "description"}) + public Person person; - @JohnzonIgnoreNested(properties = {"to", "tos"}) - public Collection<From> froms; + @JohnzonIgnoreNested(properties = {"street", "description"}) + public Collection<Person> persons; } - public static class From { + public static class Person { public String name; - - @JohnzonIgnoreNested(properties = {"from", "froms"}) - public To to; - - @JohnzonIgnoreNested(properties = {"from", "froms"}) - public Collection<To> tos; + public String street; + public String description; } }
