Skip to content

[BUG][JAVA][resteasy][jaxrs-spec] additionalProperties extends HashMap causes deserialization issues #22345

@blaghed

Description

@blaghed

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
Description

Using additionalProperties: true in java / resteasy and jaxrs-spec causes the object to be generated with extends HashMap.
Jackson's ObjectMapper is then used to perform the ser/deser.
When this is serialized from Object -> JSON, it works fine and the additional values get put into the JSON.
When it is deserialized, though, the entire object structure is put into the HashMap, ignoring the normal properties already in place.

openapi-generator version

v7.17.0 (and older)

OpenAPI declaration file content or url
components:
  schemas:
    someResponse:
      type: object
      additionalProperties: true
      properties:
        property1:
          type: string
        property2:
          type: string
someResponse.setProperty1("p1");
someResponse.setProperty2("p2");

Deserialization results in:

{
    "property1": "p1", 
    "property2": "p2"
}

Serialization results in:

someResponse.getProperty1() == null
someResponse.getProperty2() == null
someResponse.get("property1") == "p1"
someResponse.get("property2") == "p2"
Related issues/PRs

Link to an old report in StackOverflow of the same issue, 7 years ago, as it is still happening exactly as described there:
https://stackoverflow.com/questions/47850441/openapi-swagger-codegen-additionnalproperties-extends-hashmap-playjackson-de

Suggest a fix

Ideally an approach like in the Spring generated code is used, where additionalProperties is an internal field instead of resulting in an extends HashMap.
Can cause backwards-compatibility issues, so it would also be ok to have a toggle to activate this behaviour, leaving the default still with HashMap.

Alternatively, a solution can also use the approach as suggested by Jackson:
FasterXML/jackson-databind#3173
Example:

@JsonFormat(shape=JsonFormat.Shape.OBJECT)
public class SomeResponse extends HashMap<String, Object> {

  private String property1;
  private String property2;
  (...)
  
  @JsonAnySetter
  public SomeResponse putAdditionalProperty(String key, Object value) {
    this.put(key, value);
    return this;
  }

  @JsonAnyGetter
  public Map<String, Object> getAdditionalProperties() {
    return this;
  }
  
  public Object getAdditionalProperty(String key) {
    return this.get(key);
  }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions