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 ef9fc08 JOHNZON-309 more tolerance of adapters (string)
ef9fc08 is described below
commit ef9fc08a3d4846534449eb37833470837d808da7
Author: Romain Manni-Bucau <[email protected]>
AuthorDate: Fri Mar 27 10:41:51 2020 +0100
JOHNZON-309 more tolerance of adapters (string)
---
.../java/org/apache/johnzon/jsonb/AdapterTest.java | 37 ++++++++++++++++++++++
.../java/org/apache/johnzon/mapper/Mapper.java | 8 ++++-
.../org/apache/johnzon/mapper/MapperConfig.java | 32 ++++++++++++++++++-
.../apache/johnzon/mapper/MappingParserImpl.java | 34 ++++++++++++++++++--
.../apache/johnzon/mapper/internal/AdapterKey.java | 18 +++++++++++
5 files changed, 125 insertions(+), 4 deletions(-)
diff --git
a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/AdapterTest.java
b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/AdapterTest.java
index dca4576..9a69bb7 100644
--- a/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/AdapterTest.java
+++ b/johnzon-jsonb/src/test/java/org/apache/johnzon/jsonb/AdapterTest.java
@@ -29,6 +29,8 @@ import javax.json.bind.JsonbConfig;
import javax.json.bind.adapter.JsonbAdapter;
import javax.json.bind.annotation.JsonbTypeAdapter;
import javax.json.bind.config.PropertyOrderStrategy;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
@@ -41,6 +43,41 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class AdapterTest {
+ public static class PathAdapter implements JsonbAdapter<Path, JsonString> {
+ @Override
+ public JsonString adaptToJson(final Path path) {
+ return Json.createValue(path.toString());
+ }
+
+ @Override
+ public Path adaptFromJson(final JsonString jsonString) {
+ return Paths.get(jsonString.getString());
+ }
+ }
+
+ public static class PathWrapper {
+ public Path path;
+ }
+
+ @Test
+ public void testSerialize() throws Exception {
+ try (final Jsonb jsonb = JsonbBuilder.create(new
JsonbConfig().withAdapters(new PathAdapter()))) {
+ final PathWrapper wrapper = new PathWrapper();
+ wrapper.path = Paths.get("/example/file.txt");
+ assertEquals("{\"path\":\"/example/file.txt\"}",
jsonb.toJson(wrapper));
+ assertEquals("\"/example/file.txt\"", jsonb.toJson(wrapper.path));
+ }
+ }
+
+ @Test
+ public void testDeserialize() throws Exception {
+ try (final Jsonb jsonb = JsonbBuilder.create(new
JsonbConfig().withAdapters(new PathAdapter()))) {
+ final Path expected = Paths.get("/example/file.txt");
+ assertEquals(expected,
jsonb.fromJson("{\"path\":\"/example/file.txt\"}", PathWrapper.class).path);
+ assertEquals(expected, jsonb.fromJson("\"/example/file.txt\"",
Path.class));
+ }
+ }
+
@Test
public void adapt() throws Exception {
try (final Jsonb jsonb = JsonbBuilder.create(new
JsonbConfig().withAdapters(new BarAdapter()))) {
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
index 3616bf7..391c60f 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
@@ -44,6 +44,7 @@ import javax.json.JsonBuilderFactory;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.JsonReaderFactory;
+import javax.json.JsonString;
import javax.json.JsonStructure;
import javax.json.JsonValue;
import javax.json.spi.JsonProvider;
@@ -195,8 +196,13 @@ public class Mapper implements Closeable {
return;
}
+ final Adapter adapter = config.findAdapter(object.getClass());
+ if (adapter != null && TypeAwareAdapter.class.isInstance(adapter) &&
TypeAwareAdapter.class.cast(adapter).getTo() == JsonString.class) {
+ writeObject(adapter.from(object), stream);
+ return;
+ }
try (final JsonGenerator generator =
generatorFactory.createGenerator(stream(stream))) {
- writeObjectWithGenerator(object, generator);
+ writeObjectWithGenerator(adapter == null ? object :
adapter.from(object), generator);
}
}
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
index d3ef464..3046376 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperConfig.java
@@ -26,14 +26,18 @@ import org.apache.johnzon.mapper.internal.ConverterAdapter;
import javax.json.JsonValue;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
+import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import java.util.function.Predicate;
+import static java.util.stream.Collectors.toList;
+
/**
* Contains internal configuration for all the mapper stuff.
* It needs to be immutable and 100% runtime oriented.
@@ -86,6 +90,9 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig
implements Cloneable {
private final Map<Class<?>, ObjectConverter.Writer<?>>
objectConverterWriterCache;
private final Map<Class<?>, ObjectConverter.Reader<?>>
objectConverterReaderCache;
+ private final Collection<Type> noParserAdapterTypes = new
ConcurrentHashMap<Type, Boolean>().keySet(true);
+ private final Collection<Type> noGeneratorAdapterTypes = new
ConcurrentHashMap<Type, Boolean>().keySet(true);
+
//disable checkstyle for 10+ parameters
//CHECKSTYLE:OFF
public MapperConfig(final ConcurrentMap<AdapterKey, Adapter<?, ?>>
adapters,
@@ -149,6 +156,14 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig
implements Cloneable {
this.deduplicateObjects = deduplicateObjects;
}
+ public Collection<Type> getNoParserAdapterTypes() {
+ return noParserAdapterTypes;
+ }
+
+ public Collection<Type> getNoGeneratorAdapterTypes() {
+ return noGeneratorAdapterTypes;
+ }
+
public Function<String, Class<?>> getTypeLoader() {
return typeLoader;
}
@@ -186,7 +201,11 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig
implements Cloneable {
}
public Adapter findAdapter(final Type aClass) {
- final Adapter<?, ?> converter = adapters.get(new AdapterKey(aClass,
String.class));
+ if (getNoGeneratorAdapterTypes().contains(aClass)) { // avoid to
create a key for nothing
+ return null;
+ }
+
+ final Adapter<?, ?> converter = adapters.get(new AdapterKey(aClass,
String.class, true));
if (converter != null) {
return converter;
}
@@ -204,6 +223,17 @@ public /* DON'T MAKE IT HIDDEN */ class MapperConfig
implements Cloneable {
return enumConverter;
}
}
+ final List<AdapterKey> matched = adapters.keySet().stream()
+ .filter(k -> k.isAssignableFrom(aClass))
+ .collect(toList());
+ if (matched.size() == 1) {
+ final Adapter<?, ?> adapter =
adapters.get(matched.iterator().next());
+ if (TypeAwareAdapter.class.isInstance(adapter)) {
+ adapters.put(new AdapterKey(aClass,
TypeAwareAdapter.class.cast(adapter).getTo()), adapter);
+ }
+ return adapter;
+ }
+ getNoGeneratorAdapterTypes().add(aClass);
return null;
}
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 0ec10bc..26d3e12 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
@@ -77,6 +77,7 @@ import java.util.stream.LongStream;
import java.util.stream.Stream;
import static java.util.Arrays.asList;
+import static java.util.stream.Collectors.toList;
import static javax.json.JsonValue.ValueType.ARRAY;
import static javax.json.JsonValue.ValueType.FALSE;
import static javax.json.JsonValue.ValueType.NULL;
@@ -164,6 +165,20 @@ public class MappingParserImpl implements MappingParser {
if (classMapping != null && classMapping.adapter != null) {
return (T)
classMapping.adapter.to(JsonString.class.cast(jsonValue).getString());
}
+
+ final Adapter adapter = findAdapter(targetType);
+ if (adapter != null && TypeAwareAdapter.class.isInstance(adapter))
{
+ final TypeAwareAdapter typeAwareAdapter =
TypeAwareAdapter.class.cast(adapter);
+ if (typeAwareAdapter.getTo() == String.class) {
+ return (T)
adapter.to(JsonString.class.cast(jsonValue).getString());
+ }
+ if (typeAwareAdapter.getTo() == JsonString.class) {
+ return (T) adapter.to(JsonString.class.cast(jsonValue));
+ }
+ if (typeAwareAdapter.getTo() == CharSequence.class) {
+ return (T)
adapter.to(JsonString.class.cast(jsonValue).getChars());
+ }
+ }
}
if (JsonNumber.class.isInstance(jsonValue)) {
final JsonNumber number = JsonNumber.class.cast(jsonValue);
@@ -235,6 +250,7 @@ public class MappingParserImpl implements MappingParser {
if (FALSE == valueType && (Boolean.class == targetType ||
boolean.class == targetType || Object.class == targetType)) {
return (T) Boolean.FALSE;
}
+
throw new IllegalArgumentException("Unsupported " + jsonValue + " for
type " + targetType);
}
@@ -1093,10 +1109,13 @@ public class MappingParserImpl implements MappingParser
{
}
/**
- * @deprecated see MapperConfig
+ * @deprecated see MapperConfig - it is acually reversed so maybe not
deprecated after all?
*/
private Adapter findAdapter(final Type aClass) {
- final Adapter<?, ?> converter = config.getAdapters().get(new
AdapterKey(aClass, String.class));
+ if (config.getNoParserAdapterTypes().contains(aClass)) {
+ return null;
+ }
+ final Adapter<?, ?> converter = config.getAdapters().get(new
AdapterKey(aClass, String.class, true));
if (converter != null) {
return converter;
}
@@ -1108,6 +1127,17 @@ public class MappingParserImpl implements MappingParser {
return enumConverter;
}
}
+ final List<AdapterKey> matched = config.getAdapters().keySet().stream()
+ .filter(k -> k.isAssignableFrom(aClass))
+ .collect(toList());
+ if (matched.size() == 1) {
+ final Adapter<?, ?> adapter =
config.getAdapters().get(matched.iterator().next());
+ if (TypeAwareAdapter.class.isInstance(adapter)) {
+ config.getAdapters().put(new AdapterKey(aClass,
TypeAwareAdapter.class.cast(adapter).getTo()), adapter);
+ }
+ return adapter;
+ }
+ config.getNoParserAdapterTypes().add(aClass);
return null;
}
diff --git
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/AdapterKey.java
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/AdapterKey.java
index 9494ca2..27085c7 100644
---
a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/AdapterKey.java
+++
b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/internal/AdapterKey.java
@@ -24,10 +24,20 @@ public class AdapterKey {
private final Type from;
private final Type to;
private final int hash;
+ private Class valueAsClass;
+ private Class<?> keyAsClass;
public AdapterKey(final Type from, final Type to) {
+ this(from, to, false);
+ }
+
+ public AdapterKey(final Type from, final Type to, final boolean lookup) {
this.from = from;
this.to = to;
+ if (!lookup) {
+ this.keyAsClass = Class.class.isInstance(from) ?
Class.class.cast(from) : null;
+ this.valueAsClass = Class.class.isInstance(to) ?
Class.class.cast(to) : null;
+ }
int result = from.hashCode();
result = 31 * result + to.hashCode();
@@ -56,6 +66,14 @@ public class AdapterKey {
}
+ public boolean isAssignableFrom(final Type type) {
+ return keyAsClass != null && Class.class.isInstance(type) &&
keyAsClass.isAssignableFrom(Class.class.cast(type));
+ }
+
+ public boolean isAssignableTo(final Type type) {
+ return valueAsClass != null && Class.class.isInstance(type) &&
valueAsClass.isAssignableFrom(Class.class.cast(type));
+ }
+
@Override
public int hashCode() {
return hash;