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

[Java] [Jackson] discriminator is annotated with @JsonTypeId, which causes empty "type" on serialization #1190

Open
andreikubar opened this issue Sep 29, 2023 · 1 comment

Comments

@andreikubar
Copy link

We generate the oas3 schema from the java classes which use polymorphism. The schema that we get looks right:

{
    "openapi": "3.0.1",
    "info": {
        "title": "OpenAPI definition",
        "version": "v0"
    },
    "servers": [
        {
            "url": "http://localhost:8080",
            "description": "Generated server url"
        }
    ],
    "paths": {
        "/pets/{name}": {
            "get": {
                "tags": [
                    "Pets"
                ],
                "summary": "get a pet",
                "operationId": "getPet",
                "parameters": [
                    {
                        "name": "name",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "*/*": {
                                "schema": {
                                    "$ref": "#/components/schemas/PetResponse"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "Cat": {
                "type": "object",
                "allOf": [
                    {
                        "$ref": "#/components/schemas/Pet"
                    }
                ]
            },
            "Dog": {
                "type": "object",
                "allOf": [
                    {
                        "$ref": "#/components/schemas/Pet"
                    }
                ]
            },
            "Pet": {
                "required": [
                    "type"
                ],
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string"
                    },
                    "type": {
                        "type": "string"
                    }
                },
                "discriminator": {
                    "propertyName": "type"
                }
            },
            "PetResponse": {
                "type": "object",
                "properties": {
                    "pet": {
                        "oneOf": [
                            {
                                "$ref": "#/components/schemas/Cat"
                            },
                            {
                                "$ref": "#/components/schemas/Dog"
                            }
                        ]
                    }
                }
            }
        }
    }
}

The relevant source Java classes look like this:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Cat.class, name = "Cat"),
        @JsonSubTypes.Type(value = Dog.class, name = "Dog")
})
public abstract class Pet {
    public String name;
}

public class Dog extends Pet{

}

public class Cat extends Pet{

}

What we get from the codegen (we use swagger-codegen-maven-plugin version 3.0.46) is this:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", visible = true )
@JsonSubTypes({
        @JsonSubTypes.Type(value = Cat.class, name = "Cat"),
        @JsonSubTypes.Type(value = Dog.class, name = "Dog"),
})


public class Pet   {
  @JsonProperty("name")
  private String name = null;

  @JsonTypeId
  private String type = null;

...

When we serialize:

Cat cat = (Cat) new Cat().name("charly");
objectMapper.writeValueAsString(cat);

result looks like this:

{
  "type" : "",
  "name" : "charly"
}

For the serialization to work properly, I have to modify the generated Pet.java as follows:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", visible = true )
@JsonSubTypes({
        @JsonSubTypes.Type(value = Cat.class, name = "Cat"),
        @JsonSubTypes.Type(value = Dog.class, name = "Dog"),
})
@JsonIgnoreProperties(
        value = "type", // ignore manually set type, it will be automatically generated by Jackson during serialization
        allowSetters = true // allows the type to be set during deserialization
)

public class Pet   {
  @JsonProperty("name")
  private String name = null;

  private String type = null;

...

So I remove the @JsonTypeId and I add the @JsonIgnoreProperties for the type variable.
Which I think as how the code should be generated. @JsonTypeId marks a field for overriding the type id. So since type is null, we get an empty value in JSON. What should be done is that the discriminator property should be ignored, so that Jackson can populate it with the type name automatically.

Looks like the @JsonTypeId was added as result of this issue: #105 Back then it looks like Jackson was behaving differently and type was still populated. This looks however like it was an incorrect handling of @JsonTypeId on Jackson side.

@benatportland
Copy link

I've found the same. I'm having to provide my own templates to apply the workaround above.

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