Springfox 3.0.0 无法与 Spring Boot 2.6.0 一起使用

Thi*_*mal 66 java swagger spring-boot springfox spring-boot-2.6.0

Springfox 3.0.0 无法与 Spring Boot 2.6.0 一起使用,升级后出现以下错误

org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this.condition" is null
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181)
    at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54)
    at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356)
    at java.base/java.lang.Iterable.forEach(Iterable.java:75)
    at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155)
    at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123)
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:302)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1290)
    at com.enkindle.AntivirusApplication.main(AntivirusApplication.java:16)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.NullPointerException: Cannot invoke "org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this.condition" is null
    at springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns(WebMvcPatternsRequestConditionWrapper.java:56)
    at springfox.documentation.RequestHandler.sortedPaths(RequestHandler.java:113)
    at springfox.documentation.spi.service.contexts.Orderings.lambda$byPatternsCondition$3(Orderings.java:89)
    at java.base/java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:473)
    at java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355)
    at java.base/java.util.TimSort.sort(TimSort.java:234)
    at java.base/java.util.Arrays.sort(Arrays.java:1307)
    at java.base/java.util.ArrayList.sort(ArrayList.java:1721)
    at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:392)
    at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
    at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
    at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
    at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
    at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:81)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
    at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
    at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.withDefaults(AbstractDocumentationPluginsBootstrapper.java:107)
    at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.buildContext(AbstractDocumentationPluginsBootstrapper.java:91)
    at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.bootstrapDocumentationPlugins(AbstractDocumentationPluginsBootstrapper.java:82)
    at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:100)
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178)
    ... 19 common frames omitted
Run Code Online (Sandbox Code Playgroud)

ℛɑƒ*_*ƒæĿ 69

只有在主类中添加@EnableWebMvc才能解决问题:

@EnableWebMvc
@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢少于 2 行代码的解决方案。好一个。 (4认同)

Joã*_*ias 61

我知道这并不能直接解决您的问题,但请考虑转向springdoc,其最新版本支持 Spring Boot 2.6.0。Springfox 目前存在如此多的 bug,使用起来很痛苦。由于 Spring WebFlux 支持,我已经转向springdoc2 年前,对此我感到非常高兴。此外,它还支持 Kotlin 协程,我不确定 Springfox 是否支持。

如果您决定迁移,springdoc甚至还有迁移指南

  • 如果可以的话,我会投票 100 次:) 我们做出了完全相同的决定,我们摆脱了(几乎)所有与 springfox 相关的愚蠢问题! (2认同)

Pet*_*ler 30

到目前为止,Springfox 3.0.0仅适用于Spring 2.6.0-M2,但不适用于以上版本。请参阅开放的 Springfox 问题https://github.com/springfox/springfox/issues/3462。在那里您还可以找到一些可以使用的解决方法,直到问题得到解决。

\n

例如,将其添加Bean到您的 Swagger 配置中:

\n
@Bean\npublic static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {\n    return new BeanPostProcessor() {\n\n        @Override\n        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n            if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {\n                customizeSpringfoxHandlerMappings(getHandlerMappings(bean));\n            }\n            return bean;\n        }\n\n        private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {\n            List<T> copy = mappings.stream()\n                .filter(mapping -> mapping.getPatternParser() == null)\n                .collect(Collectors.toList());\n            mappings.clear();\n            mappings.addAll(copy);\n        }\n\n        @SuppressWarnings("unchecked")\n        private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {\n            try {\n                Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");\n                field.setAccessible(true);\n                return (List<RequestMappingInfoHandlerMapping>) field.get(bean);\n            } catch (IllegalArgumentException | IllegalAccessException e) {\n                throw new IllegalStateException(e);\n            }\n        }\n    };\n}\n
Run Code Online (Sandbox Code Playgroud)\n

编辑:服务器启动,但没有返回 API 信息:

\n
\n

规范中没有定义任何操作!

\n
\n

真是一团糟。

\n

编辑2:正如@H\xc3\xa9ctor所提到的,也spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER必须添加application.properties,并且操作将再次显示。但是,我不知道在任何情况下是否可以设置此属性,因为它可能会干扰其他约束。

\n


小智 17

对于 springfox 3.0.0 和 springboot 2.6.1 使用此配置并添加此标签\n@Configuration @EnableWebMvc

\n
public class SpringFoxConfig {\n\n    @Bean\n    public Docket api() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .select()\n                .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))\n                .paths(PathSelectors.any())\n                .build().apiInfo(getApiInfo());\n    }\n    \n    private ApiInfo getApiInfo() {\n        return new ApiInfo(\n                "Api Usuarios",\n                "prueba global logic",\n                "1",\n                "TERMS OF SERVICE URL",\n                new Contact("Gabriel Hern\xc3\xa1ndez","URL","gabriel.hernandez.u@gmail.com"),\n                "LICENSE",\n                "LICENSE URL",\n                Collections.emptyList()\n        );\n    }\n    \n    @Bean\n    public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {\n        return new BeanPostProcessor() {\n\n            @Override\n            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {\n                if (bean instanceof WebMvcRequestHandlerProvider ) {\n                    customizeSpringfoxHandlerMappings(getHandlerMappings(bean));\n                }\n                return bean;\n            }\n\n            private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {\n                List<T> copy = mappings.stream()\n                    .filter(mapping -> mapping.getPatternParser() == null)\n                    .collect(Collectors.toList());\n                mappings.clear();\n                mappings.addAll(copy);\n            }\n\n            @SuppressWarnings("unchecked")\n            private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {\n                try {\n                    Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");\n                    field.setAccessible(true);\n                    return (List<RequestMappingInfoHandlerMapping>) field.get(bean);\n                } catch (IllegalArgumentException | IllegalAccessException e) {\n                    throw new IllegalStateException(e);\n                }\n            }\n        };\n    }    \n}\n
Run Code Online (Sandbox Code Playgroud)\n


小智 11

一个可能的解决方案是:

1-设置spring.mvc.pathmatch.matching-strategy: ant_path_matcherapplication.properties

2-将以下 bean 添加到您的 SwaggerConfig 类中:

@Bean
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier, EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties, Environment environment) {
        List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
        Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
        allEndpoints.addAll(webEndpoints);
        allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
        allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
        String basePath = webEndpointProperties.getBasePath();
        EndpointMapping endpointMapping = new EndpointMapping(basePath);
        boolean shouldRegisterLinksMapping = this.shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
        return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes, corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath), shouldRegisterLinksMapping, null);
    }


private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment, String basePath) {
        return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath) || ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
    }
Run Code Online (Sandbox Code Playgroud)

致谢hhhhsw