swagger-api / swagger-codegen

swagger-codegen contains a template-driven engine to generate documentation, API clients and server stubs in different languages by parsing your OpenAPI / Swagger definition.
http://swagger.io
Apache License 2.0
16.88k stars 6.03k forks source link

[codegen][JAVA] Generated model with both properties and additionalProperties of differing types cannot be deserialized #8036

Open kaspersorensen opened 6 years ago

kaspersorensen commented 6 years ago
Description

When a definition in Swagger contains both regular properties (with complex value types) and additionalProperties with type string, then the generated Java model class cannot deserialized by e.g. Jackson since the class extends HashMap<String,String> and it's complex values are being "set" as a String.

A better way of generating the class would probably be that the model class has a Map<String,String> field/member which additional properties are deserialized into.

Swagger-codegen version

2.3.1

Swagger declaration file content or url

Example swagger file where the generated Java class extends HashMap<String,String> which then breaks deserialization of the codes object:

swagger: '2.0'
info:
  version: 1.0.0
  title: Example
paths:
  /foo:
    get:
      responses:
        '200':
          description: OK
          schema:
            $ref: '#/definitions/ExampleResponse'
definitions:
  ExampleResponse:
    type: object
    additionalProperties:
      type: string
    properties:
      codes:
        type: object
        description: An object containing various codes
        example:
          foo: bar
          hello: world
Maven config used for generation
            <plugin>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-codegen-maven-plugin</artifactId>
                <version>2.3.1</version>
                <configuration>
                    <groupId>${project.groupId}</groupId>
                    <language>java</language>
                    <generateApis>false</generateApis>
                    <library>jersey2</library>
                    <configOptions>
                        <dateLibrary>java8</dateLibrary>
                        <useBeanValidation>true</useBeanValidation>
                        <useJaxbAnnotations>true</useJaxbAnnotations>
                    </configOptions>
                </configuration>
            </plugin>
Suggest a fix/enhancement

I've worked around this issue in my project by having a customized mustache file without using the parent mustache property. I'm not sure what side-effects that may have for other projects though.

kaspersorensen commented 6 years ago

For reference, here's the type of exception that Jackson will report:

Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
 at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 1, column: 43] (through reference chain: example.model.ExampleResponse["codes"])
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
    at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1342)
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1138)
    at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1092)
    at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:63)
    at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:10)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:527)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:364)
    at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:29)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
hkosova commented 4 years ago

Related (or duplicate of): #5187