From 444d92929be3d32a2c4ef829dd77c51ef681d199 Mon Sep 17 00:00:00 2001 From: Anton Pinsky Date: Sat, 7 Oct 2023 23:29:30 +0200 Subject: [PATCH] [#617]User defined deserializer always should be used before standard ones --- .../DeserializationModelCreator.java | 19 ++++--- .../yasson/serializers/SerializersTest.java | 12 ++++ .../yasson/serializers/model/Colors.java | 15 +++++ .../serializers/model/ColorsDeserializer.java | 8 +++ .../serializers/model/ColorsSerializer.java | 7 +++ .../EnumWithJsonbPropertyDeserializer.java | 57 +++++++++++++++++++ .../EnumWithJsonbPropertySerializer.java | 48 ++++++++++++++++ 7 files changed, 158 insertions(+), 8 deletions(-) create mode 100644 src/test/java/org/eclipse/yasson/serializers/model/Colors.java create mode 100644 src/test/java/org/eclipse/yasson/serializers/model/ColorsDeserializer.java create mode 100644 src/test/java/org/eclipse/yasson/serializers/model/ColorsSerializer.java create mode 100644 src/test/java/org/eclipse/yasson/serializers/model/EnumWithJsonbPropertyDeserializer.java create mode 100644 src/test/java/org/eclipse/yasson/serializers/model/EnumWithJsonbPropertySerializer.java diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java b/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java index 0ac3f980..6c12822c 100644 --- a/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java @@ -152,6 +152,17 @@ private ModelDeserializer deserializerChainInternal(LinkedList models.put(cachedItem, deserializer); return deserializer; } + + ClassCustomization classCustomization = classModel.getClassCustomization(); + Optional> deserializerBinding = userDeserializer(type, + (ComponentBoundCustomization) propertyCustomization); + if (deserializerBinding.isPresent()) { + UserDefinedDeserializer user = new UserDefinedDeserializer(deserializerBinding.get().getJsonbDeserializer(), + JustReturn.instance(), type, classCustomization); + models.put(cachedItem, user); + return user; + } + Optional adapterBinding = adapterBinding(type, (ComponentBoundCustomization) propertyCustomization); if (adapterBinding.isPresent()) { AdapterBinding adapter = adapterBinding.get(); @@ -201,14 +212,6 @@ private ModelDeserializer createObjectDeserializer(LinkedList Class rawType, CachedItem cachedItem) { ClassCustomization classCustomization = classModel.getClassCustomization(); - Optional> deserializerBinding = userDeserializer(type, - (ComponentBoundCustomization) propertyCustomization); - if (deserializerBinding.isPresent()) { - UserDefinedDeserializer user = new UserDefinedDeserializer(deserializerBinding.get().getJsonbDeserializer(), - JustReturn.instance(), type, classCustomization); - models.put(cachedItem, user); - return user; - } JsonbCreator creator = classCustomization.getCreator(); boolean hasCreator = creator != null; List params = hasCreator ? creatorParamsList(creator) : Collections.emptyList(); diff --git a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java index db0efdf1..04caa8d0 100644 --- a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java +++ b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java @@ -51,6 +51,7 @@ import org.eclipse.yasson.serializers.model.Author; import org.eclipse.yasson.serializers.model.Box; import org.eclipse.yasson.serializers.model.BoxWithAnnotations; +import org.eclipse.yasson.serializers.model.Colors; import org.eclipse.yasson.serializers.model.Containee; import org.eclipse.yasson.serializers.model.Container; import org.eclipse.yasson.serializers.model.Crate; @@ -812,4 +813,15 @@ public void testCustomSerializersInContainer(){ } + @Test + void testCustomSerializersAndDeserializersInEnum(){ + Jsonb jsonb = JsonbBuilder.create(); + + Colors expected = Colors.GREEN; + + String expectedJson = jsonb.toJson(expected); + + assertEquals(expected, jsonb.fromJson(expectedJson, Colors.class)); + } + } diff --git a/src/test/java/org/eclipse/yasson/serializers/model/Colors.java b/src/test/java/org/eclipse/yasson/serializers/model/Colors.java new file mode 100644 index 00000000..154d09f0 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/serializers/model/Colors.java @@ -0,0 +1,15 @@ +package org.eclipse.yasson.serializers.model; + +import jakarta.json.bind.annotation.JsonbProperty; +import jakarta.json.bind.annotation.JsonbTypeDeserializer; +import jakarta.json.bind.annotation.JsonbTypeSerializer; + +@JsonbTypeSerializer(ColorsSerializer.class) +@JsonbTypeDeserializer(ColorsDeserializer.class) +public enum Colors { + @JsonbProperty("Red") + RED, + @JsonbProperty("Green") + GREEN +} + diff --git a/src/test/java/org/eclipse/yasson/serializers/model/ColorsDeserializer.java b/src/test/java/org/eclipse/yasson/serializers/model/ColorsDeserializer.java new file mode 100644 index 00000000..201d61bf --- /dev/null +++ b/src/test/java/org/eclipse/yasson/serializers/model/ColorsDeserializer.java @@ -0,0 +1,8 @@ +package org.eclipse.yasson.serializers.model; + +public class ColorsDeserializer extends EnumWithJsonbPropertyDeserializer { + + public ColorsDeserializer() { + super(); + } +} diff --git a/src/test/java/org/eclipse/yasson/serializers/model/ColorsSerializer.java b/src/test/java/org/eclipse/yasson/serializers/model/ColorsSerializer.java new file mode 100644 index 00000000..a8dd33b5 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/serializers/model/ColorsSerializer.java @@ -0,0 +1,7 @@ +package org.eclipse.yasson.serializers.model; + +public class ColorsSerializer extends EnumWithJsonbPropertySerializer { + public ColorsSerializer() { + super(); + } +} diff --git a/src/test/java/org/eclipse/yasson/serializers/model/EnumWithJsonbPropertyDeserializer.java b/src/test/java/org/eclipse/yasson/serializers/model/EnumWithJsonbPropertyDeserializer.java new file mode 100644 index 00000000..f26df2a1 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/serializers/model/EnumWithJsonbPropertyDeserializer.java @@ -0,0 +1,57 @@ +package org.eclipse.yasson.serializers.model; + +import static java.util.Optional.ofNullable; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +import jakarta.json.bind.annotation.JsonbProperty; +import jakarta.json.bind.serializer.DeserializationContext; +import jakarta.json.bind.serializer.JsonbDeserializer; +import jakarta.json.stream.JsonParser; + +public class EnumWithJsonbPropertyDeserializer> implements JsonbDeserializer { + + private final Map jsonToJavaMapping; + + public EnumWithJsonbPropertyDeserializer() { + super(); + + Class enumType = getEnumType(); + jsonToJavaMapping = new HashMap<>(); + + Stream.of(enumType.getEnumConstants()).forEach(constant -> { + final String asString; + try { + asString = ofNullable( + constant.getClass() + .getDeclaredField(constant.name()) + .getAnnotation(JsonbProperty.class)) + .map(JsonbProperty::value) + .orElseGet(constant::name); + } catch (final NoSuchFieldException e) { + throw new IllegalArgumentException(e); + } + jsonToJavaMapping.put(asString, constant); + }); + } + + private Class getEnumType() { + return Class.class.cast(ParameterizedType.class.cast( + getClass().getGenericSuperclass()) + .getActualTypeArguments()[0]); + } + + @Override + public E deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { + String key = parser.getString(); + + assert key != null; + + return ofNullable(jsonToJavaMapping.get(key)) + .orElseThrow(() -> new IllegalArgumentException("Unknown enum value: '" + key + "'")); + } +} diff --git a/src/test/java/org/eclipse/yasson/serializers/model/EnumWithJsonbPropertySerializer.java b/src/test/java/org/eclipse/yasson/serializers/model/EnumWithJsonbPropertySerializer.java new file mode 100644 index 00000000..5ef34776 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/serializers/model/EnumWithJsonbPropertySerializer.java @@ -0,0 +1,48 @@ +package org.eclipse.yasson.serializers.model; + +import static java.util.Optional.ofNullable; + +import java.lang.reflect.ParameterizedType; +import java.util.EnumMap; +import java.util.stream.Stream; + +import jakarta.json.bind.annotation.JsonbProperty; +import jakarta.json.bind.serializer.JsonbSerializer; +import jakarta.json.bind.serializer.SerializationContext; +import jakarta.json.stream.JsonGenerator; + +public class EnumWithJsonbPropertySerializer> implements JsonbSerializer { + private final EnumMap javaToJsonMapping; + + public EnumWithJsonbPropertySerializer() { + super(); + + Class enumType = getEnumType(); + javaToJsonMapping = new EnumMap<>(enumType); + + Stream.of(enumType.getEnumConstants()).forEach(constant -> { + final String asString; + try { + asString = ofNullable( + constant.getClass() + .getDeclaredField(constant.name()) + .getAnnotation(JsonbProperty.class)) + .map(JsonbProperty::value) + .orElseGet(constant::name); + } catch (final NoSuchFieldException e) { + throw new IllegalArgumentException(e); + } + javaToJsonMapping.put(constant, asString); + }); + } + + private Class getEnumType() { + return Class.class.cast(ParameterizedType.class.cast( + getClass().getGenericSuperclass()) + .getActualTypeArguments()[0]); + } + + @Override public void serialize(E obj, JsonGenerator generator, SerializationContext ctx) { + generator.write(javaToJsonMapping.get(obj)); + } +}