66

Springfox 3.0.0 is not working with Spring Boot 2.6.0, after upgrading I am getting the following error

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
Helen
  • 87,344
  • 17
  • 243
  • 314
Thirumal
  • 8,280
  • 11
  • 53
  • 103

8 Answers8

69

Only adding @EnableWebMvc in main class resolved the problem:

@EnableWebMvc
@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class);
    }
}
ℛɑƒæĿᴿᴹᴿ
  • 4,983
  • 4
  • 38
  • 58
  • 4
    I like solutions that are less than 2 lines of code. Good one. – coretechie Aug 12 '22 at 09:04
  • While this solves this current issue, adding this annotation has by-effects. For example, it affects Jackson marshalling in terms of encoding by me – Václav Jul 01 '23 at 13:41
59

I know this does not solve your problem directly, but consider moving to springdoc which most recent release supports Spring Boot 2.6.0. Springfox is so buggy at this point that is a pain to use. I've moved to springdoc 2 years ago because of its Spring WebFlux support and I am very happy about it. Additionally, it also supports Kotlin Coroutines, which I am not sure Springfox does.

If you decide to migrate, springdoc even has a migration guide.

João Dias
  • 16,277
  • 6
  • 33
  • 45
  • 2
    If I could I would have voted up 100 times :) We have made exactly the same decision and we got rid of (almost) all the stupid problems we had with springfox! – Honza Zidek Feb 03 '22 at 22:54
  • Voted, KIV-ed and following this answer (I dont have a need for springdoc now, as i am using a lower version of Spring Boot, but probably will) – jumping_monkey Feb 09 '22 at 06:14
29

Up to now, Springfox 3.0.0 only works with Spring 2.6.0-M2 but not with versions above. See the open Springfox issue https://github.com/springfox/springfox/issues/3462. There you will also find some workarounds you may use until the issue is fixed.

E.g. add this Bean to your Swagger configuration:

@Bean
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
    return new BeanPostProcessor() {

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
                customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
            }
            return bean;
        }

        private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
            List<T> copy = mappings.stream()
                .filter(mapping -> mapping.getPatternParser() == null)
                .collect(Collectors.toList());
            mappings.clear();
            mappings.addAll(copy);
        }

        @SuppressWarnings("unchecked")
        private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
            try {
                Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
                field.setAccessible(true);
                return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                throw new IllegalStateException(e);
            }
        }
    };
}

EDIT: The server starts, but no API info is returned:

No operations defined in spec!

What a mess.

EDIT 2: As mentioned by @Héctor, spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER must be added to application.properties as well, and the operations are displayed again. However, I don't know, if setting this property is possible in any cases, as it may interfere with other constraints.

Peter Keller
  • 7,526
  • 2
  • 26
  • 29
  • 1
    I found in this URL, the last solution: Add "spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER" to your application.properties. That's All – Héctor Dec 15 '21 at 14:32
  • 1
    @Héctor: Thanks for your input. However, I needed to define the `BeanPostProcessor` and to add `ANT_PATH_MATCHER`. Only adding `ANT_PATH_MATCHER` lead to the same error as stated by @Thirumal. – Peter Keller Dec 20 '21 at 07:01
  • Moving back to 2.5.3 works – dgupta3091 Feb 04 '22 at 09:24
  • Unfortunately this configuration removes the Swagger docs for the Actuator Controller /actuator/health and /actuator/prometueus completely. If you need these controllers in your Springfox JSON doc, use this workaround: https://github.com/springfox/springfox/issues/3462#issuecomment-1029080430 Worked for me with Spring 2.6.6 and Springfox 2.9.2 – electrobabe Apr 19 '22 at 10:34
16

for springfox 3.0.0 and springboot 2.6.1 use this config and add this tag @Configuration @EnableWebMvc

public class SpringFoxConfig {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
                .paths(PathSelectors.any())
                .build().apiInfo(getApiInfo());
    }
    
    private ApiInfo getApiInfo() {
        return new ApiInfo(
                "Api Usuarios",
                "prueba global logic",
                "1",
                "TERMS OF SERVICE URL",
                new Contact("Gabriel Hernández","URL","gabriel.hernandez.u@gmail.com"),
                "LICENSE",
                "LICENSE URL",
                Collections.emptyList()
        );
    }
    
    @Bean
    public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
        return new BeanPostProcessor() {

            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                if (bean instanceof WebMvcRequestHandlerProvider ) {
                    customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
                }
                return bean;
            }

            private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
                List<T> copy = mappings.stream()
                    .filter(mapping -> mapping.getPatternParser() == null)
                    .collect(Collectors.toList());
                mappings.clear();
                mappings.addAll(copy);
            }

            @SuppressWarnings("unchecked")
            private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
                try {
                    Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
                    field.setAccessible(true);
                    return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    throw new IllegalStateException(e);
                }
            }
        };
    }    
}
invzbl3
  • 5,872
  • 9
  • 36
  • 76
10

A possible solution is to:

1- Set up spring.mvc.pathmatch.matching-strategy: ant_path_matcher in application.properties

2- Add the following bean to your SwaggerConfig class:

@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));
    }

Credits to hhhhsw

v.ladynev
  • 19,275
  • 8
  • 46
  • 67
huguinho27
  • 111
  • 1
  • 6
4

I faced the same issue in the last project and it seems that Springfox dependency got issue with the spring 2.6.x. I found out what is the issue it's about the Springfox dependency all the spring developers facing the same issue after spring 2.6.X

so all of them give the recommendation to migrate to springdoc. you can find everything here:

https://springdoc.org/#migrating-from-springfox

3

Migration Steps:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>
  1. Maintain only above dependency.
  2. Remove library inclusions of earlier releases. Specifically remove springfox-swagger2 and springfox-swagger-ui inclusions.
  3. Remove the @EnableSwagger2 annotations
  4. Add the springfox-boot-starter
  5. Springfox 3.x removes dependencies on guava and other 3rd party libraries (not zero dep yet! depends on spring plugin and open api libraries for annotations and models) so if you used guava predicates/functions those will need to transition to java 8 function interfaces
  6. If you are using WebMvc and it's a non-springboot project, but you don’t use the @EnableWebMvc annotation yet, add this annotation.

source: doc_link

Arun Sai Mustyala
  • 1,736
  • 1
  • 11
  • 27
  • 10
    For the vast majority of people, adding `@EnableWebMvc` to a Spring Boot app is the wrong thing to do as it will disable Spring Boot's auto-configuration of Spring MVC. – Andy Wilkinson Dec 01 '21 at 11:32
  • Using SNAPSHOT versions of external dependencies is not a good idea. This makes build unrepeatable in potentially very surprising ways. – Henning Dec 04 '21 at 20:24
  • I agree until point number 5. You need to add this property to your application.properties: spring.mvc.pathmatch.matching-strategy=ant_path_matcher You can read about that here: https://github.com/spring-projects/spring-boot/issues/28874 https://spring.io/blog/2020/06/30/url-matching-with-pathpattern-in-spring-mvc – Tomas Pinto Jun 02 '22 at 14:29
0

I put the dependency:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

And remove:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Here resolved!

ℛɑƒæĿᴿᴹᴿ
  • 4,983
  • 4
  • 38
  • 58
Nataniel Paiva
  • 485
  • 4
  • 9