Merge pull request #792 from sharanggupta/fix-456-setter-error-message Fix #456: Do not call toString() of an object whose setter fails
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 c7870b7..cb49652 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,6 @@ /* * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026 Contributors to the Eclipse Foundation * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -112,11 +113,36 @@ //If the class instance and class of the field are the same and there has been generics specified for this field, //we need to use those instead of raw type. Class<?> rawType = ReflectionUtils.getRawType(type); + Customization customization = runtimeTypeCustomization(rawType, propertyCustomization); Class<?> rawLast = ReflectionUtils.getRawType(chain.getLast()); if (rawLast.equals(rawType)) { - return serializerChainInternal(chain, chain.getLast(), propertyCustomization, rootValue, isKey, true); + return serializerChainInternal(chain, chain.getLast(), customization, rootValue, isKey, true); } - return serializerChainInternal(chain, type, propertyCustomization, rootValue, isKey, true); + return serializerChainInternal(chain, type, customization, rootValue, isKey, true); + } + + /** + * Return the customization to create the serializer of a type only known at runtime with. + * The given customization is the one of the declared type, for example {@link Object} for the elements of a raw + * collection, so an adapter bound to the class of the runtime type with {@code @JsonbTypeAdapter} is taken from + * the customization of that class when the given customization binds neither a serializer nor an adapter. + * A serializer bound to the class with {@code @JsonbTypeSerializer} is already found by + * {@link ComponentMatcher#getSerializerBinding}. + * + * @param runtimeType runtime type of the value + * @param customization customization of the declared type + * @return customization to use + */ + private Customization runtimeTypeCustomization(Class<?> runtimeType, Customization customization) { + ComponentBoundCustomization declared = (ComponentBoundCustomization) customization; + if (declared != null + && (declared.getSerializerBinding() != null || declared.getSerializeAdapterBinding() != null)) { + return customization; + } + ClassCustomization classCustomization = jsonbContext.getMappingContext() + .getOrCreateClassModel(runtimeType) + .getClassCustomization(); + return classCustomization.getSerializeAdapterBinding() != null ? classCustomization : customization; } private ModelSerializer serializerChain(LinkedList<Type> chain,
diff --git a/src/test/java/org/eclipse/yasson/adapters/JsonbTypeAdapterTest.java b/src/test/java/org/eclipse/yasson/adapters/JsonbTypeAdapterTest.java index 3ee82da..4bfb142 100644 --- a/src/test/java/org/eclipse/yasson/adapters/JsonbTypeAdapterTest.java +++ b/src/test/java/org/eclipse/yasson/adapters/JsonbTypeAdapterTest.java
@@ -1,5 +1,6 @@ /* * Copyright (c) 2016, 2026 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026 Contributors to the Eclipse Foundation * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -19,6 +20,10 @@ import org.eclipse.yasson.TestTypeToken; import org.eclipse.yasson.adapters.model.*; +import java.util.List; + +import jakarta.json.bind.Jsonb; +import jakarta.json.bind.JsonbBuilder; import jakarta.json.bind.JsonbException; import jakarta.json.bind.adapter.JsonbAdapter; import jakarta.json.bind.annotation.JsonbTypeAdapter; @@ -127,6 +132,33 @@ public boolean bool; } + @JsonbTypeAdapter(AnnotatedTypeAdapter.class) + public static class AnnotatedType { + public String field = "value"; + } + + public static class AnnotatedTypeAdapter implements JsonbAdapter<AnnotatedType, String> { + + @Override + public String adaptToJson(AnnotatedType obj) { + return "adapted"; + } + + @Override + public AnnotatedType adaptFromJson(String obj) { + return new AnnotatedType(); + } + } + + @Test + public void testClassAdapterOfCollectionElement() throws Exception { + // Must use a new Jsonb instance to make sure adapter cache is empty + try (Jsonb jsonb = JsonbBuilder.create()) { + assertEquals("[\"adapted\"]", jsonb.toJson(List.of(new AnnotatedType()))); + assertEquals("\"adapted\"", jsonb.toJson(new AnnotatedType())); + } + } + @Test public void testPrimitiveDeserialzier() { String successfulJson = "{\"bool\":true}";
diff --git a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java index 8214b88..26a829a 100644 --- a/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java +++ b/src/test/java/org/eclipse/yasson/serializers/SerializersTest.java
@@ -1,5 +1,6 @@ /* * Copyright (c) 2016, 2025 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026 Contributors to the Eclipse Foundation * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -839,6 +840,27 @@ } + @JsonbTypeSerializer(SerializedTypeSerializer.class) + public static class SerializedType { + public String field = "value"; + } + + public static class SerializedTypeSerializer implements JsonbSerializer<SerializedType> { + @Override + public void serialize(SerializedType obj, JsonGenerator generator, SerializationContext ctx) { + generator.write("serialized"); + } + } + + @Test + public void testClassSerializerOfCollectionElement() throws Exception { + // Must use a new Jsonb instance to make sure serializer cache is empty + try (Jsonb jsonb = JsonbBuilder.create()) { + assertEquals("[\"serialized\"]", jsonb.toJson(List.of(new SerializedType()))); + assertEquals("\"serialized\"", jsonb.toJson(new SerializedType())); + } + } + /** * Test that annotation-based serializers work when property is declared as Object * but the runtime type has @JsonbTypeSerializer annotation.