Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polymorphic JSON deserialization with Jackson #666

Open
mbechto opened this issue Sep 9, 2024 · 1 comment
Open

Polymorphic JSON deserialization with Jackson #666

mbechto opened this issue Sep 9, 2024 · 1 comment

Comments

@mbechto
Copy link

mbechto commented Sep 9, 2024

I was wondering how to write a polymorphic parser for JSON CloudEvents, where the payload can be one of many types.
Normally, with plain Jackson one can do something like this, using @JsonTypeInfo and a type field somewhere in the JSON to determine the specific class for deserialization.

In this simple example in the CloudEvent SDK docs we knew the type in advance:

PojoCloudEventData<User> cloudEventData = mapData(
    inputEvent,
    PojoCloudEventDataMapper.from(objectMapper,User.class)
);

But in my case, I would like to achieve something like the following:

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    property = "type"
)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Foo.class, name = "foo"),
    @JsonSubTypes.Type(value = Bar.class, name = "bar")
})
sealed interface Payload permits Foo, Bar {}

record Foo(String str) implements Payload {}
record Bar(int i) implements Payload {}

// ...

PojoCloudEventData<Payload> cloudEventData = mapData(
    inputEvent,
    PojoCloudEventDataMapper.from(objectMapper, Payload.class)
);

Running this code, it results in an error (as expected):

com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve subtype of [simple type, class Payload]: missing type id property 'type'

Because the type field is part of the CloudEvent header and/or envelope that Jackson does not know about at this point.

What's your take on this?

@gustavomonarin
Copy link

gustavomonarin commented Nov 1, 2024

@mbechto in previous versions, while using the structure mode with access to the object mapper, this could be achieved easily with a mixin by adding an external behavior to the cloudevents class.

I believe the same could be used somehow, but to be honest, i am having a hard time navigating PojoCloudEventData its Mapper and escipally CloudEvent complete excluding any generic type. Maybe could someone share the reasoning, i am sure there was.

For Mix in approach (pay attention on the JsonTypeInfo.As.EXTERNAL_PROPERTY):

the mixin interface:

public interface CloudEventMixin<T> {

    @JsonTypeId
    String getType();

    @JsonTypeInfo(
            use = JsonTypeInfo.Id.NAME,
            include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
            property = "type",
            defaultImpl = Void.class)
    @JsonSubTypes({
            // 
            @JsonSubTypes.Type(value = Foo.class, name = "fulltypenameespace.foo")})
   T getData();
   
}

So was just to register this interface to the CloudEvents interface, in this case we could do the same with the pojo, but i believe the sdk could help more here :(

    Json.MAPPER
        .addMixIn(io.cloudevents.v1.CloudEventImpl.class, CloudEventMixIn.class)

I believe this could work if adjust your annotations to an interface targeting the PojoCloudEventData instead of my CloudEvent focused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants