Repository: johnzon Updated Branches: refs/heads/master 07a04d383 -> a2cbd4375
JOHNZON-176 adding a FieldFilteringStrategy for ignored fields Project: http://git-wip-us.apache.org/repos/asf/johnzon/repo Commit: http://git-wip-us.apache.org/repos/asf/johnzon/commit/a2cbd437 Tree: http://git-wip-us.apache.org/repos/asf/johnzon/tree/a2cbd437 Diff: http://git-wip-us.apache.org/repos/asf/johnzon/diff/a2cbd437 Branch: refs/heads/master Commit: a2cbd4375fcb361a8805e598e51656f34134dfad Parents: 07a04d3 Author: Romain Manni-Bucau <[email protected]> Authored: Tue Jul 3 10:24:11 2018 +0200 Committer: Romain Manni-Bucau <[email protected]> Committed: Tue Jul 3 10:24:11 2018 +0200 ---------------------------------------------------------------------- .../jaxrs/ConfigurableJohnzonProvider.java | 9 +++ .../WildcardConfigurableJohnzonProvider.java | 9 +++ .../apache/johnzon/mapper/MapperBuilder.java | 43 ++++++++++-- .../johnzon/mapper/access/BaseAccessMode.java | 70 +++++++++++++++----- .../org/apache/johnzon/mapper/MapperTest.java | 27 ++++++++ 5 files changed, 135 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/johnzon/blob/a2cbd437/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java ---------------------------------------------------------------------- diff --git a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java index 18e6466..30a452d 100644 --- a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java +++ b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/ConfigurableJohnzonProvider.java @@ -21,6 +21,7 @@ package org.apache.johnzon.jaxrs; import org.apache.johnzon.mapper.MapperBuilder; import org.apache.johnzon.mapper.SerializeValueFilter; import org.apache.johnzon.mapper.access.AccessMode; +import org.apache.johnzon.mapper.access.BaseAccessMode; import javax.json.JsonReaderFactory; import javax.json.stream.JsonGeneratorFactory; @@ -150,6 +151,14 @@ public class ConfigurableJohnzonProvider<T> implements MessageBodyWriter<T>, Mes builder.setAccessModeName(mode); } + public void setAccessModeFieldFilteringStrategy(final BaseAccessMode.FieldFilteringStrategy strategy) { + builder.setAccessModeFieldFilteringStrategy(strategy); + } + + public void setAccessModeFieldFilteringStrategyName(final String mode) { + builder.setAccessModeFieldFilteringStrategyName(mode); + } + public void setSupportHiddenAccess(final boolean supportHiddenAccess) { builder.setSupportHiddenAccess(supportHiddenAccess); } http://git-wip-us.apache.org/repos/asf/johnzon/blob/a2cbd437/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java ---------------------------------------------------------------------- diff --git a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java index 34bc456..aa71150 100644 --- a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java +++ b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WildcardConfigurableJohnzonProvider.java @@ -21,6 +21,7 @@ package org.apache.johnzon.jaxrs; import org.apache.johnzon.mapper.MapperBuilder; import org.apache.johnzon.mapper.SerializeValueFilter; import org.apache.johnzon.mapper.access.AccessMode; +import org.apache.johnzon.mapper.access.BaseAccessMode; import javax.json.JsonReaderFactory; import javax.json.stream.JsonGeneratorFactory; @@ -158,6 +159,14 @@ public class WildcardConfigurableJohnzonProvider<T> implements MessageBodyWriter builder.setAccessModeName(mode); } + public void setAccessModeFieldFilteringStrategy(final BaseAccessMode.FieldFilteringStrategy strategy) { + builder.setAccessModeFieldFilteringStrategy(strategy); + } + + public void setAccessModeFieldFilteringStrategyName(final String mode) { + builder.setAccessModeFieldFilteringStrategyName(mode); + } + public void setSupportHiddenAccess(final boolean supportHiddenAccess) { builder.setSupportHiddenAccess(supportHiddenAccess); } http://git-wip-us.apache.org/repos/asf/johnzon/blob/a2cbd437/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java index 387f3e6..126ff0a 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java @@ -18,6 +18,9 @@ */ package org.apache.johnzon.mapper; +import static java.util.Arrays.asList; +import static java.util.Locale.ROOT; + import org.apache.johnzon.core.JsonParserFactoryImpl; import org.apache.johnzon.mapper.access.AccessMode; import org.apache.johnzon.mapper.access.BaseAccessMode; @@ -129,6 +132,7 @@ public class MapperBuilder { private Map<Class<?>, ObjectConverter.Reader<?>> objectConverterReaders = new HashMap<Class<?>, ObjectConverter.Reader<?>>(); private Map<Class<?>, ObjectConverter.Writer<?>> objectConverterWriters = new HashMap<Class<?>, ObjectConverter.Writer<?>>(); private Map<Class<?>, String[]> ignoredForFields = new HashMap<Class<?>, String[]>(); + private BaseAccessMode.FieldFilteringStrategy fieldFilteringStrategy = null; private boolean primitiveConverters; private boolean failOnUnknownProperties; private SerializeValueFilter serializeValueFilter; @@ -181,15 +185,26 @@ public class MapperBuilder { throw new IllegalArgumentException("Unsupported access mode: " + accessModeName); } } + if (fieldFilteringStrategy != null) { + if (!BaseAccessMode.class.isInstance(accessMode)) { + throw new IllegalArgumentException("fieldFilteringStrategy can't be set with this access mode: " + accessMode); + } + BaseAccessMode.class.cast(accessMode).setFieldFilteringStrategy(fieldFilteringStrategy); + } if (!ignoredForFields.isEmpty()) { if (BaseAccessMode.class.isInstance(accessMode)) { final BaseAccessMode baseAccessMode = BaseAccessMode.class.cast(accessMode); - for (final Map.Entry<Class<?>, String[]> ignored : ignoredForFields.entrySet()) { - final String[] fields = ignored.getValue(); - if (fields == null || fields.length == 0) { - baseAccessMode.getFieldsToRemove().remove(ignored.getKey()); - } else { - baseAccessMode.getFieldsToRemove().put(ignored.getKey(), fields); + final BaseAccessMode.FieldFilteringStrategy strategy = baseAccessMode.getFieldFilteringStrategy(); + if (BaseAccessMode.ConfiguredFieldFilteringStrategy.class.isInstance(strategy)) { + final BaseAccessMode.ConfiguredFieldFilteringStrategy filteringStrategy = + BaseAccessMode.ConfiguredFieldFilteringStrategy.class.cast(strategy); + for (final Map.Entry<Class<?>, String[]> ignored : ignoredForFields.entrySet()) { + final String[] fields = ignored.getValue(); + if (fields == null || fields.length == 0) { + filteringStrategy.getFieldsToRemove().remove(ignored.getKey()); + } else { + filteringStrategy.getFieldsToRemove().put(ignored.getKey(), asList(fields)); + } } } } else { @@ -287,6 +302,22 @@ public class MapperBuilder { return this; } + public MapperBuilder setAccessModeFieldFilteringStrategy(final BaseAccessMode.FieldFilteringStrategy strategy) { + this.fieldFilteringStrategy = strategy; + return this; + } + + public MapperBuilder setAccessModeFieldFilteringStrategyName(final String mode) { + switch (mode.toLowerCase(ROOT)) { + case "all": + return setAccessModeFieldFilteringStrategy(new BaseAccessMode.AllEntriesFieldFilteringStrategy()); + case "single": + return setAccessModeFieldFilteringStrategy(new BaseAccessMode.SingleEntryFieldFilteringStrategy()); + default: + throw new IllegalArgumentException("Unknown field filter strategy: " + mode); + } + } + public MapperBuilder setSupportHiddenAccess(final boolean supportHiddenAccess) { this.supportHiddenAccess = supportHiddenAccess; return this; http://git-wip-us.apache.org/repos/asf/johnzon/blob/a2cbd437/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java index 5661ee2..0eba849 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/BaseAccessMode.java @@ -18,6 +18,9 @@ */ package org.apache.johnzon.mapper.access; +import static java.util.Arrays.asList; +import static java.util.Collections.emptySet; +import static java.util.stream.Collectors.toSet; import static org.apache.johnzon.mapper.reflection.Converters.matches; import java.beans.ConstructorProperties; @@ -27,8 +30,9 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; +import java.util.Collection; import java.util.Comparator; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import org.apache.johnzon.mapper.Adapter; @@ -43,16 +47,13 @@ import org.apache.johnzon.mapper.internal.ConverterAdapter; public abstract class BaseAccessMode implements AccessMode { private static final Type[] NO_PARAMS = new Type[0]; - private final Map<Class<?>, String[]> fieldsToRemove = new HashMap<Class<?>, String[]>(); + private FieldFilteringStrategy fieldFilteringStrategy = new SingleEntryFieldFilteringStrategy(); private final boolean acceptHiddenConstructor; private final boolean useConstructor; protected BaseAccessMode(final boolean useConstructor, final boolean acceptHiddenConstructor) { this.useConstructor = useConstructor; this.acceptHiddenConstructor = acceptHiddenConstructor; - - // mainly built it in the JVM types == user cant handle them - fieldsToRemove.put(Throwable.class, new String[]{"suppressedExceptions", "cause"}); } protected abstract Map<String,Reader> doFindReaders(Class<?> clazz); @@ -73,9 +74,12 @@ public abstract class BaseAccessMode implements AccessMode { return sanitize(clazz, doFindWriters(clazz)); } - // editable during builder time, dont do it at runtime or you get no guarantee - public Map<Class<?>, String[]> getFieldsToRemove() { - return fieldsToRemove; + public void setFieldFilteringStrategy(final FieldFilteringStrategy fieldFilteringStrategy) { + this.fieldFilteringStrategy = fieldFilteringStrategy; + } + + public FieldFilteringStrategy getFieldFilteringStrategy() { + return fieldFilteringStrategy; } @Override @@ -182,9 +186,7 @@ public abstract class BaseAccessMode implements AccessMode { } try { return params == null ? cons.newInstance() : cons.newInstance(params); - } catch (final InstantiationException e) { - throw new IllegalStateException(e); - } catch (final IllegalAccessException e) { + } catch (final InstantiationException | IllegalAccessException e) { throw new IllegalStateException(e); } catch (final InvocationTargetException e) { throw new IllegalStateException(e.getCause()); @@ -255,14 +257,48 @@ public abstract class BaseAccessMode implements AccessMode { } private <T> Map<String, T> sanitize(final Class<?> type, final Map<String, T> delegate) { - for (final Map.Entry<Class<?>, String[]> entry : fieldsToRemove.entrySet()) { - if (entry.getKey().isAssignableFrom(type)) { - for (final String field : entry.getValue()) { - delegate.remove(field); + for (final String field : fieldFilteringStrategy.select(type)) { + delegate.remove(field); + } + return delegate; + } + + public interface FieldFilteringStrategy { + Collection<String> select(final Class<?> type); + } + + public static abstract class ConfiguredFieldFilteringStrategy implements FieldFilteringStrategy { + private final Map<Class<?>, Collection<String>> fieldsToRemove = new LinkedHashMap<>(); + + public ConfiguredFieldFilteringStrategy() { + // mainly built it in the JVM types == user cant handle them + fieldsToRemove.put(Throwable.class, asList("suppressedExceptions", "cause")); + } + + public Map<Class<?>, Collection<String>> getFieldsToRemove() { + return fieldsToRemove; + } + } + + public static class SingleEntryFieldFilteringStrategy extends ConfiguredFieldFilteringStrategy { + @Override + public Collection<String> select(final Class<?> type) { + for (final Map.Entry<Class<?>, Collection<String>> entry : getFieldsToRemove().entrySet()) { + if (entry.getKey().isAssignableFrom(type)) { + return entry.getValue(); } - return delegate; } + return emptySet(); + } + } + + public static class AllEntriesFieldFilteringStrategy extends ConfiguredFieldFilteringStrategy { + @Override + public Collection<String> select(final Class<?> type) { + return getFieldsToRemove().entrySet().stream() + .filter(entry -> entry.getKey().isAssignableFrom(type)) + .flatMap(entry -> entry.getValue().stream()) + .collect(toSet()); } - return delegate; } } http://git-wip-us.apache.org/repos/asf/johnzon/blob/a2cbd437/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java index c3d90cf..3582460 100644 --- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java +++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/MapperTest.java @@ -32,6 +32,7 @@ import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; @@ -59,6 +60,22 @@ public class MapperTest { + "\"primitives\":[1,2,3,4,5]," + "\"collectionWrapper\":[1,2,3,4,5]," + "\"map\":{\"uno\":true,\"duos\":false}" + "}"; @Test + public void ignoreAllStrategy() { + final StringWriter writer = new StringWriter(); + final Child object = new Child(); + object.children = Collections.singletonList("first"); + object.a = 5; + object.b = 6; + object.c = 7; + new MapperBuilder().setAccessModeFieldFilteringStrategyName("all") + .setIgnoreFieldsForType(Child.class, "children") + .setIgnoreFieldsForType(Parent.class, "a", "b") + .build() + .writeObject(object, writer); + assertEquals("{\"c\":7}", writer.toString()); + } + + @Test public void writeEmptyObject() { final StringWriter writer = new StringWriter(); new MapperBuilder().build().writeObject(null, writer); @@ -1098,4 +1115,14 @@ public class MapperTest { public static class PrimitiveObject { public Object bool; } + + public static class Parent { + public int a; + public int b; + public int c; + } + + public static class Child extends Parent { + public List<String> children; + } }
