Skip to content

Instantly share code, notes, and snippets.

@aldobongio
Created August 18, 2021 14:12
Show Gist options
  • Save aldobongio/6a22f49863c7a777612f7887bbb8fd1d to your computer and use it in GitHub Desktop.
Save aldobongio/6a22f49863c7a777612f7887bbb8fd1d to your computer and use it in GitHub Desktop.
Fix for Spring Boot 2.5.x + Zuul - NoSuchMethodError: ErrorController.getErrorPath()
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.CallbackFilter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.cloud.netflix.zuul.web.ZuulController;
import org.springframework.cloud.netflix.zuul.web.ZuulHandlerMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/** Zuul configuration. */
@Configuration
public class ZuulConfiguration {
/** The path returned by ErrorContoller.getErrorPath() with Spring Boot < 2.5 (and no longer available on Spring Boot >= 2.5). */
private static final String ERROR_PATH = "/error";
/**
* Constructs a new bean post-processor for Zuul.
*
* @param routeLocator
* the route locator.
* @param zuulController
* the Zuul controller.
* @param errorController
* the error controller.
* @return the new bean post-processor.
*/
@Bean
public ZuulPostProcessor zuulPostProcessor(@Autowired RouteLocator routeLocator, @Autowired ZuulController zuulController,
@Autowired(required = false) ErrorController errorController) {
return new ZuulPostProcessor(routeLocator, zuulController, errorController);
}
private static final class ZuulPostProcessor implements BeanPostProcessor {
private final RouteLocator routeLocator;
private final ZuulController zuulController;
private final boolean hasErrorController;
ZuulPostProcessor(RouteLocator routeLocator, ZuulController zuulController, ErrorController errorController) {
this.routeLocator = routeLocator;
this.zuulController = zuulController;
this.hasErrorController = (errorController != null);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (hasErrorController && (bean instanceof ZuulHandlerMapping)) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ZuulHandlerMapping.class);
enhancer.setCallbackFilter(LookupHandlerCallbackFilter.INSTANCE); // only for lookupHandler
enhancer.setCallbacks(new Callback[] { LookupHandlerMethodInterceptor.INSTANCE, NoOp.INSTANCE });
Constructor<?> ctor = ZuulHandlerMapping.class.getConstructors()[0];
return enhancer.create(ctor.getParameterTypes(), new Object[] { routeLocator, zuulController });
}
return bean;
}
}
private static enum LookupHandlerCallbackFilter implements CallbackFilter {
INSTANCE;
@Override
public int accept(Method method) {
if ("lookupHandler".equals(method.getName())) {
return 0;
}
return 1;
}
}
private static enum LookupHandlerMethodInterceptor implements MethodInterceptor {
INSTANCE;
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if (ERROR_PATH.equals(args[0])) {
/* by entering this branch we avoid the ZuulHandlerMapping.lookupHandler method to trigger the NoSuchMethodError */
return null;
}
return methodProxy.invokeSuper(target, args);
}
}
}
@aldobongio
Copy link
Author

Relates to this issue

@varunshet393
Copy link

@aldobonigo How do i integrate same to my Zuul application ? just create the same class in configuration package and run the same ?

@julianoBRL
Copy link

julianoBRL commented Sep 16, 2021

@varunshet393

The last time i used this code in my project i just created it and started the application, it started with the application itself.

@sandipchitale
Copy link

Thanks!

@csh0711
Copy link

csh0711 commented Dec 28, 2021

Thanks a lot! :-)

@wilfridmaxis
Copy link

Thank you for this solution. I am using it and see that My Filter to inject the Authorization Header is not Invoked. Did you have the same problem?

@yassinemenssi
Copy link

Thanks!!

@waeng
Copy link

waeng commented Feb 26, 2022

Thanks!!

@free-leung
Copy link

Thanks a lot! It's working now.

@ronaimate
Copy link

Thanks!!!

@artwellmamvura
Copy link

This worked instantly with

org.springframework.boot - spring-boot-starter-parent - 2.6.4

Was getting http 500 error for the Eureka server

@mahulivishal
Copy link

Is this fix tested for 2.6.6 of spring-boot?

@frankyhollywood
Copy link

also works for upgrade to spring-boot 2.6.7, thx!

@and-ratajski
Copy link

Seems to work in ver. 2.7.1 as well! - At least this very error is gone 😉 THANKS!

@rebel-codeaz
Copy link

Seems to work in ver. 2.7.1 as well! - At least this very error is gone wink THANKS!

Hey! I'm a newbie to learn microservices using spring boot. Can anybody tell where to create this file? I'm getting error in the pom.xml itself. Using spring version 2.7.5

@SAURABH384
Copy link

Hi I am trying to migrate a spring boot 2.4.4 and zuul 1.3.1 to 2.7.0 but its not working with 1.3.1 so I tried to upgarde to zuul 2.0.0 but now issue is In my Code RequestContext was used But now in zuul 2.0.0 Its not there Any Idea How to Fix it.

@mnavyasri
Copy link

does this solution is working with spring boot 3.0.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment