Skip to content

Annotation-based serializers not applied to Object-typed properties with specific runtime types #689

@jamezp

Description

@jamezp

Describe the bug

Custom serializers registered via @JsonbTypeSerializer annotation are not applied to properties declared as Object type but containing instances of the serializer's target type at runtime. The serializer only works for properties with the exact declared type matching the annotated class.

To Reproduce

import jakarta.json.bind.*;
import jakarta.json.bind.annotation.JsonbTypeSerializer;
import jakarta.json.bind.serializer.*;
import jakarta.json.stream.JsonGenerator;

public class SerializerBugDemo {

    @JsonbTypeSerializer(MyClassSerializer.class)
    public static class MyClass { }

    public static class Container {
        private final MyClass single = new MyClass();
        private final Object singleAsObject = single;  // Same instance, different declared type

        public MyClass getSingle() { return single; }
        public Object getSingleAsObject() { return singleAsObject; }
    }

    public static class MyClassSerializer implements JsonbSerializer<MyClass> {
        @Override
        public void serialize(MyClass obj, JsonGenerator generator, SerializationContext ctx) {
            generator.write("MyClassSerialized");
        }
    }

    public static void main(String[] args) {
        try (Jsonb jsonb = JsonbBuilder.create()) {
            Container container = new Container();
            String result = jsonb.toJson(container);
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Expected behavior

The serializer should be applied to both properties:

{"single":"MyClassSerialized","singleAsObject":"MyClassSerialized"}

The singleAsObject property should use the MyClassSerializer because at runtime it contains a MyClass instance, even though the property is declared as Object.

Actual behavior

{"single":"MyClassSerialized","singleAsObject":{}}

The annotation-based serializer only works for the directly-typed property, not for the Object-typed property that contains the same instance.

System information:

  • OS: Linux (reproduced on Fedora 43)
  • Java Version: 17+
  • Yasson Version: 3.0.4

Additional context

The bug occurs in ComponentMatcher.java in the getSerializerBinding() and getDeserializerBinding() methods. When a customization binding exists (from the annotation) but doesn't exactly match the runtime type, the methods return Optional.empty() instead of returning the customization binding.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working right

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions