swagger-api / swagger-core

Examples and server integrations for generating the Swagger API Specification, which enables easy access to your REST API
http://swagger.io
Apache License 2.0
7.37k stars 2.17k forks source link

Swagger parser ignores @Schema.description for reference objects #4540

Closed woltariel closed 10 months ago

woltariel commented 10 months ago

When using descriptions @Schema.description for object types e.g.:

@field:Schema(
    description = "Total basket price",
    example = EXAMPLE_BASKET_PRICE,
)
val basketPrice: BasketPrice,

the generated spec completely ignores this description and example:

"basketPrice" : {
  "$ref" : "#/components/schemas/BasketPrice"
},

We are using swagger-core-2.2.18 and swagger-parser-2.1.18 and the model resolver is configured to use open API 3.1. Considering the Open Api Spec 3.1 allows descriptions for reference objects shouldn't these show up in the generated spec?

frantuma commented 10 months ago

this should work, when correctly setting flag openapi31 for the environment, can you provide a test case reproducing the issue, including all config and project setup?

woltariel commented 10 months ago

Full project is here https://github.com/woltariel/test-swagger31-generation

I created the following model:


data class Model(val id: String,
                 @Schema(description = "this is a test for ref description in model")
                 val modelChild: ModelChild)

data class ModelChild(val id: String)

and to generate the spec:

class SwaggerGenerator {

    private val context = ModelConverterContextImpl(ModelResolver(ObjectMapper()).openapi31(true))

    fun generate() {
        val modelClasses = listOf(Model::class.java, ModelChild::class.java)
        modelClasses.forEach { context.resolve(AnnotatedType(it)) }
        println(context.definedModels)
    }
}

and the output doesn't include this is a test for ref description in model anywhere:

2023-11-08 11:53:54.199 [main] TRACE i.s.v.c.c.ModelConverterContextImpl - defineModel Model class Schema {
    type: object
    format: null
    $ref: null
    description: null
    title: null
    multipleOf: null
    maximum: null
    exclusiveMaximum: null
    minimum: null
    exclusiveMinimum: null
    maxLength: null
    minLength: null
    pattern: null
    maxItems: null
    minItems: null
    uniqueItems: null
    maxProperties: null
    minProperties: null
    required: null
    not: null
    properties: null
    additionalProperties: null
    nullable: null
    readOnly: null
    writeOnly: null
    example: null
    externalDocs: null
    deprecated: null
    discriminator: null
    xml: null
}
2023-11-08 11:53:54.201 [main] DEBUG i.s.v.c.c.ModelConverterContextImpl - resolve [simple type, class java.lang.String]
2023-11-08 11:53:54.201 [main] TRACE i.s.v.c.c.ModelConverterContextImpl - trying extension io.swagger.v3.core.jackson.ModelResolver@7922d892
2023-11-08 11:53:54.201 [main] TRACE i.s.v3.core.jackson.ModelResolver - Can't check class [simple type, class java.lang.String], java.lang.String
2023-11-08 11:53:54.258 [main] DEBUG i.s.v.c.c.ModelConverterContextImpl - resolve [simple type, class com.example.swagger.ModelChild]
2023-11-08 11:53:54.258 [main] TRACE i.s.v.c.c.ModelConverterContextImpl - trying extension io.swagger.v3.core.jackson.ModelResolver@7922d892
2023-11-08 11:53:54.258 [main] TRACE i.s.v3.core.jackson.ModelResolver - Can't check class [simple type, class com.example.swagger.ModelChild], com.example.swagger.ModelChild
2023-11-08 11:53:54.258 [main] TRACE i.s.v.c.c.ModelConverterContextImpl - defineModel ModelChild class Schema {
    type: object
    format: null
    $ref: null
    description: null
    title: null
    multipleOf: null
    maximum: null
    exclusiveMaximum: null
    minimum: null
    exclusiveMinimum: null
    maxLength: null
    minLength: null
    pattern: null
    maxItems: null
    minItems: null
    uniqueItems: null
    maxProperties: null
    minProperties: null
    required: null
    not: null
    properties: null
    additionalProperties: null
    nullable: null
    readOnly: null
    writeOnly: null
    example: null
    externalDocs: null
    deprecated: null
    discriminator: null
    xml: null
}
2023-11-08 11:53:54.258 [main] TRACE i.s.v.c.c.ModelConverterContextImpl - defineModel ModelChild class Schema {
    type: object
    format: null
    $ref: null
    description: null
    title: null
    multipleOf: null
    maximum: null
    exclusiveMaximum: null
    minimum: null
    exclusiveMinimum: null
    maxLength: null
    minLength: null
    pattern: null
    maxItems: null
    minItems: null
    uniqueItems: null
    maxProperties: null
    minProperties: null
    required: null
    not: null
    properties: {id=class JsonSchema {
        class Schema {
            type: [string]
            format: null
            $ref: null
            description: null
            title: null
            multipleOf: null
            maximum: null
            exclusiveMaximum: null
            minimum: null
            exclusiveMinimum: null
            maxLength: null
            minLength: null
            pattern: null
            maxItems: null
            minItems: null
            uniqueItems: null
            maxProperties: null
            minProperties: null
            required: null
            not: null
            properties: null
            additionalProperties: null
            nullable: null
            readOnly: null
            writeOnly: null
            example: null
            externalDocs: null
            deprecated: null
            discriminator: null
            xml: null
            patternProperties: null
            contains: null
            $id: null
            $anchor: null
            $schema: null
            $vocabulary: null
            $dynamicAnchor: null
            const: null
            contentEncoding: null
            contentMediaType: null
            contentSchema: null
            propertyNames: null
            unevaluatedProperties: null
            maxContains: null
            minContains: null
            additionalItems: null
            unevaluatedItems: null
            _if: null
            _else: null
            then: null
            dependentRequired: null
            dependentSchemas: null
            $comment: null
            prefixItems: null
        }
    }}
    additionalProperties: null
    nullable: null
    readOnly: null
    writeOnly: null
    example: null
    externalDocs: null
    deprecated: null
    discriminator: null
    xml: null
}
2023-11-08 11:53:54.259 [main] TRACE i.s.v.c.c.ModelConverterContextImpl - defineModel ModelChild class Schema {
    type: object
    format: null
    $ref: null
    description: null
    title: null
    multipleOf: null
    maximum: null
    exclusiveMaximum: null
    minimum: null
    exclusiveMinimum: null
    maxLength: null
    minLength: null
    pattern: null
    maxItems: null
    minItems: null
    uniqueItems: null
    maxProperties: null
    minProperties: null
    required: null
    not: null
    properties: {id=class JsonSchema {
        class Schema {
            type: [string]
            format: null
            $ref: null
            description: null
            title: null
            multipleOf: null
            maximum: null
            exclusiveMaximum: null
            minimum: null
            exclusiveMinimum: null
            maxLength: null
            minLength: null
            pattern: null
            maxItems: null
            minItems: null
            uniqueItems: null
            maxProperties: null
            minProperties: null
            required: null
            not: null
            properties: null
            additionalProperties: null
            nullable: null
            readOnly: null
            writeOnly: null
            example: null
            externalDocs: null
            deprecated: null
            discriminator: null
            xml: null
            patternProperties: null
            contains: null
            $id: null
            $anchor: null
            $schema: null
            $vocabulary: null
            $dynamicAnchor: null
            const: null
            contentEncoding: null
            contentMediaType: null
            contentSchema: null
            propertyNames: null
            unevaluatedProperties: null
            maxContains: null
            minContains: null
            additionalItems: null
            unevaluatedItems: null
            _if: null
            _else: null
            then: null
            dependentRequired: null
            dependentSchemas: null
            $comment: null
            prefixItems: null
        }
    }}
    additionalProperties: null
    nullable: null
    readOnly: null
    writeOnly: null
    example: null
    externalDocs: null
    deprecated: null
    discriminator: null
    xml: null
}
2023-11-08 11:53:54.266 [main] TRACE i.s.v.c.c.ModelConverterContextImpl - defineModel Model class Schema {
    type: object
    format: null
    $ref: null
    description: null
    title: null
    multipleOf: null
    maximum: null
    exclusiveMaximum: null
    minimum: null
    exclusiveMinimum: null
    maxLength: null
    minLength: null
    pattern: null
    maxItems: null
    minItems: null
    uniqueItems: null
    maxProperties: null
    minProperties: null
    required: null
    not: null
    properties: {id=class JsonSchema {
        class Schema {
            type: [string]
            format: null
            $ref: null
            description: null
            title: null
            multipleOf: null
            maximum: null
            exclusiveMaximum: null
            minimum: null
            exclusiveMinimum: null
            maxLength: null
            minLength: null
            pattern: null
            maxItems: null
            minItems: null
            uniqueItems: null
            maxProperties: null
            minProperties: null
            required: null
            not: null
            properties: null
            additionalProperties: null
            nullable: null
            readOnly: null
            writeOnly: null
            example: null
            externalDocs: null
            deprecated: null
            discriminator: null
            xml: null
            patternProperties: null
            contains: null
            $id: null
            $anchor: null
            $schema: null
            $vocabulary: null
            $dynamicAnchor: null
            const: null
            contentEncoding: null
            contentMediaType: null
            contentSchema: null
            propertyNames: null
            unevaluatedProperties: null
            maxContains: null
            minContains: null
            additionalItems: null
            unevaluatedItems: null
            _if: null
            _else: null
            then: null
            dependentRequired: null
            dependentSchemas: null
            $comment: null
            prefixItems: null
        }
    }, modelChild=class JsonSchema {
        class Schema {
            type: null
            format: null
            $ref: #/components/schemas/ModelChild
            description: null
            title: null
            multipleOf: null
            maximum: null
            exclusiveMaximum: null
            minimum: null
            exclusiveMinimum: null
            maxLength: null
            minLength: null
            pattern: null
            maxItems: null
            minItems: null
            uniqueItems: null
            maxProperties: null
            minProperties: null
            required: null
            not: null
            properties: null
            additionalProperties: null
            nullable: null
            readOnly: null
            writeOnly: null
            example: null
            externalDocs: null
            deprecated: null
            discriminator: null
            xml: null
            patternProperties: null
            contains: null
            $id: null
            $anchor: null
            $schema: null
            $vocabulary: null
            $dynamicAnchor: null
            const: null
            contentEncoding: null
            contentMediaType: null
            contentSchema: null
            propertyNames: null
            unevaluatedProperties: null
            maxContains: null
            minContains: null
            additionalItems: null
            unevaluatedItems: null
            _if: null
            _else: null
            then: null
            dependentRequired: null
            dependentSchemas: null
            $comment: null
            prefixItems: null
        }
    }}
    additionalProperties: null
    nullable: null
    readOnly: null
    writeOnly: null
    example: null
    externalDocs: null
    deprecated: null
    discriminator: null
    xml: null
}
2023-11-08 11:53:54.266 [main] TRACE i.s.v.c.c.ModelConverterContextImpl - defineModel Model class Schema {
    type: object
    format: null
    $ref: null
    description: null
    title: null
    multipleOf: null
    maximum: null
    exclusiveMaximum: null
    minimum: null
    exclusiveMinimum: null
    maxLength: null
    minLength: null
    pattern: null
    maxItems: null
    minItems: null
    uniqueItems: null
    maxProperties: null
    minProperties: null
    required: null
    not: null
    properties: {id=class JsonSchema {
        class Schema {
            type: [string]
            format: null
            $ref: null
            description: null
            title: null
            multipleOf: null
            maximum: null
            exclusiveMaximum: null
            minimum: null
            exclusiveMinimum: null
            maxLength: null
            minLength: null
            pattern: null
            maxItems: null
            minItems: null
            uniqueItems: null
            maxProperties: null
            minProperties: null
            required: null
            not: null
            properties: null
            additionalProperties: null
            nullable: null
            readOnly: null
            writeOnly: null
            example: null
            externalDocs: null
            deprecated: null
            discriminator: null
            xml: null
            patternProperties: null
            contains: null
            $id: null
            $anchor: null
            $schema: null
            $vocabulary: null
            $dynamicAnchor: null
            const: null
            contentEncoding: null
            contentMediaType: null
            contentSchema: null
            propertyNames: null
            unevaluatedProperties: null
            maxContains: null
            minContains: null
            additionalItems: null
            unevaluatedItems: null
            _if: null
            _else: null
            then: null
            dependentRequired: null
            dependentSchemas: null
            $comment: null
            prefixItems: null
        }
    }, modelChild=class JsonSchema {
        class Schema {
            type: null
            format: null
            $ref: #/components/schemas/ModelChild
            description: null
            title: null
            multipleOf: null
            maximum: null
            exclusiveMaximum: null
            minimum: null
            exclusiveMinimum: null
            maxLength: null
            minLength: null
            pattern: null
            maxItems: null
            minItems: null
            uniqueItems: null
            maxProperties: null
            minProperties: null
            required: null
            not: null
            properties: null
            additionalProperties: null
            nullable: null
            readOnly: null
            writeOnly: null
            example: null
            externalDocs: null
            deprecated: null
            discriminator: null
            xml: null
            patternProperties: null
            contains: null
            $id: null
            $anchor: null
            $schema: null
            $vocabulary: null
            $dynamicAnchor: null
            const: null
            contentEncoding: null
            contentMediaType: null
            contentSchema: null
            propertyNames: null
            unevaluatedProperties: null
            maxContains: null
            minContains: null
            additionalItems: null
            unevaluatedItems: null
            _if: null
            _else: null
            then: null
            dependentRequired: null
            dependentSchemas: null
            $comment: null
            prefixItems: null
        }
    }}
    additionalProperties: null
    nullable: null
    readOnly: null
    writeOnly: null
    example: null
    externalDocs: null
    deprecated: null
    discriminator: null
    xml: null
}
2023-11-08 11:53:54.266 [main] DEBUG i.s.v.c.c.ModelConverterContextImpl - resolve class com.example.swagger.ModelChild
2023-11-08 11:53:54.266 [main] TRACE i.s.v.c.c.ModelConverterContextImpl - trying extension io.swagger.v3.core.jackson.ModelResolver@7922d892
2023-11-08 11:53:54.266 [main] TRACE i.s.v.c.c.ModelConverterContextImpl - defineModel ModelChild class Schema {
    type: object
    format: null
    $ref: null
    description: null
    title: null
    multipleOf: null
    maximum: null
    exclusiveMaximum: null
    minimum: null
    exclusiveMinimum: null
    maxLength: null
    minLength: null
    pattern: null
    maxItems: null
    minItems: null
    uniqueItems: null
    maxProperties: null
    minProperties: null
    required: null
    not: null
    properties: null
    additionalProperties: null
    nullable: null
    readOnly: null
    writeOnly: null
    example: null
    externalDocs: null
    deprecated: null
    discriminator: null
    xml: null
}
2023-11-08 11:53:54.267 [main] TRACE i.s.v.c.c.ModelConverterContextImpl - defineModel ModelChild class Schema {
    type: object
    format: null
    $ref: null
    description: null
    title: null
    multipleOf: null
    maximum: null
    exclusiveMaximum: null
    minimum: null
    exclusiveMinimum: null
    maxLength: null
    minLength: null
    pattern: null
    maxItems: null
    minItems: null
    uniqueItems: null
    maxProperties: null
    minProperties: null
    required: null
    not: null
    properties: {id=class JsonSchema {
        class Schema {
            type: [string]
            format: null
            $ref: null
            description: null
            title: null
            multipleOf: null
            maximum: null
            exclusiveMaximum: null
            minimum: null
            exclusiveMinimum: null
            maxLength: null
            minLength: null
            pattern: null
            maxItems: null
            minItems: null
            uniqueItems: null
            maxProperties: null
            minProperties: null
            required: null
            not: null
            properties: null
            additionalProperties: null
            nullable: null
            readOnly: null
            writeOnly: null
            example: null
            externalDocs: null
            deprecated: null
            discriminator: null
            xml: null
            patternProperties: null
            contains: null
            $id: null
            $anchor: null
            $schema: null
            $vocabulary: null
            $dynamicAnchor: null
            const: null
            contentEncoding: null
            contentMediaType: null
            contentSchema: null
            propertyNames: null
            unevaluatedProperties: null
            maxContains: null
            minContains: null
            additionalItems: null
            unevaluatedItems: null
            _if: null
            _else: null
            then: null
            dependentRequired: null
            dependentSchemas: null
            $comment: null
            prefixItems: null
        }
    }}
    additionalProperties: null
    nullable: null
    readOnly: null
    writeOnly: null
    example: null
    externalDocs: null
    deprecated: null
    discriminator: null
    xml: null
}
2023-11-08 11:53:54.267 [main] TRACE i.s.v.c.c.ModelConverterContextImpl - defineModel ModelChild class Schema {
    type: object
    format: null
    $ref: null
    description: null
    title: null
    multipleOf: null
    maximum: null
    exclusiveMaximum: null
    minimum: null
    exclusiveMinimum: null
    maxLength: null
    minLength: null
    pattern: null
    maxItems: null
    minItems: null
    uniqueItems: null
    maxProperties: null
    minProperties: null
    required: null
    not: null
    properties: {id=class JsonSchema {
        class Schema {
            type: [string]
            format: null
            $ref: null
            description: null
            title: null
            multipleOf: null
            maximum: null
            exclusiveMaximum: null
            minimum: null
            exclusiveMinimum: null
            maxLength: null
            minLength: null
            pattern: null
            maxItems: null
            minItems: null
            uniqueItems: null
            maxProperties: null
            minProperties: null
            required: null
            not: null
            properties: null
            additionalProperties: null
            nullable: null
            readOnly: null
            writeOnly: null
            example: null
            externalDocs: null
            deprecated: null
            discriminator: null
            xml: null
            patternProperties: null
            contains: null
            $id: null
            $anchor: null
            $schema: null
            $vocabulary: null
            $dynamicAnchor: null
            const: null
            contentEncoding: null
            contentMediaType: null
            contentSchema: null
            propertyNames: null
            unevaluatedProperties: null
            maxContains: null
            minContains: null
            additionalItems: null
            unevaluatedItems: null
            _if: null
            _else: null
            then: null
            dependentRequired: null
            dependentSchemas: null
            $comment: null
            prefixItems: null
        }
    }}
    additionalProperties: null
    nullable: null
    readOnly: null
    writeOnly: null
    example: null
    externalDocs: null
    deprecated: null
    discriminator: null
    xml: null
}
{Model=class Schema {
    type: object
    format: null
    $ref: null
    description: null
    title: null
    multipleOf: null
    maximum: null
    exclusiveMaximum: null
    minimum: null
    exclusiveMinimum: null
    maxLength: null
    minLength: null
    pattern: null
    maxItems: null
    minItems: null
    uniqueItems: null
    maxProperties: null
    minProperties: null
    required: null
    not: null
    properties: {id=class JsonSchema {
        class Schema {
            type: [string]
            format: null
            $ref: null
            description: null
            title: null
            multipleOf: null
            maximum: null
            exclusiveMaximum: null
            minimum: null
            exclusiveMinimum: null
            maxLength: null
            minLength: null
            pattern: null
            maxItems: null
            minItems: null
            uniqueItems: null
            maxProperties: null
            minProperties: null
            required: null
            not: null
            properties: null
            additionalProperties: null
            nullable: null
            readOnly: null
            writeOnly: null
            example: null
            externalDocs: null
            deprecated: null
            discriminator: null
            xml: null
            patternProperties: null
            contains: null
            $id: null
            $anchor: null
            $schema: null
            $vocabulary: null
            $dynamicAnchor: null
            const: null
            contentEncoding: null
            contentMediaType: null
            contentSchema: null
            propertyNames: null
            unevaluatedProperties: null
            maxContains: null
            minContains: null
            additionalItems: null
            unevaluatedItems: null
            _if: null
            _else: null
            then: null
            dependentRequired: null
            dependentSchemas: null
            $comment: null
            prefixItems: null
        }
    }, modelChild=class JsonSchema {
        class Schema {
            type: null
            format: null
            $ref: #/components/schemas/ModelChild
            description: null
            title: null
            multipleOf: null
            maximum: null
            exclusiveMaximum: null
            minimum: null
            exclusiveMinimum: null
            maxLength: null
            minLength: null
            pattern: null
            maxItems: null
            minItems: null
            uniqueItems: null
            maxProperties: null
            minProperties: null
            required: null
            not: null
            properties: null
            additionalProperties: null
            nullable: null
            readOnly: null
            writeOnly: null
            example: null
            externalDocs: null
            deprecated: null
            discriminator: null
            xml: null
            patternProperties: null
            contains: null
            $id: null
            $anchor: null
            $schema: null
            $vocabulary: null
            $dynamicAnchor: null
            const: null
            contentEncoding: null
            contentMediaType: null
            contentSchema: null
            propertyNames: null
            unevaluatedProperties: null
            maxContains: null
            minContains: null
            additionalItems: null
            unevaluatedItems: null
            _if: null
            _else: null
            then: null
            dependentRequired: null
            dependentSchemas: null
            $comment: null
            prefixItems: null
        }
    }}
    additionalProperties: null
    nullable: null
    readOnly: null
    writeOnly: null
    example: null
    externalDocs: null
    deprecated: null
    discriminator: null
    xml: null
}, ModelChild=class Schema {
    type: object
    format: null
    $ref: null
    description: null
    title: null
    multipleOf: null
    maximum: null
    exclusiveMaximum: null
    minimum: null
    exclusiveMinimum: null
    maxLength: null
    minLength: null
    pattern: null
    maxItems: null
    minItems: null
    uniqueItems: null
    maxProperties: null
    minProperties: null
    required: null
    not: null
    properties: {id=class JsonSchema {
        class Schema {
            type: [string]
            format: null
            $ref: null
            description: null
            title: null
            multipleOf: null
            maximum: null
            exclusiveMaximum: null
            minimum: null
            exclusiveMinimum: null
            maxLength: null
            minLength: null
            pattern: null
            maxItems: null
            minItems: null
            uniqueItems: null
            maxProperties: null
            minProperties: null
            required: null
            not: null
            properties: null
            additionalProperties: null
            nullable: null
            readOnly: null
            writeOnly: null
            example: null
            externalDocs: null
            deprecated: null
            discriminator: null
            xml: null
            patternProperties: null
            contains: null
            $id: null
            $anchor: null
            $schema: null
            $vocabulary: null
            $dynamicAnchor: null
            const: null
            contentEncoding: null
            contentMediaType: null
            contentSchema: null
            propertyNames: null
            unevaluatedProperties: null
            maxContains: null
            minContains: null
            additionalItems: null
            unevaluatedItems: null
            _if: null
            _else: null
            then: null
            dependentRequired: null
            dependentSchemas: null
            $comment: null
            prefixItems: null
        }
    }}
    additionalProperties: null
    nullable: null
    readOnly: null
    writeOnly: null
    example: null
    externalDocs: null
    deprecated: null
    discriminator: null
    xml: null
}}
frantuma commented 10 months ago

@woltariel trasfered ticket to swagger-core as the described functionality is provided by Swagger Core, not Swagger Parser.

The reason of behaviour you are experiencing is the lack of the Jackson Kotlin Module dependency and configuration; this module allows Jackson to fully introspect Kotlin classes/types, also covering your case.

You would need to add the following dependency:

implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.15.3")

and configure the object mapper in use (see also module home page for other ways to configure)


import com.fasterxml.jackson.module.kotlin.registerKotlinModule
...
private val context = ModelConverterContextImpl(ModelResolver(ObjectMapper().registerKotlinModule()).openapi31(true))

Closing ticket, please reopen if you are still experiencing issues