Search code examples
javajacksonopenapiswagger-codegen

Deserializing with Jackson (fail on unknown properties) does not ignore discriminator property (DTO's created with SwaggerCodegen)


EDIT:

I found the problem: I have to find a way to make swagger Codegen remove the "visible = true" part when it generates the java class. If i remove that manually it works. Problem is that the classes generate at compile-time and that modification will be overridden.

Stil need help!

Initial post:

I have the following:

  • a Reception entity class that has a List. Checkpoint is the base class, but it will only contain subclasses like Checkpoint1, Checkpoint2 etc.

  • a ReceptionCotroller that has an HTTP POST method mapped by "/receptions".

  • DTO classes for Reception and Checkpoints (Checkpoint base class, Checkpoint1, Checkpoint2 etc) generated with Swagger CodeGen openapi 3.0.2. using a yml file. The Checkpoint DTO has a discriminator field (in the yml file) named "dtype" so when deserializing the JSON into a Checkpoint, it knows what subclass it refers to.

The problem is when I add the property: spring.jackson.deserialization.fail-on-unknown-properties = true, it does not recognize the "dtype" property and it fails. I want the application to fail when it encounters unknown properties, but to ignore the "dtype".

I've tried to add a dtype field (beside the discriminator definition) in the Checkpoint DTO but then the JSON that returns as a response has 2 dtype fields (one with the discriminator value, and one with null).

Reception and Checkpoint in yml file:

Reception:
      description: description1
      type: object
      properties:
        id:
          type: integer
          format: int64
          description: Id of the reception.
        checkpoints:
          type: array
          items:
            oneOf:
              - $ref: '#/components/schemas/Checkpoint1'
              - $ref: '#/components/schemas/Checkpoint2'
            discriminator:
              propertyName: dtype
            $ref: '#/components/schemas/Checkpoint'
          description: List of checkpoints attached to this reception.
Checkpoint:
      description: Checkpoint entity.
      type: object
      properties:
        checkpointId:
          type: string
          description: description1.
      required:
        - checkpointId
        - dtype
      discriminator:
        propertyName: dtype

Generated Checkpoint DTO class:

@ApiModel(description = "Checkpoint entity.")
@Validated
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "dtype", visible = true )
@JsonSubTypes({
  @JsonSubTypes.Type(value = Checkpoint1.class, name = "Checkpoint1"),
  @JsonSubTypes.Type(value = Checkpoint2.class, name = "Checkpoint2")
})
public class Checkpoint   {
  @JsonProperty("dtype")
  private String dtype = null;

  @JsonProperty("checkpointId")
  private String checkpointId = null;

(.....)

Json sent as request body:

{
    "id": 123,
    "checkpoints": [
        {
            "dtype": "Checkpoint1",
            "checkpointId": "Checkpoint1"
                }
    }

It says that it does not recognize dtype field. I want it to create the appropriate Checkpoint object, but ignore that the Checkpoint DTO does not actually contain a dtype field in the generated class. I DO NOT want it to ignore OTHER unknown properties. For example: if i add another "fooBar" field in the JSON, I want it to fail.

Hope the information provided is ok to understand what my problem is. If not, I can give further information.

Many thanks in advance!! PS: Please ignore eventual syntax errors or typos, the code works and copiles correctly, but i don't know how to ignore ONLY the discriminator (dtype) property.


Solution

  • There are two ways you could get this done.
    First :
    If you are allowed to change the auto generated java code, you can add the annotation @JsonIgnoreProperties(value = ["dtype"]) to all the classes that have discriminator fields like below.

    @JsonIgnoreProperties(value = ["dtype"])
    public class Checkpoint   {
    //your properties here
    }
    

    An example implementation : Use of JsonIgnoreProperties specific property deserialize properties exists only in JSON The question has a sample implementation

    Second:
    If you are not allowed to edit the autogenerated java code, you can use Jackson Mixins to ignore specific unwanted fields .

    @JsonIgnoreProperties(value = ["dtype"])
    public abstract class CheckpointMixin {}
    

    and in your object mapper register this mixin for the target class like below :

    mapper.addMixIn(Checkpoint::class.java, CheckpointMixin::class.java)
    

    I tried it out in kotlin and it worked as expected. Please ignore any syntactical inaccuraces.