Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Description missing in generated spec when field type is a byte array #2275

Closed
jarnbjo opened this issue Jun 22, 2023 · 10 comments · Fixed by #2711
Closed

Description missing in generated spec when field type is a byte array #2275

jarnbjo opened this issue Jun 22, 2023 · 10 comments · Fixed by #2711
Labels
wontfix This will not be worked on

Comments

@jarnbjo
Copy link

jarnbjo commented Jun 22, 2023

With springdoc-openapi-starter-common:2.0.4 and newer, generating an OpenAPI spec from a value object containing a byte array field, e.g:

    @Schema(description = "foo")
    byte[] content;

will generate an OpenAPI specification, in which the description of the field is missing:

    content:
      type: string
      format: byte

If I generate the specification from the same model class with version 2.0.2, the following spec comes out:

    content:
      type: array
      description: foo
      items:
        type: string
        description: foo
        format: byte

Here, the description is present, although the data type is incorrectly specified. There have been a lot of bugs reported against both Springdoc as well as Swagger with the data type issue. Probably something went wrong with the bugfix. It is BTW also no more possible to overwrite the type and format fields with the corresponding values in the Schema annotation. The required value in the Schema annotation seem however still to be evaluated.

I am honestly not sure which project (Springdoc or Swagger) might be responsible for this issue, but I assume that it actually is some issue in Springdoc. The reason is:

  • using Springdoc 2.0.4 and Swagger-Core downgraded to version 2.0.7, the description is missing and the data type is correctly specified
  • using Springdoc 2.0.2 and Swagger-Core 2.0.7 (as used by Springdoc 2.0.2), the description is present, but the the data type is incorrectly specified

When using Springdoc 2.0.2, it is at least possible to specify the correct type and format in the Schema annotation:

    @Schema(description = "foo", type = "string", format = "byte")
    byte[] content = {};

... in which case the correct spec is generated:

    content:
      type: string
      description: foo
      format: byte
@uc4w6c uc4w6c closed this as completed Jun 22, 2023
@uc4w6c uc4w6c added question Further information is requested and removed question Further information is requested labels Jun 22, 2023
@uc4w6c uc4w6c reopened this Jun 22, 2023
@uc4w6c
Copy link
Collaborator

uc4w6c commented Jun 22, 2023

When I tried the following using springdoc 2.0.4, the expected value was returned.

  @GetMapping
  public Response index() {
    return null;
  }

  public record Response(
      @Schema(description = "foo")
      byte[] content,

      @ArraySchema(arraySchema = @Schema(description = "foo2"))
      byte[] content2,

      @Schema(description = "foo", type = "string", format = "byte")
      byte[] content3
  ) {}
            "Response": {
                "type": "object",
                "properties": {
                    "content": {
                        "type": "array",
                        "description": "foo",
                        "items": {
                            "type": "string",
                            "description": "foo",
                            "format": "byte"
                        }
                    },
                    "content2": {
                        "type": "array",
                        "description": "foo2",
                        "items": {
                            "type": "string",
                            "format": "byte"
                        }
                    },
                    "content3": {
                        "type": "string",
                        "description": "foo",
                        "format": "byte"
                    }
                }
            }

Can you tell me a concrete code example?

@jarnbjo
Copy link
Author

jarnbjo commented Jun 23, 2023

When I tried the following using springdoc 2.0.4, the expected value was returned.

If I generate a spec from the Record class as you have written it, Springdoc 2.0.4 generates for me the following description (with all the issues I already tried to explain in my original report). Most values in the annotations seem to be ignored:

"Response": {
  "type": "object",
  "properties": {
    "content": {
      "type": "string",
      "format": "byte"
    },
    "content2": {
      "type": "string",
      "format": "byte"
    },
    "content3": {
      "type": "string",
      "format": "byte"
    }
  }
},

If I use Springdoc 2.0.2, I get the same output as you claim to get with Springdoc 2.0.4, but this is not the 'expected value'.

I can try to explain again it in more detail:

The generated specification for the field content is:

  • an array (type = array)
  • of strings (items.type = string)
  • which each are base64-encoded (items.format = byte)

Trying to generate code again from this specification will give you a field of type List<byte[]> or similar. I do not want an array of base64 encoded strings in the JSON document, but a single base64 encoded string representing the byte array in the model class. This specification is simply wrong and the issue has been reported in many bugs, e.g:

swagger-api/swagger-core#3944

The generated specification for the field content2 is wrong for the same reason why the specification for content is wrong. The only difference is that the advisory field items.description is missing. Since I don't want the JSON to contain an array, but a base64-encoded string, the usage of the @ArraySchema annotation is also more than questionable.

The generated specification for the field content3 is correct, but only because the correct type and format is explicitely specified in the @Scehma annotation. Springdoc 2.0.2 still allows me to overwrite the default values here, with Springdoc 2.0.4 I am, als already written in the original report, not able anymore to specify format and type in the annotation, as those values are simply ignored.

I am not sure if any other dependencies may be relevant. We are using Spring Boot 3.1.0 if that helps narrowing down the problem.

@jarnbjo
Copy link
Author

jarnbjo commented Jun 23, 2023

I have tried to check if any other dependency in our project is relevant for the behaviour I see and the culprit is Spring Cloud:

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-kubernetes-client-config</artifactId>
        <version>3.0.3</version>
    </dependency>

Without Spring Cloud, Springdoc >=2.0.4 shows the same erroneous behaviour as Springdoc 2.0.2.

With Spring Cloud, Springdoc >=2.0.4 produces correct type and format attributes for the byte array field, but ignores most other attributes of the @Schema annotation, e.g. the missing description field. Springdoc <= 2.0.2 shows the same erroneous behaviour as without the Spring Cloud dependency.

@jarnbjo
Copy link
Author

jarnbjo commented Jun 23, 2023

Attached here is an MVP allowing to easily test with different versions of Springdoc together with or without a dependency on Spring Cloud.

springdoc-openapi-2275.zip

@uc4w6c
Copy link
Collaborator

uc4w6c commented Jun 25, 2023

@jarnbjo
Thank you.
I don't fully understand the cause, but I found that setting springdoc.enable-kotlin=false worked around it.

@uc4w6c
Copy link
Collaborator

uc4w6c commented Jun 26, 2023

org.springframework.cloud:spring-cloud-starter-kubernetes-client-config uses Kotlin. So, SpringDocKotlinConfiguration is enabled and .replaceWithSchema(ByteArray::class.java, ByteArraySchema()) is called.
I think this is difficult to improve.
It can be avoided by setting springdoc.enable-kotlin=false, so it is not dealt with.

@uc4w6c uc4w6c closed this as completed Jun 26, 2023
@uc4w6c uc4w6c added the wontfix This will not be worked on label Jun 26, 2023
@jarnbjo
Copy link
Author

jarnbjo commented Jun 27, 2023

@uc4w6c I would really appreciate if you tried to understand the issue.

In Springdoc <=2.0.2, SpringDocKotlinConfiguration does not invoke .replaceWithSchema(ByteArray::class.java, ByteArraySchema()) and the generated spec is incorrect (type/format attributes are incorrect),

In Springdoc >=2.04, SpringDocKotlinConfiguration invokes .replaceWithSchema(ByteArray::class.java, ByteArraySchema()) and the generated spec is incorrect (description is missing).

And now, instead of fixing the issue, you just close the bug?

Setting springdoc.enable-kotlin=false and disabling Kotlin does not fix the problem. And for those who are now actually using Kotlin and therefore can't disable it with springdoc.enable-kotlin=false, the generated spec is still false.

@uc4w6c
Copy link
Collaborator

uc4w6c commented Jun 27, 2023

@jarnbjo
Open for some more conversation.

Setting springdoc.enable-kotlin=false and disabling Kotlin does not fix the problem.

By setting springdoc.enable-kotlin=false, description can be displayed using @Schema.

@Schema(description = "foo", type = "string", format = "byte")
byte[] content

If you have a problem with byte[] returning a List<byte[]> when you don't specify type and format, as you wrote earlier, It's a swagger-core issue. (swagger-api/swagger-core#3944)

Also, if we were to fix that problem, it would be necessary to add a description after swagger-core generated the component.
This is costly, so fixing swagger-core is more efficient.

If you still want to fix it, I would appreciate it if you could create a PR.

@uc4w6c uc4w6c reopened this Jun 27, 2023
@uc4w6c uc4w6c closed this as completed Jul 1, 2023
@GeorgEchterling
Copy link

I think this issue should be reopened. The workaround springdoc.enable-kotlin=false also disables other relevant customizations for Kotlin users.

Since swagger-api/swagger-core#3944 is now fixed, it should be possible to fix this issue by simply removing the line .replaceWithSchema(ByteArray::class.java, ByteArraySchema()) from SpringDocKotlinConfiguration.

I was able to restore the correct behavior locally by calling SpringDocUtils.getConfig().removeFromSchemaMap(ByteArray::class.java) (after SpringDocKotlinConfiguration is initialized).

The affected field:

@Schema(
    description = "The file's byte content encoded as Base64.",
    accessMode = Schema.AccessMode.WRITE_ONLY,
    example = "IDwhRE9DVFlQRSBodG1sPjxodG1sPjxoZWFkPjx0aXRsZT5TdGVsbGVuYW56ZWlnZTwvdGl0bGU+PC9oZWFkPjxib2R5PjwvYm9keT48L2h0bWw+",
)
val dataBase64: ByteArray,

The default generated schema as of springdoc-openapi 2.6.0:
image

The generated schema after calling SpringDocUtils.getConfig().removeFromSchemaMap(ByteArray::class.java):

image

Afaict, this Kotlin-specific override of ByteArray is no longer necessary and should be removed.

@GeorgEchterling
Copy link

This is fixed in 2.7.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wontfix This will not be worked on
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants