Repository: johnzon Updated Branches: refs/heads/master 2507062b0 -> 4166c51f6
JOHNZON-198 basic adder support Project: http://git-wip-us.apache.org/repos/asf/johnzon/repo Commit: http://git-wip-us.apache.org/repos/asf/johnzon/commit/4166c51f Tree: http://git-wip-us.apache.org/repos/asf/johnzon/tree/4166c51f Diff: http://git-wip-us.apache.org/repos/asf/johnzon/diff/4166c51f Branch: refs/heads/master Commit: 4166c51f6daa73cf080b33896328f0b4bd13126f Parents: 2507062 Author: Romain Manni-Bucau <[email protected]> Authored: Mon Dec 17 18:11:12 2018 +0100 Committer: Romain Manni-Bucau <[email protected]> Committed: Mon Dec 17 18:11:12 2018 +0100 ---------------------------------------------------------------------- .../jsonb/OverrideDefaultAdaptersTest.java | 29 +++++----- .../johnzon/mapper/MappingParserImpl.java | 20 +++++++ .../org/apache/johnzon/mapper/Mappings.java | 12 +++-- .../johnzon/mapper/access/AccessMode.java | 52 ++++++++++++++++-- .../org/apache/johnzon/mapper/AdderTest.java | 56 ++++++++++++++++++++ 5 files changed, 150 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/johnzon/blob/4166c51f/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/OverrideDefaultAdaptersTest.java ---------------------------------------------------------------------- diff --git a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/OverrideDefaultAdaptersTest.java b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/OverrideDefaultAdaptersTest.java index a7118c5..99b2f22 100644 --- a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/OverrideDefaultAdaptersTest.java +++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/OverrideDefaultAdaptersTest.java @@ -1,17 +1,20 @@ -/** - * Copyright (C) 2006-2018 Talend Inc. - www.talend.com - * <p> - * Licensed 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 - * <p> +/* + * 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 - * <p> - * 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. + * + * 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; http://git-wip-us.apache.org/repos/asf/johnzon/blob/4166c51f/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 a920324..4ad1633 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 @@ -357,6 +357,26 @@ public class MappingParserImpl implements MappingParser { } } } + if (classMapping.mapAdder != null) { + object.entrySet().stream() + .filter(it -> !classMapping.setters.containsKey(it.getKey())) + .filter(it -> it.getValue().getValueType() != NULL) + .forEach(e -> { + final Object convertedValue = toValue( + null, e.getValue(), null, null, + classMapping.mapAdderType, null, + new JsonPointerTracker(jsonPointer, e.getKey()), inType); + if (convertedValue != null) { + try { + classMapping.mapAdder.invoke(t, e.getKey(), convertedValue); + } catch (final IllegalAccessException ex) { + throw new IllegalStateException(ex); + } catch (final InvocationTargetException ex) { + throw new MapperException(ex.getCause()); + } + } + }); + } return t; } http://git-wip-us.apache.org/repos/asf/johnzon/blob/4166c51f/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 d18d085..539fdb8 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 @@ -67,6 +67,8 @@ public class Mappings { public final ObjectConverter.Writer writer; public final Getter anyGetter; public final Method anySetter; + public final Method mapAdder; + public final Class<?> mapAdderType; private Boolean deduplicateObjects; private boolean deduplicationEvaluated = false; @@ -75,7 +77,8 @@ public class Mappings { final Map<String, Getter> getters, final Map<String, Setter> setters, final Adapter<?, ?> adapter, final ObjectConverter.Reader<?> reader, final ObjectConverter.Writer<?> writer, - final Getter anyGetter, final Method anySetter) { + final Getter anyGetter, final Method anySetter, + final Method mapAdder) { this.clazz = clazz; this.factory = factory; this.getters = getters; @@ -85,11 +88,13 @@ public class Mappings { this.reader = reader; this.anyGetter = anyGetter; this.anySetter = anySetter; + this.mapAdder = mapAdder; + this.mapAdderType = mapAdder == null ? null : mapAdder.getParameterTypes()[1]; } public Boolean isDeduplicateObjects() { if (!deduplicationEvaluated) { - JohnzonDeduplicateObjects jdo = ((Class<JohnzonDeduplicateObjects>) clazz).getAnnotation(JohnzonDeduplicateObjects.class); + JohnzonDeduplicateObjects jdo = clazz.getAnnotation(JohnzonDeduplicateObjects.class); if (jdo != null){ deduplicateObjects = jdo.value(); } @@ -424,7 +429,8 @@ public class Mappings { anyGetter != null ? new Getter( new MethodAccessMode.MethodReader(anyGetter, anyGetter.getReturnType()), false,false, false, false, true, null, null, -1, null) : null, - accessMode.findAnySetter(clazz)); + accessMode.findAnySetter(clazz), + Map.class.isAssignableFrom(clazz) ? accessMode.findMapAdder(clazz) : null); accessMode.afterParsed(clazz); http://git-wip-us.apache.org/repos/asf/johnzon/blob/4166c51f/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java index 4d590bf..6c95675 100644 --- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java +++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/AccessMode.java @@ -18,14 +18,56 @@ */ package org.apache.johnzon.mapper.access; -import org.apache.johnzon.mapper.Adapter; -import org.apache.johnzon.mapper.ObjectConverter; - import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Comparator; import java.util.Map; +import java.util.Objects; +import java.util.stream.Stream; + +import org.apache.johnzon.mapper.Adapter; +import org.apache.johnzon.mapper.ObjectConverter; + +@FunctionalInterface +interface FindMethod { + Method get(String name, Class<?> type, Class<?> param) throws NoSuchMethodException; +} + +class MapHelper { + private MapHelper() { + // no-op + } + + static Method find(final FindMethod finder, final Class<?> type) { + return Stream.of(type.getGenericSuperclass()) + .filter(ParameterizedType.class::isInstance) + .map(ParameterizedType.class::cast) + .filter(it -> Class.class.isInstance(it.getRawType()) && Map.class.isAssignableFrom(Class.class.cast(it.getRawType()))) + .map(ParameterizedType::getActualTypeArguments) + .filter(a -> a.length == 2) + .map(a -> a[1]) + .filter(Class.class::isInstance) + .map(Class.class::cast) + .flatMap(param -> { + final String simpleName = param.getSimpleName(); + return Stream.of( // direct name or if the pattern is FoosImpl try addFoo + simpleName, + simpleName.replaceAll("Impl$" ,"").replaceAll("s$", "")) + .map(it -> { + try { + return finder.get(it, type, param); + } catch (final NoSuchMethodException e) { + return null; + } + }) + .filter(Objects::nonNull); + }) + .findFirst() + .orElse(null); + } +} public interface AccessMode { interface DecoratedType { @@ -65,6 +107,10 @@ public interface AccessMode { Method findAnyGetter(Class<?> clazz); Method findAnySetter(Class<?> clazz); + default Method findMapAdder(final Class<?> clazz) { + return MapHelper.find((name, type, param) -> type.getMethod("add" + name, String.class, param), clazz); + } + /** * Called once johnzon will not use AccessMode anymore. Can be used to clean up any local cache. * http://git-wip-us.apache.org/repos/asf/johnzon/blob/4166c51f/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/AdderTest.java ---------------------------------------------------------------------- diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/AdderTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/AdderTest.java new file mode 100644 index 0000000..82b5ae9 --- /dev/null +++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/AdderTest.java @@ -0,0 +1,56 @@ +/* + * 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 static java.util.Collections.singletonMap; +import static org.junit.Assert.assertEquals; + +import java.util.LinkedHashMap; + +import org.junit.Test; + +public class AdderTest { + @Test + public void adderString() { + assertEquals(singletonMap("foo", "bar"), new MapperBuilder().build() + .readObject("{\"foo\":\"bar\"}", MyMap.class)); + } + @Test + public void adderObject() { + final MyMapOfObjects map = new MapperBuilder().build() + .readObject("{\"foo\":{\"value\":\"bar\"}}", MyMapOfObjects.class); + assertEquals("bar", map.get("foo").value); + } + + public static class MyMap extends LinkedHashMap<String, String> { + public void addString(final String name, final String value) { + put(name, value); + } + } + + public static class MyObject { + public String value; + } + + public static class MyMapOfObjects extends LinkedHashMap<String, MyObject> { + public void addMyObject(final String name, final MyObject value) { + put(name, value); + } + } +}
