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;
}