From 3a5b85a6c53b83713b0a364238633eceb3d5d45e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kr=C3=A1l?= Date: Fri, 13 Jan 2023 09:25:14 +0100 Subject: [PATCH 1/2] User defined deserializer/serializer in collection (#588) User defined deserializer/serializer in collection Signed-off-by: David Kral --- .../DeserializationModelCreator.java | 5 +- .../serializer/SerializationModelCreator.java | 7 ++- .../yasson/serializers/SerializersTest.java | 17 +++++- .../yasson/serializers/model/Containee.java | 47 ++++++++++++++++ .../model/ContaineeDeserializer.java | 41 ++++++++++++++ .../model/ContaineeSerializer.java | 29 ++++++++++ .../yasson/serializers/model/Container.java | 55 +++++++++++++++++++ 7 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 src/test/java/org/eclipse/yasson/serializers/model/Containee.java create mode 100644 src/test/java/org/eclipse/yasson/serializers/model/ContaineeDeserializer.java create mode 100644 src/test/java/org/eclipse/yasson/serializers/model/ContaineeSerializer.java create mode 100644 src/test/java/org/eclipse/yasson/serializers/model/Container.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 e582a7412..0ac3f980a 100644 --- a/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -269,9 +269,10 @@ private ModelDeserializer createCollectionDeserializer(CachedItem ca ? ((ParameterizedType) type).getActualTypeArguments()[0] : Object.class; colType = ReflectionUtils.resolveType(chain, colType); + ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(ReflectionUtils.getRawType(colType)); ModelDeserializer typeProcessor = typeProcessor(chain, colType, - propertyCustomization, + classModel.getClassCustomization(), JustReturn.instance()); CollectionDeserializer collectionDeserializer = new CollectionDeserializer(typeProcessor); CollectionInstanceCreator instanceDeserializer = new CollectionInstanceCreator(collectionDeserializer, type); diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/SerializationModelCreator.java b/src/main/java/org/eclipse/yasson/internal/serializer/SerializationModelCreator.java index de8942e1f..315fe4a85 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/SerializationModelCreator.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/SerializationModelCreator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -286,7 +286,10 @@ private ModelSerializer createCollectionSerializer(LinkedList chain, Type colType = type instanceof ParameterizedType ? ((ParameterizedType) type).getActualTypeArguments()[0] : Object.class; - ModelSerializer typeSerializer = memberSerializer(chain, colType, customization, false); + Type resolvedKey = ReflectionUtils.resolveType(chain, colType); + Class rawClass = ReflectionUtils.getRawType(resolvedKey); + ClassModel classModel = jsonbContext.getMappingContext().getOrCreateClassModel(rawClass); + ModelSerializer typeSerializer = memberSerializer(chain, colType, classModel.getClassCustomization(), false); CollectionSerializer collectionSerializer = new CollectionSerializer(typeSerializer); KeyWriter keyWriter = new KeyWriter(collectionSerializer); NullVisibilitySwitcher nullVisibilitySwitcher = new NullVisibilitySwitcher(true, keyWriter); diff --git a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java index 8557f7615..db0efdf18 100644 --- a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java +++ b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -51,6 +51,8 @@ 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.Containee; +import org.eclipse.yasson.serializers.model.Container; import org.eclipse.yasson.serializers.model.Crate; import org.eclipse.yasson.serializers.model.CrateDeserializer; import org.eclipse.yasson.serializers.model.CrateDeserializerWithConversion; @@ -797,4 +799,17 @@ public void testBoxToArray() { assertThat(jsonb.toJson(box), is(expected)); } + @Test + public void testCustomSerializersInContainer(){ + Jsonb jsonb = JsonbBuilder.create(); + + Container expected = new Container(List.of(new Containee("k", "v"))); + + String expectedJson = jsonb.toJson(expected); + System.out.println(expectedJson); + + assertEquals(expected, jsonb.fromJson(expectedJson, Container.class)); + + } + } diff --git a/src/test/java/org/eclipse/yasson/serializers/model/Containee.java b/src/test/java/org/eclipse/yasson/serializers/model/Containee.java new file mode 100644 index 000000000..ada2d4668 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/serializers/model/Containee.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +package org.eclipse.yasson.serializers.model; + +import java.util.Objects; + +import jakarta.json.bind.annotation.JsonbTypeDeserializer; +import jakarta.json.bind.annotation.JsonbTypeSerializer; + +@JsonbTypeDeserializer(ContaineeDeserializer.class) +@JsonbTypeSerializer(ContaineeSerializer.class) +public class Containee { + final String key; + final String value; + + public Containee(String key, String value) { + this.key = key; + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Containee containee = (Containee) o; + return Objects.equals(key, containee.key) && Objects.equals(value, containee.value); + } + + @Override + public int hashCode() { + return Objects.hash(key, value); + } +} diff --git a/src/test/java/org/eclipse/yasson/serializers/model/ContaineeDeserializer.java b/src/test/java/org/eclipse/yasson/serializers/model/ContaineeDeserializer.java new file mode 100644 index 000000000..232738057 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/serializers/model/ContaineeDeserializer.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +package org.eclipse.yasson.serializers.model; + +import java.lang.reflect.Type; + +import jakarta.json.bind.serializer.DeserializationContext; +import jakarta.json.bind.serializer.JsonbDeserializer; +import jakarta.json.stream.JsonParser; + +public class ContaineeDeserializer implements JsonbDeserializer { + + @Override + public Containee deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { + String key = null; + String value = ""; + while (parser.hasNext()) { + var event = parser.next(); + if (event == JsonParser.Event.KEY_NAME && parser.getString().equals("key")) { + parser.next(); // move to VALUE + key = parser.getString(); + } else if (event == JsonParser.Event.KEY_NAME && parser.getString().equals("value")) { + parser.next(); // move to VALUE + value = parser.getString(); + } + } + assert key != null; + return new Containee(key, value); + } + +} diff --git a/src/test/java/org/eclipse/yasson/serializers/model/ContaineeSerializer.java b/src/test/java/org/eclipse/yasson/serializers/model/ContaineeSerializer.java new file mode 100644 index 000000000..152e9ab5d --- /dev/null +++ b/src/test/java/org/eclipse/yasson/serializers/model/ContaineeSerializer.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +package org.eclipse.yasson.serializers.model; + +import jakarta.json.bind.serializer.JsonbSerializer; +import jakarta.json.bind.serializer.SerializationContext; +import jakarta.json.stream.JsonGenerator; + +public class ContaineeSerializer implements JsonbSerializer { + + @Override + public void serialize(Containee obj, JsonGenerator generator, SerializationContext ctx) { + generator.writeStartObject(); + generator.write("key", obj.key); + generator.write("value", obj.value); + generator.writeEnd(); + } + +} diff --git a/src/test/java/org/eclipse/yasson/serializers/model/Container.java b/src/test/java/org/eclipse/yasson/serializers/model/Container.java new file mode 100644 index 000000000..8c732fba7 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/serializers/model/Container.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +package org.eclipse.yasson.serializers.model; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class Container { + + private List containees; + + public Container() { + containees = new ArrayList<>(); + } + + public Container(List containees) { + this.containees = containees; + } + + public void setContainees(List containees) { + this.containees = containees; + } + + public List getContainees() { + return containees; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Container container = (Container) o; + return Objects.equals(containees, container.containees); + } + + @Override + public int hashCode() { + return Objects.hash(containees); + } +} From 66bef0919e79f775fc34841b9aee89a6108bdbe8 Mon Sep 17 00:00:00 2001 From: Benjamin Marwell Date: Wed, 15 Feb 2023 12:53:15 +0100 Subject: [PATCH 2/2] @JsonbCreator uses PropertyNamingStrategy. (#584) Signed-off-by: Benjamin Marwell --- .../internal/AnnotationIntrospector.java | 27 +++++---- .../internal/ClassMultiReleaseExtension.java | 4 +- .../yasson/internal/MappingContext.java | 3 +- .../internal/ClassMultiReleaseExtension.java | 6 +- .../internal/AnnotationIntrospectorTest.java | 18 +++--- ...ntrospectorWithoutOptionalModulesTest.java | 21 ++++--- .../yasson/internal/ClassParserTest.java | 4 +- .../CarWithCreateNamingStrategyTest.java | 57 +++++++++++++++++++ 8 files changed, 107 insertions(+), 33 deletions(-) create mode 100644 src/test/java16/org/eclipse/yasson/records/CarWithCreateNamingStrategyTest.java diff --git a/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java b/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java index ba085194f..a71c1f24d 100644 --- a/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java +++ b/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java @@ -59,6 +59,7 @@ import jakarta.json.bind.annotation.JsonbTypeInfo; import jakarta.json.bind.annotation.JsonbTypeSerializer; import jakarta.json.bind.annotation.JsonbVisibility; +import jakarta.json.bind.config.PropertyNamingStrategy; import jakarta.json.bind.config.PropertyVisibilityStrategy; import jakarta.json.bind.serializer.JsonbDeserializer; import jakarta.json.bind.serializer.JsonbSerializer; @@ -152,10 +153,12 @@ private String getJsonbPropertyCustomizedName(Property property, JsonbAnnotatedE /** * Searches for JsonbCreator annotation on constructors and static methods. * - * @param clazz class to search + * @param clazz class to search + * @param propertyNamingStrategy The naming strategy to use for the ${@code JsonbConstructor} annotation, + * if set and no {@code JsonbProperty} annotations are present. * @return JsonbCreator metadata object */ - public JsonbCreator getCreator(Class clazz) { + public JsonbCreator getCreator(Class clazz, PropertyNamingStrategy propertyNamingStrategy) { JsonbCreator jsonbCreator = null; Constructor[] declaredConstructors = AccessController.doPrivileged((PrivilegedAction[]>) clazz::getDeclaredConstructors); @@ -164,7 +167,7 @@ public JsonbCreator getCreator(Class clazz) { final jakarta.json.bind.annotation.JsonbCreator annot = findAnnotation(constructor.getDeclaredAnnotations(), jakarta.json.bind.annotation.JsonbCreator.class); if (annot != null) { - jsonbCreator = createJsonbCreator(constructor, jsonbCreator, clazz); + jsonbCreator = createJsonbCreator(constructor, jsonbCreator, clazz, propertyNamingStrategy); } } @@ -179,11 +182,11 @@ public JsonbCreator getCreator(Class clazz) { method, clazz)); } - jsonbCreator = createJsonbCreator(method, jsonbCreator, clazz); + jsonbCreator = createJsonbCreator(method, jsonbCreator, clazz, propertyNamingStrategy); } } if (jsonbCreator == null) { - jsonbCreator = ClassMultiReleaseExtension.findCreator(clazz, declaredConstructors, this); + jsonbCreator = ClassMultiReleaseExtension.findCreator(clazz, declaredConstructors, this, propertyNamingStrategy); if (jsonbCreator == null) { jsonbCreator = constructorPropertiesIntrospector.getCreator(declaredConstructors); } @@ -191,7 +194,7 @@ public JsonbCreator getCreator(Class clazz) { return jsonbCreator; } - JsonbCreator createJsonbCreator(Executable executable, JsonbCreator existing, Class clazz) { + JsonbCreator createJsonbCreator(Executable executable, JsonbCreator existing, Class clazz, PropertyNamingStrategy propertyNamingStrategy) { if (existing != null) { throw new JsonbException(Messages.getMessage(MessageKeys.MULTIPLE_JSONB_CREATORS, clazz)); } @@ -205,7 +208,8 @@ JsonbCreator createJsonbCreator(Executable executable, JsonbCreator existing, Cl if (jsonbPropertyAnnotation != null && !jsonbPropertyAnnotation.value().isEmpty()) { creatorModels[i] = new CreatorModel(jsonbPropertyAnnotation.value(), parameter, executable, jsonbContext); } else { - creatorModels[i] = new CreatorModel(parameter.getName(), parameter, executable, jsonbContext); + final String translatedParameterName = propertyNamingStrategy.translateName(parameter.getName()); + creatorModels[i] = new CreatorModel(translatedParameterName, parameter, executable, jsonbContext); } } @@ -779,16 +783,19 @@ public Set> collectInterfaces(Class cls) { /** * Processes customizations. * - * @param clsElement Element to process. + * @param clsElement Element to process. + * @param propertyNamingStrategy The naming strategy to use for the ${@code JsonbConstructor} annotation, + * if set and no {@code JsonbProperty} annotations are present. * @return Populated {@link ClassCustomization} instance. */ public ClassCustomization introspectCustomization(JsonbAnnotatedElement> clsElement, - ClassCustomization parentCustomization) { + ClassCustomization parentCustomization, + PropertyNamingStrategy propertyNamingStrategy) { return ClassCustomization.builder() .nillable(isClassNillable(clsElement)) .dateTimeFormatter(getJsonbDateFormat(clsElement)) .numberFormatter(getJsonbNumberFormat(clsElement)) - .creator(getCreator(clsElement.getElement())) + .creator(getCreator(clsElement.getElement(), propertyNamingStrategy)) .propertyOrder(getPropertyOrder(clsElement)) .adapterBinding(getAdapterBinding(clsElement)) .serializerBinding(getSerializerBinding(clsElement)) diff --git a/src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java b/src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java index ee719e91b..d5df2f870 100644 --- a/src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java +++ b/src/main/java/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java @@ -18,6 +18,7 @@ import java.util.Optional; import jakarta.json.bind.JsonbException; +import jakarta.json.bind.config.PropertyNamingStrategy; import org.eclipse.yasson.internal.model.JsonbCreator; import org.eclipse.yasson.internal.model.Property; @@ -42,7 +43,8 @@ static boolean isSpecialAccessorMethod(Method method, Map clas static JsonbCreator findCreator(Class clazz, Constructor[] declaredConstructors, - AnnotationIntrospector introspector) { + AnnotationIntrospector introspector, + PropertyNamingStrategy propertyNamingStrategy) { return null; } diff --git a/src/main/java/org/eclipse/yasson/internal/MappingContext.java b/src/main/java/org/eclipse/yasson/internal/MappingContext.java index a480aca77..1a7b7233b 100644 --- a/src/main/java/org/eclipse/yasson/internal/MappingContext.java +++ b/src/main/java/org/eclipse/yasson/internal/MappingContext.java @@ -88,7 +88,8 @@ private static Function, ClassModel> createParseClassModelFunction(Clas .introspectCustomization(clsElement, parentClassModel == null ? ClassCustomization.empty() - : parentClassModel.getClassCustomization()); + : parentClassModel.getClassCustomization(), + jsonbContext.getConfigProperties().getPropertyNamingStrategy()); // PolymorphismSupport configPolymorphism = jsonbContext.getConfigProperties().getPolymorphismSupport(); // if (configPolymorphism != null) { // customization = mergeConfigAndAnnotationPolymorphism(configPolymorphism, diff --git a/src/main/java16/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java b/src/main/java16/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java index 35c7a89b0..d876a1e71 100644 --- a/src/main/java16/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java +++ b/src/main/java16/org/eclipse/yasson/internal/ClassMultiReleaseExtension.java @@ -18,6 +18,7 @@ import java.util.Optional; import jakarta.json.bind.JsonbException; +import jakarta.json.bind.config.PropertyNamingStrategy; import org.eclipse.yasson.internal.model.JsonbCreator; import org.eclipse.yasson.internal.model.Property; @@ -47,10 +48,11 @@ static boolean isSpecialAccessorMethod(Method method, Map clas static JsonbCreator findCreator(Class clazz, Constructor[] declaredConstructors, - AnnotationIntrospector introspector) { + AnnotationIntrospector introspector, + PropertyNamingStrategy propertyNamingStrategy) { if (clazz.isRecord()) { if (declaredConstructors.length == 1) { - return introspector.createJsonbCreator(declaredConstructors[0], null, clazz); + return introspector.createJsonbCreator(declaredConstructors[0], null, clazz, propertyNamingStrategy); } } return null; diff --git a/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorTest.java b/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorTest.java index 14201cf60..dd0cf0656 100644 --- a/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorTest.java +++ b/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -12,6 +12,7 @@ package org.eclipse.yasson.internal; +import jakarta.json.bind.config.PropertyNamingStrategy; import org.junit.jupiter.api.*; import static org.junit.jupiter.api.Assertions.*; @@ -40,6 +41,7 @@ */ public class AnnotationIntrospectorTest { private final JsonbContext jsonbContext = new JsonbContext(new JsonbConfig(), JsonProvider.provider()); + private final PropertyNamingStrategy propertyNamingStrategy = jsonbContext.getConfigProperties().getPropertyNamingStrategy(); /** * class under test. @@ -48,21 +50,21 @@ public class AnnotationIntrospectorTest { @Test public void testObjectShouldBeCreateableFromJsonbAnnotatedConstructor() { - JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAnnotatedConstructor.class); + JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAnnotatedConstructor.class, propertyNamingStrategy); assertParameters(ObjectWithJsonbCreatorAnnotatedConstructor.parameters(), creator); assertCreatedInstanceContainsAllParameters(ObjectWithJsonbCreatorAnnotatedConstructor.example(), creator); } @Test public void testObjectShouldBeCreateableFromJsonbAnnotatedStaticFactoryMethod() { - JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAnnotatedFactoryMethod.class); + JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAnnotatedFactoryMethod.class, propertyNamingStrategy); assertParameters(ObjectWithJsonbCreatorAnnotatedFactoryMethod.parameters(), creator); assertCreatedInstanceContainsAllParameters(ObjectWithJsonbCreatorAnnotatedFactoryMethod.example(), creator); } @Test public void testObjectShouldBeCreateableFromJsonbAnnotatedStaticFactoryMethodIgnoringConstructorPorperties() { - JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAndConstructorPropertiesAnnotation.class); + JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAndConstructorPropertiesAnnotation.class, propertyNamingStrategy); assertParameters(ObjectWithJsonbCreatorAndConstructorPropertiesAnnotation.parameters(), creator); assertCreatedInstanceContainsAllParameters(ObjectWithJsonbCreatorAndConstructorPropertiesAnnotation.example(), creator); } @@ -70,7 +72,7 @@ public void testObjectShouldBeCreateableFromJsonbAnnotatedStaticFactoryMethodIgn @Test public void testJsonbAnnotatedProtectedConstructorLeadsToAnException() { assertThrows(JsonbException.class, () -> { - JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAnnotatedProtectedConstructor.class); + JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAnnotatedProtectedConstructor.class, propertyNamingStrategy); assertCreatedInstanceContainsAllParameters(ObjectWithJsonbCreatorAnnotatedProtectedConstructor.example(), creator); }); } @@ -79,7 +81,7 @@ public void testJsonbAnnotatedProtectedConstructorLeadsToAnException() { @Disabled @Test public void testNoArgConstructorShouldBePreferredOverUnusableJsonbAnnotatedProtectedConstructor() { - JsonbCreator creator = instrospector.getCreator(ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor.class); + JsonbCreator creator = instrospector.getCreator(ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor.class, propertyNamingStrategy); assertParameters(ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor.parameters(), creator); assertCreatedInstanceContainsAllParameters(ObjectWithNoArgAndJsonbCreatorAnnotatedProtectedConstructor.example(), creator); } @@ -87,13 +89,13 @@ public void testNoArgConstructorShouldBePreferredOverUnusableJsonbAnnotatedProte @Test public void testMoreThanOneAnnotatedCreatorMethodShouldLeadToAnException() { assertThrows(JsonbException.class, - () -> instrospector.getCreator(ObjectWithTwoJsonbCreatorAnnotatedSpots.class), + () -> instrospector.getCreator(ObjectWithTwoJsonbCreatorAnnotatedSpots.class, propertyNamingStrategy), () -> "More than one @" + JsonbCreator.class.getSimpleName()); } @Test public void testCreatorShouldBeNullOnMissingConstructorAnnotation() { - assertNull(instrospector.getCreator(ObjectWithoutAnnotatedConstructor.class)); + assertNull(instrospector.getCreator(ObjectWithoutAnnotatedConstructor.class, propertyNamingStrategy)); } } diff --git a/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorWithoutOptionalModulesTest.java b/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorWithoutOptionalModulesTest.java index 8ec8fb335..95568109d 100644 --- a/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorWithoutOptionalModulesTest.java +++ b/src/test/java/org/eclipse/yasson/internal/AnnotationIntrospectorWithoutOptionalModulesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -12,19 +12,21 @@ package org.eclipse.yasson.internal; -import org.junit.jupiter.api.*; -import static org.junit.jupiter.api.Assertions.*; - import static org.eclipse.yasson.internal.AnnotationIntrospectorTestAsserts.assertCreatedInstanceContainsAllParameters; import static org.eclipse.yasson.internal.AnnotationIntrospectorTestAsserts.assertParameters; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.fail; + +import jakarta.json.bind.JsonbConfig; +import jakarta.json.bind.config.PropertyNamingStrategy; +import jakarta.json.spi.JsonProvider; import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithJsonbCreatorAnnotatedConstructor; import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithJsonbCreatorAnnotatedFactoryMethod; import org.eclipse.yasson.internal.AnnotationIntrospectorTestFixtures.ObjectWithoutAnnotatedConstructor; import org.eclipse.yasson.internal.model.JsonbCreator; -import jakarta.json.bind.JsonbConfig; -import jakarta.json.spi.JsonProvider; +import org.junit.jupiter.api.Test; /** * Tests the {@link AnnotationIntrospector} with missing optional module "java.deskop",
@@ -41,6 +43,7 @@ public class AnnotationIntrospectorWithoutOptionalModulesTest { * class under test. */ private static final AnnotationIntrospector instrospector = new AnnotationIntrospector(new JsonbContext(new JsonbConfig(), JsonProvider.provider())); + private final PropertyNamingStrategy propertyNamingStrategy = propertyName -> propertyName; @Test public void testNoConstructorPropertiesAnnotationWithoutOptionalModules() { @@ -55,19 +58,19 @@ public void testNoConstructorPropertiesAnnotationWithoutOptionalModules() { @Test public void testCreatorShouldBeNullOnMissingConstructorAnnotation() { - assertNull(instrospector.getCreator(ObjectWithoutAnnotatedConstructor.class)); + assertNull(instrospector.getCreator(ObjectWithoutAnnotatedConstructor.class, propertyNamingStrategy)); } @Test public void testObjectShouldBeCreateableFromJsonbAnnotatedConstructorWithoutOptionalModules() { - JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAnnotatedConstructor.class); + JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAnnotatedConstructor.class, propertyNamingStrategy); assertParameters(ObjectWithJsonbCreatorAnnotatedConstructor.parameters(), creator); assertCreatedInstanceContainsAllParameters(ObjectWithJsonbCreatorAnnotatedConstructor.example(), creator); } @Test public void testObjectShouldBeCreateableFromJsonbAnnotatedStaticFactoryMethodWithoutOptionalModules() { - JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAnnotatedFactoryMethod.class); + JsonbCreator creator = instrospector.getCreator(ObjectWithJsonbCreatorAnnotatedFactoryMethod.class, propertyNamingStrategy); assertParameters(ObjectWithJsonbCreatorAnnotatedFactoryMethod.parameters(), creator); assertCreatedInstanceContainsAllParameters(ObjectWithJsonbCreatorAnnotatedFactoryMethod.example(), creator); } diff --git a/src/test/java/org/eclipse/yasson/internal/ClassParserTest.java b/src/test/java/org/eclipse/yasson/internal/ClassParserTest.java index 5dd8f42e0..0e866252d 100644 --- a/src/test/java/org/eclipse/yasson/internal/ClassParserTest.java +++ b/src/test/java/org/eclipse/yasson/internal/ClassParserTest.java @@ -40,7 +40,7 @@ public class ClassParserTest { public void testDefaultMappingFieldModifiers() { final JsonbAnnotatedElement> clsElement = introspector.collectAnnotations(FieldModifiersClass.class); ClassModel model = new ClassModel(FieldModifiersClass.class, introspector.introspectCustomization(clsElement, - ClassCustomization.empty()), null, null); + ClassCustomization.empty(), jsonbContext.getConfigProperties().getPropertyNamingStrategy()), null, null); classParser.parseProperties(model, clsElement); assertTrue(model.getPropertyModel("finalString").isReadable()); assertFalse(model.getPropertyModel("finalString").isWritable()); @@ -54,7 +54,7 @@ public void testDefaultMappingFieldModifiers() { public void testDefaultMappingMethodModifiers() { final JsonbAnnotatedElement> clsElement = introspector.collectAnnotations(MethodModifiersClass.class); ClassModel model = new ClassModel(FieldModifiersClass.class, introspector.introspectCustomization(clsElement, - ClassCustomization.empty()), null, null); + ClassCustomization.empty(), jsonbContext.getConfigProperties().getPropertyNamingStrategy()), null, null); classParser.parseProperties(model, clsElement); assertFalse(model.getPropertyModel("publicFieldWithPrivateMethods").isReadable()); assertFalse(model.getPropertyModel("publicFieldWithPrivateMethods").isWritable()); diff --git a/src/test/java16/org/eclipse/yasson/records/CarWithCreateNamingStrategyTest.java b/src/test/java16/org/eclipse/yasson/records/CarWithCreateNamingStrategyTest.java new file mode 100644 index 000000000..1fbd17dd1 --- /dev/null +++ b/src/test/java16/org/eclipse/yasson/records/CarWithCreateNamingStrategyTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +package org.eclipse.yasson.records; + +import jakarta.json.bind.Jsonb; +import jakarta.json.bind.JsonbBuilder; +import jakarta.json.bind.JsonbConfig; +import jakarta.json.bind.annotation.JsonbCreator; +import jakarta.json.bind.config.PropertyNamingStrategy; +import org.junit.jupiter.api.Test; + +import static java.util.Objects.requireNonNull; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CarWithCreateNamingStrategyTest { + + // camel case is intentional for this test case + public record Car(String brandName, String colorName) { + + @JsonbCreator + public Car { + requireNonNull(brandName, "brandName"); + requireNonNull(colorName, "colorName"); + } + } + + @Test + public void testRecordJsonbCreatorWithNamingStrategy() { + // given + final JsonbConfig config = new JsonbConfig() + .withPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE_WITH_UNDERSCORES); + final Jsonb jsonb = JsonbBuilder.create(config); + + var json = """ + { + "brand_name": "Volkswagen", + "color_name": "Piano black" + } + """; + + // when + final Car car = jsonb.fromJson(json, Car.class); + + // then + assertEquals("Volkswagen", car.brandName()); + assertEquals("Piano black", car.colorName()); + } +}