This is an automated email from the ASF dual-hosted git repository. struberg pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/johnzon.git
commit 23b49f3d517a07e3d51f1ea1d32cf94a474cd7d4 Author: Mark Struberg <strub...@apache.org> AuthorDate: Tue Apr 12 10:03:36 2022 +0200 JOHNZON-364 use reflection to avoid caches. --- .../org/apache/johnzon/core/util/ClassUtil.java | 32 ++++++++++++++++++ .../org/apache/johnzon/core/ClassUtilTest.java | 38 ++++++++++++++++++++++ .../jsonb/DefaultPropertyVisibilityStrategy.java | 23 +++++++++---- 3 files changed, 87 insertions(+), 6 deletions(-) diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/util/ClassUtil.java b/johnzon-core/src/main/java/org/apache/johnzon/core/util/ClassUtil.java index 1dc189b..1eebe6f 100644 --- a/johnzon-core/src/main/java/org/apache/johnzon/core/util/ClassUtil.java +++ b/johnzon-core/src/main/java/org/apache/johnzon/core/util/ClassUtil.java @@ -58,4 +58,36 @@ public final class ClassUtil { } } + /** + * Calculate the name of a getter based on the name of it's field and the type + * + * @param fieldName + * @param type of the field + * @return "get" or "is" method name for the field + */ + public static String getterName(String fieldName, Class<?> type) { + StringBuilder sb = new StringBuilder(50); + sb.append(type == Boolean.class || type == boolean.class ? "is" : "get"); + sb.append(Character.toUpperCase(fieldName.charAt(0))).append(fieldName.substring(1)); + return sb.toString(); + } + + /** + * Calculate the name of a setter based on the name of it's field + * + * @param fieldName + * @return "set" method name for the field + */ + public static String setterName(String fieldName) { + StringBuilder sb = new StringBuilder(50); + sb.append("set"); + sb.append(Character.toUpperCase(fieldName.charAt(0))).append(fieldName.substring(1)); + return sb.toString(); + } + + public static String capitalizeName(String fieldName) { + StringBuilder sb = new StringBuilder(50); + sb.append(Character.toUpperCase(fieldName.charAt(0))).append(fieldName.substring(1)); + return sb.toString(); + } } \ No newline at end of file diff --git a/johnzon-core/src/test/java/org/apache/johnzon/core/ClassUtilTest.java b/johnzon-core/src/test/java/org/apache/johnzon/core/ClassUtilTest.java new file mode 100644 index 0000000..299d146 --- /dev/null +++ b/johnzon-core/src/test/java/org/apache/johnzon/core/ClassUtilTest.java @@ -0,0 +1,38 @@ +/* + * 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.core; + +import org.apache.johnzon.core.util.ClassUtil; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ClassUtilTest { + + @Test + public void testGetterNames() { + assertEquals("getMyName", ClassUtil.getterName("myName", Integer.class)); + assertEquals("isEnabled", ClassUtil.getterName("enabled", Boolean.class)); + assertEquals("isEnabled", ClassUtil.getterName("enabled", boolean.class)); + } + + @Test + public void testSetterNames() { + assertEquals("setMyName", ClassUtil.setterName("myName")); + assertEquals("setEnabled", ClassUtil.setterName("enabled")); + } +} diff --git a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/DefaultPropertyVisibilityStrategy.java b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/DefaultPropertyVisibilityStrategy.java index fe4d449..33e0be5 100644 --- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/DefaultPropertyVisibilityStrategy.java +++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/DefaultPropertyVisibilityStrategy.java @@ -18,6 +18,7 @@ */ package org.apache.johnzon.jsonb; +import org.apache.johnzon.core.util.ClassUtil; import org.apache.johnzon.mapper.Cleanable; import javax.json.bind.annotation.JsonbProperty; @@ -36,8 +37,6 @@ import static java.util.Optional.ofNullable; class DefaultPropertyVisibilityStrategy implements javax.json.bind.config.PropertyVisibilityStrategy, Cleanable<Class<?>> { private final ConcurrentMap<Class<?>, PropertyVisibilityStrategy> strategies = new ConcurrentHashMap<>(); - private final ConcurrentMap<Class<?>, Map<String, Boolean>> getters = new ConcurrentHashMap<>(); - private final ConcurrentMap<Class<?>, Map<String, Boolean>> setters = new ConcurrentHashMap<>(); private volatile boolean skipGetpackage; @@ -61,9 +60,23 @@ class DefaultPropertyVisibilityStrategy implements javax.json.bind.config.Proper // 3.7.1. Scope and Field access strategy // note: we should bind the class since a field of a parent class can have a getter in a child if (!useGetter) { - return setters.computeIfAbsent(root, this::calculateSetters).getOrDefault(field.getName(), true); + return !hasMethod(root, ClassUtil.setterName(field.getName())); + } + final String capitalizedName = ClassUtil.capitalizeName(field.getName()); + return !hasMethod(root, "get" + capitalizedName) || hasMethod(root, "is" + capitalizedName); + } + + private boolean hasMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) { + try { + clazz.getDeclaredMethod(methodName, paramTypes); + return true; + } catch (NoSuchMethodException e) { + final Class<?> superclass = clazz.getSuperclass(); + if (superclass == Object.class) { + return false; + } + return hasMethod(superclass, methodName, paramTypes); } - return getters.computeIfAbsent(root, this::calculateGetters).getOrDefault(field.getName(), true); } /** @@ -165,8 +178,6 @@ class DefaultPropertyVisibilityStrategy implements javax.json.bind.config.Proper @Override public void clean(final Class<?> clazz) { - getters.remove(clazz); - setters.remove(clazz); strategies.remove(clazz); } }