springfox: Endpoints with the same path and parameters but different headers some times cause java.lang.IllegalArgumentException: Multiple entries with same key

I am using version 2.7.0 and i am experiencing an erratic behavior where sometimes my application fails to start with the following error:

java.lang.IllegalArgumentException: Multiple entries with same key: springfox.documentation.spring.web.plugins.PathAndParametersEquivalence@50d2ab9.wrap(springfox.documentation.spring.web.WebMvcRequestHandler@4df57fa4)=[springfox.documentation.spring.web.WebMvcRequestHandler@4df57fa4] and springfox.documentation.spring.web.plugins.PathAndParametersEquivalence@50d2ab9.wrap(springfox.documentation.spring.web.WebMvcRequestHandler@844c806)=[springfox.documentation.spring.web.WebMvcRequestHandler@844c806] at com.google.common.collect.ImmutableMap.checkNoConflict(ImmutableMap.java:150) at com.google.common.collect.RegularImmutableMap.checkNoConflictInBucket(RegularImmutableMap.java:104) at com.google.common.collect.RegularImmutableMap.<init>(RegularImmutableMap.java:70) at com.google.common.collect.ImmutableMap$Builder.build(ImmutableMap.java:254) at com.google.common.collect.ImmutableListMultimap.copyOf(ImmutableListMultimap.java:268) at com.google.common.collect.ImmutableMultimap.copyOf(ImmutableMultimap.java:298) at com.google.common.collect.ImmutableMultimap$Builder.build(ImmutableMultimap.java:272) at com.google.common.collect.ImmutableListMultimap$Builder.build(ImmutableListMultimap.java:224) at com.google.common.collect.Multimaps.index(Multimaps.java:1511) at com.google.common.collect.Multimaps.index(Multimaps.java:1455) at springfox.documentation.spring.web.plugins.DefaultRequestHandlerCombiner.combined(DefaultRequestHandlerCombiner.java:59) at springfox.documentation.spring.web.plugins.DefaultRequestHandlerCombiner.combine(DefaultRequestHandlerCombiner.java:49) at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.defaultContextBuilder(DocumentationPluginsBootstrapper.java:106) at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.buildContext(DocumentationPluginsBootstrapper.java:91) at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:154) at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:175) ... 22 more

Debugging led me to pinpoint the issue to 2 mappings:

@ApiOperation(value = "foo by bar", hidden = true) @postmapping(path = "/foo/{bar}")

and

@ApiOperation(value = "new foo by bar", nickname = "new_foo_bar") @postmapping(path = "/foo/{bar}", headers = {"some_header"})

In #1894 I was pointed out that PathAndParametersEquivalence is supposed to just compare path and parameters ignoring the headers, so I would like to know how to proceed to avoid this?

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 39 (12 by maintainers)

Most upvoted comments

Tested the current version: 2.7.1-SNAPSHOT. It works like you describe: 2 errors at start, but the application started fine. So it’s better! Thanks @dilipkrish

Here the logs, when I started jhipster-registry:

2017-12-29 18:02:54.842 DEBUG 27412 --- [kground-preinit] org.jboss.logging                        : Logging Provider: org.jboss.logging.Slf4jLoggerProvider found via system property

        ██╗ ██╗   ██╗ ████████╗ ███████╗   ██████╗ ████████╗ ████████╗ ███████╗
        ██║ ██║   ██║ ╚══██╔══╝ ██╔═══██╗ ██╔════╝ ╚══██╔══╝ ██╔═════╝ ██╔═══██╗
        ██║ ████████║    ██║    ███████╔╝ ╚█████╗     ██║    ██████╗   ███████╔╝
  ██╗   ██║ ██╔═══██║    ██║    ██╔════╝   ╚═══██╗    ██║    ██╔═══╝   ██╔══██║
  ╚██████╔╝ ██║   ██║ ████████╗ ██║       ██████╔╝    ██║    ████████╗ ██║  ╚██╗
   ╚═════╝  ╚═╝   ╚═╝ ╚═══════╝ ╚═╝       ╚═════╝     ╚═╝    ╚═══════╝ ╚═╝   ╚═╝

:: JHipster Registry :: Running Spring Boot 1.5.9.RELEASE ::
:: http://jhipster.github.io ::

2017-12-29 18:02:56.319  INFO 27412 --- [  restartedMain] i.g.j.registry.JHipsterRegistryApp       : The following profiles are active: swagger,dev,native
2017-12-29 18:02:58.714 DEBUG 27412 --- [  restartedMain] i.g.j.r.config.AsyncConfiguration        : Creating Async Task Executor
2017-12-29 18:02:59.500 DEBUG 27412 --- [  restartedMain] i.g.j.r.config.MetricsConfiguration      : Registering JVM gauges
2017-12-29 18:02:59.573 DEBUG 27412 --- [  restartedMain] i.g.j.r.config.MetricsConfiguration      : Initializing Metrics JMX reporting
2017-12-29 18:03:01.820 DEBUG 27412 --- [  restartedMain] i.g.j.registry.config.WebConfigurer      : Registering CORS filter
2017-12-29 18:03:01.969  INFO 27412 --- [  restartedMain] i.g.j.registry.config.WebConfigurer      : Web application configuration, using profiles: swagger
2017-12-29 18:03:01.970 DEBUG 27412 --- [  restartedMain] i.g.j.registry.config.WebConfigurer      : Initializing Metrics registries
2017-12-29 18:03:01.974 DEBUG 27412 --- [  restartedMain] i.g.j.registry.config.WebConfigurer      : Registering Metrics Filter
2017-12-29 18:03:01.975 DEBUG 27412 --- [  restartedMain] i.g.j.registry.config.WebConfigurer      : Registering Metrics Servlet
2017-12-29 18:03:01.979  INFO 27412 --- [  restartedMain] i.g.j.registry.config.WebConfigurer      : Web application fully configured
2017-12-29 18:03:02.824  WARN 27412 --- [  restartedMain] c.n.c.sources.URLConfigurationSource     : No URLs will be polled as dynamic configuration sources.
2017-12-29 18:03:05.546  WARN 27412 --- [  restartedMain] c.n.c.sources.URLConfigurationSource     : No URLs will be polled as dynamic configuration sources.
2017-12-29 18:03:06.951 DEBUG 27412 --- [  restartedMain] i.g.j.c.apidoc.SwaggerConfiguration      : Starting Swagger
2017-12-29 18:03:06.961 DEBUG 27412 --- [  restartedMain] i.g.j.c.apidoc.SwaggerConfiguration      : Started Swagger in 9 ms
2017-12-29 18:03:08.607  INFO 27412 --- [  restartedMain] com.netflix.discovery.DiscoveryClient    : Initializing Eureka in region us-east-1
2017-12-29 18:03:08.607  INFO 27412 --- [  restartedMain] com.netflix.discovery.DiscoveryClient    : Client configured to neither register nor query for data.
2017-12-29 18:03:08.617  INFO 27412 --- [  restartedMain] com.netflix.discovery.DiscoveryClient    : Discovery Client initialized at timestamp 1514566988617 with initial instances count: 0
2017-12-29 18:03:08.968  INFO 27412 --- [  restartedMain] c.n.d.provider.DiscoveryJerseyProvider   : Using JSON encoding codec LegacyJacksonJson
2017-12-29 18:03:08.968  INFO 27412 --- [  restartedMain] c.n.d.provider.DiscoveryJerseyProvider   : Using JSON decoding codec LegacyJacksonJson
2017-12-29 18:03:08.971  INFO 27412 --- [  restartedMain] c.n.d.provider.DiscoveryJerseyProvider   : Using XML encoding codec XStreamXml
2017-12-29 18:03:08.974  INFO 27412 --- [  restartedMain] c.n.d.provider.DiscoveryJerseyProvider   : Using XML decoding codec XStreamXml
2017-12-29 18:03:09.775  WARN 27412 --- [  restartedMain] o.s.j.e.a.AnnotationMBeanExporter        : Bean with key 'zuulEndpoint' has been registered as an MBean but has no exposed attributes or operations
2017-12-29 18:03:10.886 ERROR 27412 --- [  restartedMain] s.d.s.w.p.DefaultRequestHandlerCombiner  : Unable to index request handlers Multiple entries with same key: springfox.documentation.spring.web.plugins.PathAndParametersEquivalence@3895a88c.wrap(WebMvcRequestHandler{key=RequestHandlerKey{pathMappings=[/config/{name}/{profile}/{label}/**], supportedMethods=[GET], supportedMediaTypes=[], producibleMediaTypes=[application/octet-stream]}})=[WebMvcRequestHandler{key=RequestHandlerKey{pathMappings=[/config/{name}/{profile}/{label}/**], supportedMethods=[GET], supportedMediaTypes=[], producibleMediaTypes=[application/octet-stream]}}] and springfox.documentation.spring.web.plugins.PathAndParametersEquivalence@3895a88c.wrap(WebMvcRequestHandler{key=RequestHandlerKey{pathMappings=[/config/{name}/{profile}/{label}/**], supportedMethods=[GET], supportedMediaTypes=[], producibleMediaTypes=[]}})=[WebMvcRequestHandler{key=RequestHandlerKey{pathMappings=[/config/{name}/{profile}/{label}/**], supportedMethods=[GET], supportedMediaTypes=[], producibleMediaTypes=[]}}]. Request handlers with issuesRequest Handlers with duplicate keys {	0. RequestHandlerKey{pathMappings=[/config/{name}/{profile}/{label}/**], supportedMethods=[GET], supportedMediaTypes=[], producibleMediaTypes=[]}	1. RequestHandlerKey{pathMappings=[/config/{name}/{profile}/{label}/**], supportedMethods=[GET], supportedMediaTypes=[], producibleMediaTypes=[application/octet-stream]}}
2017-12-29 18:03:11.262 ERROR 27412 --- [  restartedMain] s.d.s.w.p.DefaultRequestHandlerCombiner  : Unable to index request handlers Multiple entries with same key: springfox.documentation.spring.web.plugins.PathAndParametersEquivalence@3895a88c.wrap(WebMvcRequestHandler{key=RequestHandlerKey{pathMappings=[/config/{name}/{profile}/{label}/**], supportedMethods=[GET], supportedMediaTypes=[], producibleMediaTypes=[application/octet-stream]}})=[WebMvcRequestHandler{key=RequestHandlerKey{pathMappings=[/config/{name}/{profile}/{label}/**], supportedMethods=[GET], supportedMediaTypes=[], producibleMediaTypes=[application/octet-stream]}}] and springfox.documentation.spring.web.plugins.PathAndParametersEquivalence@3895a88c.wrap(WebMvcRequestHandler{key=RequestHandlerKey{pathMappings=[/config/{name}/{profile}/{label}/**], supportedMethods=[GET], supportedMediaTypes=[], producibleMediaTypes=[]}})=[WebMvcRequestHandler{key=RequestHandlerKey{pathMappings=[/config/{name}/{profile}/{label}/**], supportedMethods=[GET], supportedMediaTypes=[], producibleMediaTypes=[]}}]. Request handlers with issuesRequest Handlers with duplicate keys {	0. RequestHandlerKey{pathMappings=[/config/{name}/{profile}/{label}/**], supportedMethods=[GET], supportedMediaTypes=[], producibleMediaTypes=[]}	1. RequestHandlerKey{pathMappings=[/config/{name}/{profile}/{label}/**], supportedMethods=[GET], supportedMediaTypes=[], producibleMediaTypes=[application/octet-stream]}}
2017-12-29 18:03:11.526 DEBUG 27412 --- [pool-4-thread-1] i.g.j.r.aop.logging.LoggingAspect        : Enter: io.github.jhipster.registry.service.ZuulUpdaterService.updateZuulRoutes() with argument[s] = []
2017-12-29 18:03:11.552 DEBUG 27412 --- [pool-4-thread-1] i.g.j.r.aop.logging.LoggingAspect        : Exit: io.github.jhipster.registry.service.ZuulUpdaterService.updateZuulRoutes() with result = null
2017-12-29 18:03:11.656  INFO 27412 --- [  restartedMain] i.g.j.registry.JHipsterRegistryApp       : Started JHipsterRegistryApp in 18.001 seconds (JVM running for 18.736)
2017-12-29 18:03:11.657  INFO 27412 --- [  restartedMain] i.g.j.registry.JHipsterRegistryApp       : 
----------------------------------------------------------
	Application 'jhipster-registry' is running! Access URLs:
	Local: 		http://localhost:8761
	External: 	http://127.0.1.1:8761
	Profile(s): 	[swagger, dev, native]
----------------------------------------------------------

@dilipkrish With 2.7.1-SNAPSHOT, it will print an error message instead of throw the exception:

2017-12-29 01:33:17.202 ERROR 31745 --- [           main] s.d.s.w.p.DefaultRequestHandlerCombiner  : Unable to index request handlers Multiple entries with same key: springfox.documentation.spring.web.plugins.PathAndParametersEquivalence@df6f19b.wrap(com.emc.autoconfigure.springfox.DefaultsRequestHandlerCombiner$DelegateRequestHandler@6d842877)=[com.emc.autoconfigure.springfox.DefaultsRequestHandlerCombiner$DelegateRequestHandler@6d842877] and springfox.documentation.spring.web.plugins.PathAndParametersEquivalence@df6f19b.wrap(com.emc.autoconfigure.springfox.DefaultsRequestHandlerCombiner$DelegateRequestHandler@614cbec4)=[com.emc.autoconfigure.springfox.DefaultsRequestHandlerCombiner$DelegateRequestHandler@614cbec4]. Request handlers with issuesRequest Handlers with duplicate keys {	0. RequestHandlerKey{pathMappings=[/error], supportedMethods=[], supportedMediaTypes=[], producibleMediaTypes=[text/html]}	1. RequestHandlerKey{pathMappings=[/error], supportedMethods=[], supportedMediaTypes=[], producibleMediaTypes=[]}}

But I believe the right fix is to change:

  protected boolean doEquivalent(RequestHandler a, RequestHandler b) {
    return a.getPatternsCondition().equals(b.getPatternsCondition())
        && !Sets.intersection(a.supportedMethods(), b.supportedMethods()).isEmpty()
        && a.params().equals(b.params())
        && Sets.difference(wrapped(a.getParameters()), wrapped(b.getParameters())).isEmpty();
  }

to:

  protected boolean doEquivalent(RequestHandler a, RequestHandler b) {
    return a.getPatternsCondition().equals(b.getPatternsCondition())
        && !Sets.intersection(a.supportedMethods(), b.supportedMethods()).isEmpty()
        && a.params().equals(b.params())
        && Sets.symmetricDifference(wrapped(a.getParameters()), wrapped(b.getParameters())).isEmpty();
  }

@dhamudeva I am using 2.6.1 without problems while i wait for this issue to be fixed