You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by rm...@apache.org on 2017/04/18 19:18:04 UTC
johnzon git commit: JOHNZON-114 @JohnzonIgnoreNested support to cut
common cycles (JPA for instance)
Repository: johnzon
Updated Branches:
refs/heads/master dd294bd13 -> dc7306d0e
JOHNZON-114 @JohnzonIgnoreNested support to cut common cycles (JPA for instance)
Project: http://git-wip-us.apache.org/repos/asf/johnzon/repo
Commit: http://git-wip-us.apache.org/repos/asf/johnzon/commit/dc7306d0
Tree: http://git-wip-us.apache.org/repos/asf/johnzon/tree/dc7306d0
Diff: http://git-wip-us.apache.org/repos/asf/johnzon/diff/dc7306d0
Branch: refs/heads/master
Commit: dc7306d0e22647e7d48ff1e0958f984bbc369554
Parents: dd294bd
Author: rmannibucau <rm...@apache.org>
Authored: Tue Apr 18 21:17:52 2017 +0200
Committer: rmannibucau <rm...@apache.org>
Committed: Tue Apr 18 21:17:52 2017 +0200
----------------------------------------------------------------------
.../johnzon/jsonb/JohnzonIgnoreNestedTest.java | 69 ++++++++++++++++++++
.../johnzon/mapper/JohnzonIgnoreNested.java | 39 +++++++++++
.../java/org/apache/johnzon/mapper/Mapper.java | 21 +++---
.../johnzon/mapper/MappingGeneratorImpl.java | 43 ++++++------
.../org/apache/johnzon/mapper/Mappings.java | 13 ++--
.../johnzon/mapper/JohnzonIgnoreNestedTest.java | 67 +++++++++++++++++++
6 files changed, 220 insertions(+), 32 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/johnzon/blob/dc7306d0/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
new file mode 100644
index 0000000..fb36804
--- /dev/null
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/JohnzonIgnoreNestedTest.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.jsonb;
+
+import org.apache.johnzon.mapper.JohnzonIgnoreNested;
+import org.junit.Test;
+
+import javax.json.bind.Jsonb;
+import javax.json.bind.spi.JsonbProvider;
+import java.util.Collection;
+
+import static java.util.Collections.singletonList;
+import static org.junit.Assert.assertEquals;
+
+public class JohnzonIgnoreNestedTest {
+ @Test
+ public void ignoreNested() {
+ final To to = new To();
+ to.name = "to";
+
+ final From from = new From();
+ from.name = "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));
+ }
+
+ public static class To {
+ public String name;
+
+ @JohnzonIgnoreNested(properties = {"to", "tos"})
+ public From from;
+
+ @JohnzonIgnoreNested(properties = {"to", "tos"})
+ public Collection<From> froms;
+ }
+
+ public static class From {
+ public String name;
+
+ @JohnzonIgnoreNested(properties = {"from", "froms"})
+ public To to;
+
+ @JohnzonIgnoreNested(properties = {"from", "froms"})
+ public Collection<To> tos;
+ }
+}
http://git-wip-us.apache.org/repos/asf/johnzon/blob/dc7306d0/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonIgnoreNested.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonIgnoreNested.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonIgnoreNested.java
new file mode 100644
index 0000000..f1d16a7
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonIgnoreNested.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.johnzon.mapper;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Only used during serialization for now.
+ */
+@Target({ METHOD, FIELD, ANNOTATION_TYPE })
+@Retention(RUNTIME)
+public @interface JohnzonIgnoreNested {
+ /**
+ * @return the array of properties to avoid in the nested type.
+ */
+ String[] properties() default {};
+}
http://git-wip-us.apache.org/repos/asf/johnzon/blob/dc7306d0/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 9fe2bc8..b245e96 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
@@ -85,7 +85,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);
+ writeObject(object, generator, null);
}
public <T> void writeIterable(final Iterable<T> object, final OutputStream stream) {
@@ -94,7 +94,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);
+ writeObject(object, generator, null);
}
public void writeObject(final Object object, final Writer stream) {
@@ -125,21 +125,21 @@ public class Mapper implements Closeable {
}
final JsonGenerator generator = generatorFactory.createGenerator(stream(stream));
- writeObject(object, generator);
+ writeObject(object, generator, null);
}
public void writeObject(final Object object, final OutputStream stream) {
final JsonGenerator generator = generatorFactory.createGenerator(stream(stream), config.getEncoding());
- writeObject(object, generator);
+ writeObject(object, generator, null);
}
- private void writeObject(final Object object, final JsonGenerator generator) {
+ private void writeObject(final Object object, final JsonGenerator generator, final Collection<String> ignored) {
MappingGeneratorImpl mappingGenerator = new MappingGeneratorImpl(config, generator, mappings);
- RuntimeException originalException = null;
+ Throwable originalException = null;
try {
- mappingGenerator.doWriteObject(object, generator, true);
- } catch (RuntimeException e) {
+ mappingGenerator.doWriteObject(object, generator, true, ignored);
+ } catch (final Error | RuntimeException e) {
originalException = e;
} finally {
@@ -148,7 +148,10 @@ public class Mapper implements Closeable {
} catch (JsonException e) {
if (originalException != null) {
- throw originalException;
+ if (RuntimeException.class.isInstance(originalException)) {
+ throw RuntimeException.class.cast(originalException);
+ }
+ throw Error.class.cast(originalException); // stackoverflow falls here
} else {
throw e;
}
http://git-wip-us.apache.org/repos/asf/johnzon/blob/dc7306d0/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
index 38b5315..107307a 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
@@ -54,12 +54,12 @@ public class MappingGeneratorImpl implements MappingGenerator {
} else if (object instanceof JsonValue) {
generator.write((JsonValue) object);
} else {
- doWriteObject(object, generator, false);
+ doWriteObject(object, generator, false, null);
}
return this;
}
- public void doWriteObject(Object object, JsonGenerator generator, boolean writeBody) {
+ public void doWriteObject(Object object, JsonGenerator generator, boolean writeBody, final Collection<String> ignoredProperties) {
try {
if (object instanceof Map) {
if (writeBody) {
@@ -85,7 +85,7 @@ public class MappingGeneratorImpl implements MappingGenerator {
}
if (object instanceof Iterable) {
- doWriteIterable((Iterable) object);
+ doWriteIterable((Iterable) object, ignoredProperties);
return;
}
@@ -97,7 +97,7 @@ public class MappingGeneratorImpl implements MappingGenerator {
if (writeBody && objectConverter != null) {
objectConverter.writeJson(object, this);
} else {
- doWriteObjectBody(object);
+ doWriteObjectBody(object, ignoredProperties);
}
if (writeBody) {
@@ -132,7 +132,7 @@ public class MappingGeneratorImpl implements MappingGenerator {
final boolean map = clazz || primitive || array || collection ? false : Map.class.isAssignableFrom(valueClass);
writeValue(valueClass,
primitive, array, collection, map, itemConverter,
- key == null ? "null" : key.toString(), value, null);
+ key == null ? "null" : key.toString(), value, null, null);
}
return generator;
}
@@ -224,7 +224,7 @@ public class MappingGeneratorImpl implements MappingGenerator {
}
- private void doWriteObjectBody(final Object object) throws IllegalAccessException, InvocationTargetException {
+ private void doWriteObjectBody(final Object object, final Collection<String> ignored) throws IllegalAccessException, InvocationTargetException {
final Class<?> objectClass = object.getClass();
final Mappings.ClassMapping classMapping = mappings.findOrCreateClassMapping(objectClass);
if (classMapping == null) {
@@ -236,12 +236,15 @@ public class MappingGeneratorImpl implements MappingGenerator {
return;
}
if (classMapping.adapter != null) {
- doWriteObjectBody(classMapping.adapter.to(object));
+ doWriteObjectBody(classMapping.adapter.to(object), ignored);
return;
}
for (final Map.Entry<String, Mappings.Getter> getterEntry : classMapping.getters.entrySet()) {
final Mappings.Getter getter = getterEntry.getValue();
+ if (ignored != null && ignored.contains(getterEntry.getKey())) {
+ continue;
+ }
if (getter.version >= 0 && config.getVersion() >= getter.version) {
continue;
}
@@ -268,7 +271,8 @@ public class MappingGeneratorImpl implements MappingGenerator {
getter.collection, getter.map,
getter.itemConverter,
getterEntry.getKey(),
- val, getter.objectConverter);
+ val, getter.objectConverter,
+ getter.ignoreNested);
}
// @JohnzonAny doesn't respect comparator since it is a map and not purely in the model we append it after and
@@ -286,7 +290,8 @@ public class MappingGeneratorImpl implements MappingGenerator {
final boolean collection, final boolean map,
final Adapter itemConverter,
final String key, final Object value,
- final ObjectConverter.Writer objectConverter) throws InvocationTargetException, IllegalAccessException {
+ final ObjectConverter.Writer objectConverter,
+ final Collection<String> ignoredProperties) throws InvocationTargetException, IllegalAccessException {
if (array) {
final int length = Array.getLength(value);
if (length == 0 && config.isSkipEmptyArray()) {
@@ -306,14 +311,14 @@ 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);
+ writeItem(itemConverter != null ? itemConverter.from(o) : o, ignoredProperties);
}
generator.writeEnd();
return;
} else if (collection) {
generator.writeStartArray(key);
for (final Object o : Collection.class.cast(value)) {
- writeItem(itemConverter != null ? itemConverter.from(o) : o);
+ writeItem(itemConverter != null ? itemConverter.from(o) : o, ignoredProperties);
}
generator.writeEnd();
return;
@@ -332,7 +337,7 @@ public class MappingGeneratorImpl implements MappingGenerator {
if (writePrimitives(key, adapted.getClass(), adapted)) {
return;
}
- writeValue(String.class, true, false, false, false, null, key, adapted, null);
+ writeValue(String.class, true, false, false, false, null, key, adapted, null, ignoredProperties);
return;
} else {
@@ -352,15 +357,15 @@ public class MappingGeneratorImpl implements MappingGenerator {
return;
}
generator.writeStartObject(key);
- doWriteObjectBody(value);
+ doWriteObjectBody(value, ignoredProperties);
generator.writeEnd();
}
}
- private void writeItem(final Object o) {
+ private void writeItem(final Object o, final Collection<String> ignoredProperties) {
if (!writePrimitives(o)) {
if (Collection.class.isInstance(o)) {
- doWriteIterable(Collection.class.cast(o));
+ doWriteIterable(Collection.class.cast(o), ignoredProperties);
} else if (o != null && o.getClass().isArray()) {
final int length = Array.getLength(o);
if (length > 0 || !config.isSkipEmptyArray()) {
@@ -370,7 +375,7 @@ public class MappingGeneratorImpl implements MappingGenerator {
if (t == null) {
generator.writeNull();
} else {
- writeItem(t);
+ writeItem(t, ignoredProperties);
}
}
generator.writeEnd();
@@ -378,12 +383,12 @@ public class MappingGeneratorImpl implements MappingGenerator {
} else if (o == null) {
generator.writeNull();
} else {
- doWriteObject(o, generator, true);
+ doWriteObject(o, generator, true, ignoredProperties);
}
}
}
- private <T> void doWriteIterable(final Iterable<T> object) {
+ private <T> void doWriteIterable(final Iterable<T> object, final Collection<String> ignoredProperties) {
if (object == null) {
generator.writeStartArray().writeEnd();
} else {
@@ -395,7 +400,7 @@ public class MappingGeneratorImpl implements MappingGenerator {
if (t == null) {
generator.writeNull();
} else {
- writeItem(t);
+ writeItem(t, ignoredProperties);
}
}
}
http://git-wip-us.apache.org/repos/asf/johnzon/blob/dc7306d0/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
index 35dea61..51ae62c 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
@@ -104,18 +104,20 @@ public class Mappings {
public final boolean array;
public final boolean map;
public final boolean collection;
+ public final Collection<String> ignoreNested;
public Getter(final AccessMode.Reader reader,
final boolean primitive, final boolean array,
final boolean collection, final boolean map,
final MapperConverter converter,
final ObjectConverter.Writer providedObjectConverter,
- final int version) {
+ final int version, final String[] ignoreNested) {
this.reader = reader;
this.version = version;
this.array = array;
this.collection = collection;
this.primitive = primitive;
+ this.ignoreNested = ignoreNested == null || ignoreNested.length == 0 ? null : new HashSet<>(asList(ignoreNested));
Adapter theConverter = null;
Adapter theItemConverter = null;
@@ -387,7 +389,7 @@ public class Mappings {
accessMode.findWriter(clazz),
anyGetter != null ? new Getter(
new MethodAccessMode.MethodReader(anyGetter, anyGetter.getReturnType()),
- false, false, false, true, null, null, -1) : null,
+ false, false, false, true, null, null, -1, null) : null,
accessMode.findAnySetter(clazz));
accessMode.afterParsed(clazz);
@@ -437,6 +439,7 @@ public class Mappings {
final AccessMode.Reader value,
final boolean copyDate) {
final JohnzonIgnore readIgnore = value.getAnnotation(JohnzonIgnore.class);
+ final JohnzonIgnoreNested ignoreNested = value.getAnnotation(JohnzonIgnoreNested.class);
if (readIgnore == null || readIgnore.minVersion() >= 0) {
final Class<?> returnType = Class.class.isInstance(value.getType()) ? Class.class.cast(value.getType()) : null;
final ParameterizedType pt = ParameterizedType.class.isInstance(value.getType()) ? ParameterizedType.class.cast(value.getType()) : null;
@@ -447,7 +450,8 @@ public class Mappings {
(pt != null && Map.class.isAssignableFrom(Class.class.cast(pt.getRawType())))
|| (returnType != null && Map.class.isAssignableFrom(returnType)),
findConverter(copyDate, value), value.findObjectConverterWriter(),
- readIgnore != null ? readIgnore.minVersion() : -1);
+ readIgnore != null ? readIgnore.minVersion() : -1,
+ ignoreNested != null ? ignoreNested.properties() : null);
getters.put(key, getter);
}
}
@@ -494,7 +498,8 @@ public class Mappings {
final Getter getter = getters.get(key);
final MapBuilderReader newReader = new MapBuilderReader(objectGetters, path, config.getVersion());
- getters.put(key, new Getter(getter == null ? newReader : new CompositeReader(getter.reader, newReader), false, false, false, true, null, null, -1));
+ getters.put(key, new Getter(getter == null ? newReader :
+ new CompositeReader(getter.reader, newReader), false, false, false, true, null, null, -1, null));
final Setter newSetter = setters.get(key);
final MapUnwrapperWriter newWriter = new MapUnwrapperWriter(objectSetters, path);
http://git-wip-us.apache.org/repos/asf/johnzon/blob/dc7306d0/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
new file mode 100644
index 0000000..986c744
--- /dev/null
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/JohnzonIgnoreNestedTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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 org.junit.Test;
+
+import java.util.Collection;
+import java.util.Comparator;
+
+import static java.util.Collections.singletonList;
+import static org.junit.Assert.assertEquals;
+
+public class JohnzonIgnoreNestedTest {
+ @Test
+ public void ignoreNested() {
+ final To to = new To();
+ to.name = "to";
+
+ final From from = new From();
+ from.name = "from";
+
+ to.from = from;
+ to.froms = singletonList(from);
+ from.to = to;
+ from.tos = singletonList(to);
+
+ 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));
+ }
+
+ public static class To {
+ public String name;
+
+ @JohnzonIgnoreNested(properties = {"to", "tos"})
+ public From from;
+
+ @JohnzonIgnoreNested(properties = {"to", "tos"})
+ public Collection<From> froms;
+ }
+
+ public static class From {
+ public String name;
+
+ @JohnzonIgnoreNested(properties = {"from", "froms"})
+ public To to;
+
+ @JohnzonIgnoreNested(properties = {"from", "froms"})
+ public Collection<To> tos;
+ }
+}