Skip to content

IllegalStateException when having multiple endpoints differentiated by header value #1253

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

Closed
Neloop opened this issue Aug 30, 2021 · 5 comments
Labels
invalid This doesn't seem right

Comments

@Neloop
Copy link

Neloop commented Aug 30, 2021

Describe the bug
We are currently exploring ways how to version our REST API in Spring application. During the research we also tried how the different versioning ways work with springdoc and we found out that custom header versioning does not cope well with springdoc. When generating OpenAPI for the controller below we are experiencing IllegalStateException, because of that OpenAPI JSON cannot be generated.

To Reproduce
Steps to reproduce the behavior:

  • spring-boot 2.5.3
  • springdoc-openapi-ui 1.5.10
  • Controller with following 2 endpoints:
@RestController
public class VersionController {

  @GetMapping(value = "groups", headers = "X-Version=1")
  public GroupV1 groupV1() {
      return null;
  }

  @GetMapping(value = "groups", headers = "X-Version=2")
  public GroupV2 groupV2() {
      return null;
  }
}
  • Produced exception on Swagger generation:
java.lang.IllegalStateException: Duplicate key class Parameter {
    name: X-Version
    in: header
    description: null
    required: null
    deprecated: null
    allowEmptyValue: null
    style: null
    explode: null
    allowReserved: null
    schema: 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: null
            writeOnly: null
            example: null
            externalDocs: null
            deprecated: null
            discriminator: null
            xml: null
        }
    }
    examples: null
    example: null
    content: null
    $ref: null
}
               at org.springdoc.core.AbstractRequestService.lambda$getParameterLinkedHashMap$5(AbstractRequestService.java:297) ~[springdoc-openapi-common-1.5.10.jar:1.5.10]
               at java.base/java.util.HashMap.merge(HashMap.java:1297) ~[na:na]
               at java.base/java.util.stream.Collectors.lambda$toMap$68(Collectors.java:1658) ~[na:na]
               at java.base/java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169) ~[na:na]
               at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655) ~[na:na]
               at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na]
               at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]
               at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913) ~[na:na]
               at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
               at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578) ~[na:na]
               at org.springdoc.core.AbstractRequestService.getParameterLinkedHashMap(AbstractRequestService.java:293) ~[springdoc-openapi-common-1.5.10.jar:1.5.10]
               at org.springdoc.core.AbstractRequestService.build(AbstractRequestService.java:277) ~[springdoc-openapi-common-1.5.10.jar:1.5.10]
               at org.springdoc.api.AbstractOpenApiResource.calculatePath(AbstractOpenApiResource.java:391) ~[springdoc-openapi-common-1.5.10.jar:1.5.10]
               at org.springdoc.api.AbstractOpenApiResource.calculatePath(AbstractOpenApiResource.java:528) ~[springdoc-openapi-common-1.5.10.jar:1.5.10]
               at org.springdoc.webmvc.api.OpenApiResource.calculatePath(OpenApiResource.java:261) ~[springdoc-openapi-webmvc-core-1.5.10.jar:1.5.10]
               at org.springdoc.webmvc.api.OpenApiResource.getPaths(OpenApiResource.java:213) ~[springdoc-openapi-webmvc-core-1.5.10.jar:1.5.10]
               at org.springdoc.api.AbstractOpenApiResource.getOpenApi(AbstractOpenApiResource.java:287) ~[springdoc-openapi-common-1.5.10.jar:1.5.10]
               at org.springdoc.webmvc.api.OpenApiResource.openapiJson(OpenApiResource.java:176) ~[springdoc-openapi-webmvc-core-1.5.10.jar:1.5.10]
               at org.springdoc.webmvc.api.OpenApiWebMvcResource.openapiJson(OpenApiWebMvcResource.java:116) ~[springdoc-openapi-webmvc-core-1.5.10.jar:1.5.10]
...

Expected behavior

  • Springdoc is expected to generate OpenAPI JSON without throwing exception
@bnasslahsen
Copy link
Collaborator

@Neloop,

See the answer here: #580

Make sure you don't create duplicates. #1131 , #1184.

And this is this sample test, how you can handle this case.

@Neloop
Copy link
Author

Neloop commented Aug 30, 2021

Sorry about the duplicates, I was too quick and created issue without thinking and checking.

If I may have one more question, why same name parameters in RequestMapping do not raise exception, but headers do? From user point of view it seems a little incoherent, but there might be some internal reasons...

@bnasslahsen
Copy link
Collaborator

what do you mean by same name parameters in RequestMapping ?

@Neloop
Copy link
Author

Neloop commented Aug 30, 2021

Basically the same example as I provided, but instead of headers with params, that case does not raise an exception, see below

@RestController
public class VersionController {

  @GetMapping(value = "groups", params = "version=1")
  public GroupV1 paramsGroupV1() {
      return null;
  }

  @GetMapping(value = "groups", params = "version=2")
  public GroupV2 paramsGroupV2() {
      return null;
  }
}

@bnasslahsen
Copy link
Collaborator

params in the level of @RequestMapping, is not supported at all in the code of springdoc-openapi.
You should get the same error.

You can log a feature request and propose a related PR, if you feel it useful for the community.

@bnasslahsen bnasslahsen added the invalid This doesn't seem right label Jan 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
invalid This doesn't seem right
Projects
None yet
Development

No branches or pull requests

2 participants