I get the following error when navigating to the url set for our OpenAPI json file after upgrading from Spring Boot 3.3.5 to 3.4.1:
java.lang.NoSuchMethodError: 'void .springframework.web.method.ControllerAdviceBean.<init>(java.lang.Object)'
We're using springdoc version 2.2.0 (artifact id: springdoc-openapi-starter-webmvc-ui) and Java 17 and using ControllerAdvice in one of our modules. We set the following JVM properties:
-Dspringdoc.api-docs.groups.enabled=true -Dspringdoc.swagger-ui.enabled=false -Dspringdoc.api-docs.path=/summary/api/openapi.json -Dspringdoc.api-docs.version=OPENAPI_3_1 -Dspringdoc.group-configs[0].group=summary -Dspringdoc.group-configs[0].paths-to-match=/** -Dspringdoc.group-configs[0].packages-to-scan=com.summary -Dspringdoc.group-configs[0].paths-to-include=/** -Dspringdoc.group-configs[0].paths-to-exclude=/*/ws/*
It works again when I revert the Spring Boot version.
This is the class that is failing:
package com.web.controller;
import jakarta.servlet.http.HttpServletRequest;
import .apache.lucene.queryparser.classic.ParseException;
import .slf4j.Logger;
import .slf4j.LoggerFactory;
import .springframework.http.HttpStatus;
import .springframework.web.bind.annotation.ControllerAdvice;
import .springframework.web.bind.annotation.ExceptionHandler;
import .springframework.web.bind.annotation.ResponseStatus;
import .springframework.core.Ordered;
import .springframework.core.annotation.Order;
import .springframework.web.servlet.ModelAndView;
import java.InetAddress;
import java.UnknownHostException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* This is to handle exceptions across all controllers in a uniform way.
*/
@ControllerAdvice
@Order()
public class GlobalControllerExceptionHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(GlobalControllerExceptionHandler.class);
private static final String MODEL = "model";
private PropertiesContainer propertiesContainer = null;
/**
* To deal with search failure cases
* @param request
* @param exception
* @return
*/
@ExceptionHandler(SearchFailedException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ModelAndView handleSearchFailedException(final HttpServletRequest request, final Exception exception) {
final ModelAndView modelAndView = new ModelAndView("error");
final Map<String, Object> model = getBaseModel(request, exception);
// If parsing error,
if (exception != null && exception.getCause() != null && exception.getCause().getClass().equals(ParseException.class)) {
model.put("parseError", true);
model.put("original_query", request.getParameter("query"));
model.put("title", "Sorry, we can't perform your search request");
}
modelAndView.addObject(MODEL, model);
return modelAndView;
}
/**
* To deal with other exceptions
* @param request
* @param exception
* @return
*/
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ModelAndView handleException(final HttpServletRequest request, final Exception exception) {
final ModelAndView modelAndView = new ModelAndView("error");
final Map<String, Object> model = getBaseModel(request, exception);
model.put("title", "Something has gone wrong with our web server");
modelAndView.addObject(MODEL, model);
return modelAndView;
}
/**
* Return a base map with given request and exception
* @param request
* @param exception
* @return
*/
protected Map<String, Object> getBaseModel(final HttpServletRequest request, final Exception exception) {
final Map<String, Object> model = new HashMap<>();
setException(model, exception);
setTimeStamp(model);
setLocalHost(model);
setAppVersion(model);
return model;
}
protected static void setException(final Map<String, Object> model, final Exception exception) {
model.put("exception", exception);
}
protected static void setLocalHost(final Map<String, Object> model) {
try {
model.put("server", getCurrentHostname());
} catch (final UnknownHostException e) {
LOGGER.warn(ExceptionMessageContainer.cannotGetLocalHostName(), e);
}
}
protected static void setTimeStamp(final Map<String, Object> model) {
model.put("timestamp", new Date(System.currentTimeMillis()).toString());
}
protected static String getCurrentHostname() throws UnknownHostException {
return InetAddress.getLocalHost().getHostName();
}
protected PropertiesContainer getPropertiesContainer() {
if (propertiesContainer == null) {
propertiesContainer = PropertiesHelper.getPropertiesContainer();
}
return propertiesContainer;
}
protected void setAppVersion(final Map<String, Object> model) {
if (MetaInfUtil.getAppVersion() != null) {
model.put("appversion", MetaInfUtil.getAppVersion());
}
else {
model.put("appversion", System.currentTimeMillis());
}
}
}
And the full stacktrace:
2025-02-04 11:47:06,530 DEBUG [http-nio-8080-exec-2] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Using @ExceptionHandler com.web.controller.GlobalControllerExceptionHandler#handleException(HttpServletRequest, Exception)
jakarta.servlet.ServletException: Handler dispatch failed: java.lang.NoSuchMethodError: 'void .springframework.web.method.ControllerAdviceBean.<init>(java.lang.Object)'
at .springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1103)
at .springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978)
at .springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at .springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
at .springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:289)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:114)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at .apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at .apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at .apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
at .apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at .apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at .apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at .apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:663)
at .apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
at .apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
at .apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at .apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
at .apache.tomcat.util.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
at .apache.tomcat.util.SocketProcessorBase.run(SocketProcessorBase.java:52)
at .apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
at .apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at .apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.NoSuchMethodError: 'void .springframework.web.method.ControllerAdviceBean.<init>(java.lang.Object)'
at .springdoc.core.service.GenericResponseService.lambda$getGenericMapResponse$8(GenericResponseService.java:700)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:178)
at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992)
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.AbstractPipeline.evaluate(AbstractPipeline.java:575)
at java.base/java.util.stream.AbstractPipeline.evaluateToArrayNode(AbstractPipeline.java:260)
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:616)
at java.base/java.util.stream.ReferencePipeline.toArray(ReferencePipeline.java:622)
at java.base/java.util.stream.ReferencePipeline.toList(ReferencePipeline.java:627)
at .springdoc.core.service.GenericResponseService.getGenericMapResponse(GenericResponseService.java:702)
at .springdoc.core.service.GenericResponseService.build(GenericResponseService.java:245)
at .springdoc.api.AbstractOpenApiResource.calculatePath(AbstractOpenApiResource.java:496)
at .springdoc.api.AbstractOpenApiResource.calculatePath(AbstractOpenApiResource.java:673)
at .springdoc.webmvc.api.OpenApiResource.lambda$calculatePath$11(OpenApiResource.java:219)
at java.base/java.util.Optional.ifPresent(Optional.java:178)
at .springdoc.webmvc.api.OpenApiResource.calculatePath(OpenApiResource.java:200)
at .springdoc.webmvc.api.OpenApiResource.lambda$getPaths$2(OpenApiResource.java:170)
at java.base/java.util.Optional.ifPresent(Optional.java:178)
at .springdoc.webmvc.api.OpenApiResource.getPaths(OpenApiResource.java:149)
at .springdoc.api.AbstractOpenApiResource.getOpenApi(AbstractOpenApiResource.java:350)
at .springdoc.webmvc.api.OpenApiResource.openapiJson(OpenApiResource.java:124)
at .springdoc.webmvc.api.OpenApiWebMvcResource.openapiJson(OpenApiWebMvcResource.java:111)
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 .springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:257)
at .springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:190)
at .springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
at .springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:986)
at .springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:891)
at .springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at .springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088)
... 40 more
I've tried setting the order precedence to high as seen in another post, since there is another ControllerAdvice in the same module, and that didn't work. I also tried changing @ControllerAdvice to @RestControllerAdvice, also with no effect. The other openapi.json in our app, which is located in the root application, does work.