JOHNZON-282: add support for @JsonbTypeAdapter at class level (#53)
* JOHNZON-282: add support for @JsonbTypeAdapter at class level
* add test with adapter at root object
* remove recursion
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 89f85a5..7f6ddaa 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
@@ -868,8 +868,10 @@
ReaderConverters(final DecoratedType annotationHolder) {
final boolean numberType = isNumberType(annotationHolder.getType());
final boolean dateType = isDateType(annotationHolder.getType());
+ final boolean hasRawType = hasRawType(annotationHolder.getType());
final JsonbTypeDeserializer deserializer = annotationHolder.getAnnotation(JsonbTypeDeserializer.class);
final JsonbTypeAdapter adapter = annotationHolder.getAnnotation(JsonbTypeAdapter.class);
+ final JsonbTypeAdapter typeAdapter = hasRawType ? getRawType(annotationHolder.getType()).getDeclaredAnnotation(JsonbTypeAdapter.class) : null;
JsonbDateFormat dateFormat = dateType ? annotationHolder.getAnnotation(JsonbDateFormat.class) : null;
JsonbNumberFormat numberFormat = numberType ? annotationHolder.getAnnotation(JsonbNumberFormat.class) : null;
final JohnzonConverter johnzonConverter = annotationHolder.getAnnotation(JohnzonConverter.class);
@@ -881,9 +883,9 @@
numberFormat = annotationHolder.getClassOrPackageAnnotation(JsonbNumberFormat.class);
}
- converter = adapter == null && dateFormat == null && numberFormat == null && johnzonConverter == null ?
+ converter = adapter == null && typeAdapter == null && dateFormat == null && numberFormat == null && johnzonConverter == null ?
defaultConverters.get(new AdapterKey(annotationHolder.getType(), String.class)) :
- toConverter(types, annotationHolder.getType(), adapter, dateFormat, numberFormat);
+ toConverter(types, annotationHolder.getType(), adapter != null ? adapter : typeAdapter, dateFormat, numberFormat);
if (deserializer != null) {
final Class<? extends JsonbDeserializer> value = deserializer.value();
@@ -966,12 +968,14 @@
WriterConverters(final DecoratedType reader, final Types types) {
final boolean numberType = isNumberType(reader.getType());
final boolean dateType = isDateType(reader.getType());
+ final boolean hasRawType = hasRawType(reader.getType());
final JsonbTypeSerializer serializer = reader.getAnnotation(JsonbTypeSerializer.class);
final JsonbTypeAdapter adapter = reader.getAnnotation(JsonbTypeAdapter.class);
+ final JsonbTypeAdapter typeAdapter = hasRawType ? getRawType(reader.getType()).getDeclaredAnnotation(JsonbTypeAdapter.class) : null;
JsonbDateFormat dateFormat = dateType ? reader.getAnnotation(JsonbDateFormat.class) : null;
JsonbNumberFormat numberFormat = numberType ? reader.getAnnotation(JsonbNumberFormat.class) : null;
final JohnzonConverter johnzonConverter = reader.getAnnotation(JohnzonConverter.class);
- validateAnnotations(reader, adapter, dateFormat, numberFormat, johnzonConverter);
+ validateAnnotations(reader, adapter != null ? adapter : typeAdapter, dateFormat, numberFormat, johnzonConverter);
if (dateFormat == null && isDateType(reader.getType())) {
dateFormat = reader.getClassOrPackageAnnotation(JsonbDateFormat.class);
}
@@ -979,9 +983,9 @@
numberFormat = reader.getClassOrPackageAnnotation(JsonbNumberFormat.class);
}
- converter = adapter == null && dateFormat == null && numberFormat == null && johnzonConverter == null ?
+ converter = adapter == null && typeAdapter == null && dateFormat == null && numberFormat == null && johnzonConverter == null ?
defaultConverters.get(new AdapterKey(reader.getType(), String.class)) :
- toConverter(types, reader.getType(), adapter, dateFormat, numberFormat);
+ toConverter(types, reader.getType(), adapter != null ? adapter : typeAdapter, dateFormat, numberFormat);
if (serializer != null) {
final Class<? extends JsonbSerializer> value = serializer.value();
@@ -1033,6 +1037,20 @@
return Number.class.isAssignableFrom(clazz) || clazz.isPrimitive();
}
+ private boolean hasRawType(final Type type) {
+ return Class.class.isInstance(type) || ParameterizedType.class.isInstance(type);
+ }
+
+ private Class<?> getRawType(final Type type) {
+ if (!Class.class.isInstance(type) && !ParameterizedType.class.isInstance(type)) {
+ throw new IllegalStateException("Unsupported generic type " + type.getClass().getName());
+ } else if (Class.class.isInstance(type)) {
+ return Class.class.cast(type);
+ } else /*if (ParameterizedType.class.isInstance(type))*/ {
+ return Class.class.cast(ParameterizedType.class.cast(type).getRawType());
+ }
+ }
+
private static class ClassDecoratedType implements DecoratedType {
private final Class<?> annotations;
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 8e12cbd..dca4576 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
@@ -1,3 +1,4 @@
+package org.apache.johnzon.jsonb;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -16,7 +17,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.johnzon.jsonb;
+
import org.junit.Test;
@@ -32,7 +33,11 @@
import java.util.List;
import static java.util.Arrays.asList;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.endsWith;
+import static org.hamcrest.CoreMatchers.startsWith;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class AdapterTest {
@@ -44,13 +49,32 @@
foo.bar.value = 1;
foo.dummy = new Dummy();
foo.dummy.value = 2L;
+ foo.baz = new Baz();
+ foo.baz.value = "3";
final String toString = jsonb.toJson(foo);
- assertEquals("{\"bar\":\"1\",\"dummy\":\"2\"}", toString);
+ assertThat(toString, startsWith("{"));
+ assertThat(toString, containsString("\"bar\":\"1\""));
+ assertThat(toString, containsString("\"dummy\":\"2\""));
+ assertThat(toString, containsString("\"baz\":\"3\""));
+ assertThat(toString, endsWith("}"));
+ assertEquals("{\"bar\":\"1\",\"dummy\":\"2\",\"baz\":\"3\"}".length(), toString.length());
final Foo read = jsonb.fromJson(toString, Foo.class);
assertEquals(foo.bar.value, read.bar.value);
assertEquals(foo.dummy.value, read.dummy.value);
+ assertEquals(foo.baz.value, read.baz.value);
+ }
+ }
+
+ @Test
+ public void adaptValue() throws Exception {
+ try (final Jsonb jsonb = JsonbBuilder.create()) {
+ final Baz baz = new Baz();
+ baz.value = "test";
+
+ final String toString = jsonb.toJson(baz);
+ assertEquals("\"test\"", toString);
}
}
@@ -144,6 +168,8 @@
@JsonbTypeAdapter(DummyAdapter.class)
public Dummy dummy;
+
+ public Baz baz;
}
public static class Bar2 extends Bar {
@@ -169,6 +195,27 @@
}
}
+ @JsonbTypeAdapter(BazAdapter.class)
+ public static class Baz {
+ public String value;
+ }
+
+ public static class BazAdapter implements JsonbAdapter<Baz, String> {
+
+ @Override
+ public String adaptToJson(Baz obj) throws Exception {
+ return obj.value;
+ }
+
+ @Override
+ public Baz adaptFromJson(String obj) throws Exception {
+ Baz baz = new Baz();
+ baz.value = obj;
+ return baz;
+ }
+
+ }
+
public static class Dummy2 {
public long value;
}