You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by jl...@apache.org on 2023/10/11 15:05:16 UTC

[johnzon] branch master updated: feat: add support for JsonbTypeDeserializer with factories (JsonbCreator)

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

jlmonteiro 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 aef76ee8 feat: add support for JsonbTypeDeserializer with factories (JsonbCreator)
aef76ee8 is described below

commit aef76ee8b6ab4f76e2ffc709cd9f61abc61c435c
Author: Jean-Louis Monteiro <jl...@tomitribe.com>
AuthorDate: Wed Oct 11 16:39:44 2023 +0200

    feat: add support for JsonbTypeDeserializer with factories (JsonbCreator)
    
    Signed-off-by: Jean-Louis Monteiro <jl...@tomitribe.com>
---
 .../org/apache/johnzon/jsonb/JsonbAccessMode.java  | 60 +++++++++++++++++++++-
 1 file changed, 59 insertions(+), 1 deletion(-)

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 fb3f3fc7..a18b3481 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
@@ -264,7 +264,8 @@ public class JsonbAccessMode implements AccessMode, Closeable, Cleanable<Class<?
                 final JsonbDateFormat dateFormat = getAnnotation(parameter, JsonbDateFormat.class);
                 final JsonbNumberFormat numberFormat = getAnnotation(parameter, JsonbNumberFormat.class);
                 final JohnzonConverter johnzonConverter = getAnnotation(parameter, JohnzonConverter.class);
-                if (adapter == null && dateFormat == null && numberFormat == null && johnzonConverter == null) {
+                final JsonbTypeDeserializer deserializer = getAnnotation(parameter, JsonbTypeDeserializer.class);
+                if (adapter == null && dateFormat == null && numberFormat == null && johnzonConverter == null && deserializer == null) {
                     converters[i] = defaultConverters.get(parameter.getType());
                     itemConverters[i] = null;
                 } else {
@@ -283,6 +284,63 @@ public class JsonbAccessMode implements AccessMode, Closeable, Cleanable<Class<?
                             }
                         } else if (johnzonConverter != null) {
                             objectConverters[i] = (ObjectConverter.Codec<?>) johnzonConverter.value().newInstance();
+
+                        } else if (deserializer != null) {
+                            final Class<? extends JsonbDeserializer> value = deserializer.value();
+                            final JohnzonAdapterFactory.Instance<? extends JsonbDeserializer> instance = newInstance(value);
+                            final ParameterizedType pt = this.types.findParameterizedType(value, JsonbDeserializer.class);
+                            final Class<?> mappedType = this.types.findParamType(pt, JsonbDeserializer.class);
+                            toRelease.add(instance);
+                            final JsonBuilderFactory builderFactoryInstance = builderFactory.get();
+                            final Type[] arguments = this.types.findParameterizedType(value, JsonbDeserializer.class).getActualTypeArguments();
+                            final boolean global = arguments.length == 1 && arguments[0] != null && arguments[0].equals(parameter.getType());
+                            objectConverters[i] = new ObjectConverter.Codec() {
+                                private final ConcurrentMap<Type, BiFunction<JsonValue, MappingParser, Object>> impl =
+                                    new ConcurrentHashMap<>();
+                                @Override
+                                public Object fromJson(final JsonValue value, final Type targetType, final MappingParser parser) {
+                                    final JsonbDeserializer jsonbDeserializer = instance.getValue();
+                                    if (global || targetType == mappedType) { // fast test and matches most cases
+                                        return mapItem(value, targetType, parser, jsonbDeserializer);
+                                    }
+
+                                    BiFunction<JsonValue, MappingParser, Object> fn = impl.get(targetType);
+                                    if (fn == null) {
+                                        if (value.getValueType() == JsonValue.ValueType.ARRAY) {
+                                            if (ParameterizedType.class.isInstance(targetType)) {
+                                                final ParameterizedType parameterizedType = ParameterizedType.class.cast(targetType);
+                                                final Class<?> paramType = JsonbAccessMode.this.types.findParamType(parameterizedType, Collection.class);
+                                                if (paramType != null && (mappedType == null /*Object*/ || mappedType.isAssignableFrom(paramType))) {
+                                                    final Collector<Object, ?, ? extends Collection<Object>> collector =
+                                                        Set.class.isAssignableFrom(
+                                                            JsonbAccessMode.this.types.asClass(parameterizedType.getRawType())) ? toSet() : toList();
+                                                    fn = (json, mp) -> json.asJsonArray().stream()
+                                                                           .map(i -> mapItem(i, paramType, mp, jsonbDeserializer))
+                                                                           .collect(collector);
+                                                }
+                                            }
+                                        }
+                                        if (fn == null) {
+                                            fn = (json, mp) -> mapItem(json, targetType, mp, jsonbDeserializer);
+                                        }
+                                        impl.putIfAbsent(targetType, fn);
+                                    }
+                                    return fn.apply(value, parser);
+                                }
+
+                                private Object mapItem(final JsonValue jsonValue, final Type targetType,
+                                                       final MappingParser parser, final JsonbDeserializer jsonbDeserializer) {
+                                    return jsonbDeserializer.deserialize(
+                                        JsonValueParserAdapter.createFor(jsonValue, parserFactory),
+                                        new JohnzonDeserializationContext(parser, builderFactoryInstance, jsonProvider),
+                                        targetType);
+                                }
+
+                                @Override
+                                public void writeJson(final Object instance, final MappingGenerator jsonbGenerator) {
+                                    // no-op, it's for factories only
+                                }
+                            };
                         }
                     } catch (final InstantiationException | IllegalAccessException e) {
                         throw new IllegalArgumentException(e);