@Schema(accessMode) doesn't work for objects that are contained by other objects
From springdoc/springdoc-openapi#1080:
Describe the bug
@Schema(accessMode = READ_ONLY)(or WRITE_ONLY) doesn't work, if it's used on an object that is contained by another object in the same class:@Getter @Setter public class Person { // This works. Name will only be visable in GET requests @Schema(accessMode = Schema.AccessMode.READ_ONLY) private String name; // This doesn't work. Age will be visable in GET and POST requests. WRITE_ONLY doesn't work here as well @Schema(accessMode = Schema.AccessMode.READ_ONLY) private Age age; // The class Mother has an Age instance variable. This is the reason why @Schema doesn't work for Person.age private Mother mother; }To Reproduce I have a minimal project here: https://github.com/Shryne/SwaggerAccess. Just start
SwaggerAccessApplication.mainand visit http://localhost:8090/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/. It will show:GET /person 200 Response: { "name": "string", "age": { "value": 0 }, "mother": { "bid": { "value": 0 } } }POST /person Request Body (example Value) { "age": { "value": 0 }, "mother": { "bid": { "value": 0 } } }Expected behavior
nameandageare read only values.nameisn't shown in the POST request, as expected. Unfortunately, this doesn't apply to age. POST should look like this:{ "mother": { "bid": { "value": 0 } } }
And using this code:
System.out.println(
ModelConverters
.getInstance()
.resolveAsResolvedSchema(new AnnotatedType(Person.class))
.referencedSchemas
);
I get this output:
{Age=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: {value=class IntegerSchema {
class Schema {
type: integer
format: int32
$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
}
}}
additionalProperties: null
nullable: null
readOnly: null
writeOnly: null
example: null
externalDocs: null
deprecated: null
discriminator: null
xml: null
}, Mother=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: {bid=class Schema {
type: null
format: null
$ref: #/components/schemas/Age
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
}}
additionalProperties: null
nullable: null
readOnly: null
writeOnly: null
example: null
externalDocs: null
deprecated: null
discriminator: null
xml: null
}, Person=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: {name=class StringSchema {
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: true
writeOnly: null
example: null
externalDocs: null
deprecated: null
discriminator: null
xml: null
}
}, age=class Schema {
type: null
format: null
$ref: #/components/schemas/Age
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
}, mother=class Schema {
type: null
format: null
$ref: #/components/schemas/Mother
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
}}
additionalProperties: null
nullable: null
readOnly: null
writeOnly: null
example: null
externalDocs: null
deprecated: null
discriminator: null
xml: null
}}
Furthermore, if I use @Schema(accessMode = Schema.AccessMode.READ_ONLY) on the mother instance variable, it won't be displayed in POST as expected, but age stays as it is.
This issue here has a reproducible example provided as a spring boot based repo: https://github.com/springdoc/springdoc-openapi/issues/1135
Currently I am using this workaround:
class A {
var b = ReadOnlyB()
var otherB = B()
}
open class B {}
@Schema(
accessMode = Schema.AccessMode.READ_ONLY,
title = "B (read only)"
)
class ReadOnlyB : B()
I create additional classes for every class that I want to be read (or write) only. Since they are other classes, swagger-core doesn't overwrite their access mode. The disadvantages of this method are: We have additional classes that do nothing and
the user will see additional, unnecessary, copied classes in the generated documentation.
A fix of this issue would be nice.
I have the same question, curious about what hasn't been fixed