This is an automated email from the ASF dual-hosted git repository.

rmannibucau pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/johnzon.git


The following commit(s) were added to refs/heads/master by this push:
     new 2e24d5a  better record support (after jdk14 validation)
2e24d5a is described below

commit 2e24d5a2f070d46f9e0ded9b479f633559953620
Author: Romain Manni-Bucau <[email protected]>
AuthorDate: Fri Dec 20 10:16:28 2019 +0100

    better record support (after jdk14 validation)
---
 .../org/apache/johnzon/jsonb/JsonbAccessMode.java  | 14 ++++++--
 .../apache/johnzon/mapper/access/AccessMode.java   |  9 ++++-
 .../johnzon/mapper/access/BaseAccessMode.java      | 41 ++++++++++++++++++----
 .../mapper/access/FieldAndMethodAccessMode.java    | 21 ++++++++---
 .../org/apache/johnzon/mapper/access/Meta.java     | 10 ++----
 .../johnzon/mapper/access/MethodAccessMode.java    |  5 +--
 .../java/org/apache/johnzon/mapper/RecordTest.java |  8 +++--
 7 files changed, 81 insertions(+), 27 deletions(-)

diff --git 
a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java 
b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
index c778724..3ab3fd0 100644
--- a/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
+++ b/johnzon-jsonb/src/main/java/org/apache/johnzon/jsonb/JsonbAccessMode.java
@@ -27,6 +27,7 @@ import static 
org.apache.johnzon.mapper.reflection.Converters.matches;
 import java.io.Closeable;
 import java.io.IOException;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.GenericArrayType;
@@ -181,7 +182,7 @@ public class JsonbAccessMode implements AccessMode, 
Closeable {
     }
 
     @Override
-    public Factory findFactory(final Class<?> clazz) {
+    public Factory findFactory(final Class<?> clazz, final 
Function<AnnotatedElement, String>... parameterNameExtractors) {
         Constructor<?> constructor = null;
         Method factory = null;
         boolean invalidConstructorForDeserialization = false;
@@ -280,7 +281,11 @@ public class JsonbAccessMode implements AccessMode, 
Closeable {
         }
 
         if (constructor == null && factory == null && 
!invalidConstructorForDeserialization) {
-            return delegate.findFactory(clazz);
+            final Stream<Function<AnnotatedElement, String>> jsonbFn = 
Stream.of(this::getJsonbProperty);
+            return delegate.findFactory(
+                    clazz,
+                    (parameterNameExtractors == null ?
+                        jsonbFn : Stream.concat(jsonbFn, 
Stream.of(parameterNameExtractors))).toArray(Function[]::new));
         }
         if (constructor != null || invalidConstructorForDeserialization) {
             return constructorFactory(finalConstructor, 
invalidConstructorForDeserialization ? (Consumer<Object[]>) objects -> {
@@ -290,6 +295,11 @@ public class JsonbAccessMode implements AccessMode, 
Closeable {
         return methodFactory(clazz, finalFactory, factoryValidator, types, 
params, converters, itemConverters, objectConverters);
     }
 
+    private String getJsonbProperty(final AnnotatedElement a) {
+        final JsonbProperty p = Meta.getAnnotation(a, JsonbProperty.class);
+        return p != null ? p.value() : null;
+    }
+
     private Stream<Method> findPotentialFactoryMethods(final Class<?> clazz) {
         return (!supportsPrivateAccess ?
                 Stream.of(clazz.getMethods()) :
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 ece888b..4f12fa2 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
@@ -19,12 +19,14 @@
 package org.apache.johnzon.mapper.access;
 
 import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
 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.function.Function;
 import java.util.stream.Stream;
 
 import org.apache.johnzon.mapper.Adapter;
@@ -97,7 +99,12 @@ public interface AccessMode {
         ObjectConverter.Codec<?>[] getObjectConverter();
     }
 
-    Factory findFactory(Class<?> clazz);
+    Factory findFactory(Class<?> clazz, Function<AnnotatedElement, String>... 
parameterNameExtractors);
+
+    default Factory findFactory(final Class<?> clazz) {
+        return findFactory(clazz, null);
+    }
+
     Comparator<String> fieldComparator(Class<?> clazz);
     Map<String, Reader> findReaders(Class<?> clazz);
     Map<String, Writer> findWriters(Class<?> clazz);
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 818ddec..1a5931e 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
@@ -28,6 +28,7 @@ import static 
org.apache.johnzon.mapper.reflection.Converters.matches;
 
 import java.beans.ConstructorProperties;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -37,12 +38,15 @@ import java.util.Collection;
 import java.util.Comparator;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Objects;
+import java.util.function.Function;
 import java.util.stream.Stream;
 
 import org.apache.johnzon.mapper.Adapter;
 import org.apache.johnzon.mapper.Converter;
 import org.apache.johnzon.mapper.JohnzonAny;
 import org.apache.johnzon.mapper.JohnzonConverter;
+import org.apache.johnzon.mapper.JohnzonProperty;
 import org.apache.johnzon.mapper.JohnzonRecord;
 import org.apache.johnzon.mapper.MapperConverter;
 import org.apache.johnzon.mapper.ObjectConverter;
@@ -109,9 +113,10 @@ public abstract class BaseAccessMode implements AccessMode 
{
     }
 
     @Override
-    public Factory findFactory(final Class<?> clazz) {
+    public Factory findFactory(final Class<?> clazz, final 
Function<AnnotatedElement, String>... parameterNameExtractors) {
         Constructor<?> constructor = null;
-        if (isRecord(clazz) || Meta.getAnnotation(clazz, JohnzonRecord.class) 
!= null) {
+        final boolean record = isRecord(clazz);
+        if (record || Meta.getAnnotation(clazz, JohnzonRecord.class) != null) {
             constructor = findRecordConstructor(clazz);
         } else {
             for (final Constructor<?> c : clazz.getDeclaredConstructors()) {
@@ -151,11 +156,33 @@ public abstract class BaseAccessMode implements 
AccessMode {
             final Constructor<?> fc = constructor;
             final String[] constructorProperties = 
ofNullable(constructor.getAnnotation(ConstructorProperties.class))
                     .map(ConstructorProperties::value)
-                    .orElseGet(() -> Stream.of(fc.getParameters())
-                            .map(p -> 
ofNullable(p.getAnnotation(JohnzonRecord.Name.class))
-                                            .map(JohnzonRecord.Name::value)
-                                            .orElseGet(p::getName))
-                            .toArray(String[]::new));
+                    .orElseGet(() -> {
+                        if (record) {
+                            return Stream.of(fc.getParameters())
+                                    .map(p -> {
+                                        try {
+                                            if (parameterNameExtractors != 
null) {
+                                                return 
Stream.of(parameterNameExtractors)
+                                                        .map(fn -> fn.apply(p))
+                                                        
.filter(Objects::nonNull)
+                                                        .findFirst()
+                                                        .orElseGet(p::getName);
+                                            }
+                                            final JohnzonProperty property = 
Meta.getAnnotation(
+                                                    
clazz.getMethod(p.getName()), JohnzonProperty.class);
+                                            return property != null ? 
property.value() : p.getName();
+                                        } catch (final NoSuchMethodException 
e) {
+                                            return p.getName();
+                                        }
+                                    })
+                                    .toArray(String[]::new);
+                        }
+                        return Stream.of(fc.getParameters())
+                                .map(p -> 
ofNullable(p.getAnnotation(JohnzonRecord.Name.class))
+                                        .map(JohnzonRecord.Name::value)
+                                        .orElseGet(p::getName))
+                                .toArray(String[]::new);
+                    });
             System.arraycopy(constructorProperties, 0, constructorParameters, 
0, constructorParameters.length);
 
             constructorParameterConverters = new Adapter<?, 
?>[constructor.getGenericParameterTypes().length];
diff --git 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
index 9b04452..4fb0be4 100644
--- 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
+++ 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/FieldAndMethodAccessMode.java
@@ -18,6 +18,8 @@
  */
 package org.apache.johnzon.mapper.access;
 
+import static org.apache.johnzon.mapper.reflection.Records.isRecord;
+
 import org.apache.johnzon.mapper.Adapter;
 import org.apache.johnzon.mapper.JohnzonIgnore;
 import org.apache.johnzon.mapper.JohnzonProperty;
@@ -57,15 +59,21 @@ public class FieldAndMethodAccessMode extends 
BaseAccessMode {
 
     @Override
     public Map<String, Reader> doFindReaders(final Class<?> clazz) {
-        final Map<String, Reader> fieldsReaders = 
this.fields.findReaders(clazz);
         final Map<String, Reader> methodReaders = 
this.methods.findReaders(clazz);
+        final boolean record = isRecord(clazz);
+        if (record) {
+            return methodReaders;
+        }
 
-        final Map<String, Reader> readers = new HashMap<String, Reader>();
+        final Map<String, Reader> fieldsReaders = 
this.fields.findReaders(clazz);
+        final Map<String, Reader> readers = new HashMap<>();
 
         for (final Map.Entry<String, Reader> entry : fieldsReaders.entrySet()) 
{
             final String key = entry.getKey();
-            Method m = getMethod("get" + Character.toUpperCase(key.charAt(0)) 
+ (key.length() > 1 ? key.substring(1) : ""), clazz);
-            if (m == null && (boolean.class == entry.getValue().getType() || 
Boolean.class == entry.getValue().getType())) {
+            Method m = record ?
+                    getMethod(key, clazz) :
+                    getMethod("get" + Character.toUpperCase(key.charAt(0)) + 
(key.length() > 1 ? key.substring(1) : ""), clazz);
+            if (m == null && !record && (boolean.class == 
entry.getValue().getType() || Boolean.class == entry.getValue().getType())) {
                 m = getMethod("is" + Character.toUpperCase(key.charAt(0)) + 
(key.length() > 1 ? key.substring(1) : ""), clazz);
             }
             boolean skip = false;
@@ -89,7 +97,10 @@ public class FieldAndMethodAccessMode extends BaseAccessMode 
{
 
         for (final Map.Entry<String, Reader> entry : methodReaders.entrySet()) 
{
             final Method mr = 
MethodAccessMode.MethodDecoratedType.class.cast(entry.getValue()).getMethod();
-            final String fieldName = 
Introspector.decapitalize(mr.getName().startsWith("is") ? 
mr.getName().substring(2) : mr.getName().substring(3));
+            final String fieldName = record ?
+                    mr.getName() :
+                    Introspector.decapitalize(mr.getName().startsWith("is") ?
+                            mr.getName().substring(2) : 
mr.getName().substring(3));
             final Field f = getField(fieldName, clazz);
             boolean skip = false;
             if (f != null) {
diff --git 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/Meta.java 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/Meta.java
index 97cfab1..adcf650 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/Meta.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/Meta.java
@@ -21,7 +21,7 @@ package org.apache.johnzon.mapper.access;
 import static java.util.Arrays.asList;
 
 import java.lang.annotation.Annotation;
-import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -37,11 +37,7 @@ public final class Meta {
         // no-op
     }
 
-    public static <T extends Annotation> T getAnnotation(final Method holder, 
final Class<T> api) {
-        return getDirectAnnotation(holder, api);
-    }
-
-    public static <T extends Annotation> T getAnnotation(final Field holder, 
final Class<T> api) {
+    public static <T extends Annotation> T getAnnotation(final 
AnnotatedElement holder, final Class<T> api) {
         return getDirectAnnotation(holder, api);
     }
 
@@ -53,7 +49,7 @@ public final class Meta {
         return getIndirectAnnotation(api, holder::getDeclaringClass, () -> 
holder.getDeclaringClass().getPackage());
     }
 
-    private static <T extends Annotation> T getDirectAnnotation(final 
AccessibleObject holder, final Class<T> api) {
+    private static <T extends Annotation> T getDirectAnnotation(final 
AnnotatedElement holder, final Class<T> api) {
         final T annotation = holder.getAnnotation(api);
         if (annotation != null) {
             return annotation;
diff --git 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
index 67fab32..0b7a1ae 100644
--- 
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
+++ 
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/access/MethodAccessMode.java
@@ -49,12 +49,13 @@ public class MethodAccessMode extends BaseAccessMode {
 
     @Override
     public Map<String, Reader> doFindReaders(final Class<?> clazz) {
-        final Map<String, Reader> readers = new HashMap<String, Reader>();
+        final Map<String, Reader> readers = new HashMap<>();
         if (isRecord(clazz) || Meta.getAnnotation(clazz, JohnzonRecord.class) 
!= null) {
             readers.putAll(Stream.of(clazz.getMethods())
                 .filter(it -> it.getDeclaringClass() != Object.class && 
it.getParameterCount() == 0)
                 .filter(it -> !"toString".equals(it.getName()) && 
!"hashCode".equals(it.getName()))
-                .collect(toMap(Method::getName, it -> new MethodReader(it, 
it.getGenericReturnType()))));
+                .filter(it -> !isIgnored(it.getName()) && 
Meta.getAnnotation(it, JohnzonAny.class) == null)
+                .collect(toMap(m -> extractKey(m.getName(), m, null), it -> 
new MethodReader(it, it.getGenericReturnType()))));
         } else {
             final PropertyDescriptor[] propertyDescriptors = 
getPropertyDescriptors(clazz);
             for (final PropertyDescriptor descriptor : propertyDescriptors) {
diff --git 
a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/RecordTest.java 
b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/RecordTest.java
index 32a8738..6e1043b 100644
--- a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/RecordTest.java
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/RecordTest.java
@@ -29,7 +29,7 @@ public class RecordTest {
     public void roundTrip() {
         final Record ref = new Record(119, "Santa");
         try (final Mapper mapper = new 
MapperBuilder().setAttributeOrder(String.CASE_INSENSITIVE_ORDER).build()) {
-            final String expectedJson = "{\"age\":119,\"name\":\"Santa\"}";
+            final String expectedJson = "{\"_name\":\"Santa\",\"age\":119}";
             assertEquals(expectedJson, mapper.writeObjectAsString(ref));
             assertEquals(ref, mapper.readObject(expectedJson, Record.class));
         }
@@ -38,6 +38,8 @@ public class RecordTest {
     @JohnzonRecord
     public static class Record {
         private final int age;
+
+        @JohnzonProperty("_name")
         private final String name;
 
         public Record() { // simulate custom constructor
@@ -45,13 +47,13 @@ public class RecordTest {
             this.name = "failed";
         }
 
-        public Record(final int age) { // simulate custom constructor
+        public Record(final int age) { // simulate another custom constructor
             this.age = age;
             this.name = "failed";
         }
 
         public Record(@JohnzonRecord.Name("age") final int age,
-                      @JohnzonRecord.Name("name") final String name) {
+                      @JohnzonRecord.Name("_name") final String name) {
             this.age = age;
             this.name = name;
         }

Reply via email to