dimanche 28 août 2022

Changing Annotation value via Reflection does not work JDK17

I have spring boot application with some controllers.

All the controllers have @RequestMapping annotation with a path/value attribute. I would like to change the value of this attribute at runtime by hooking into the bean lifecycle.

I am using BeanPostProcessor.postProcessBeforeInitialization() to accomplish this and below is the reflection code that I use:

public class RequestMappingProcessor implements BeanPostProcessor
{
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
    {
        RequestMapping requestMapping = bean.getClass().getAnnotation(RequestMapping.class);

        System.out.println("OldAnnotation Value " + requestMapping.value()[0]);

        Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(requestMapping);
        String[] values = (String[]) attributes.get("path");
        var newValue = getNewPath(path);

        Object handler = Proxy.getInvocationHandler(annotation);
        Field f;
        try
        {
            f = handler.getClass().getDeclaredField("memberValues");
        }
        catch (NoSuchFieldException | SecurityException e)
        {
            throw new IllegalStateException(e);
        }
        f.setAccessible(true);
        Map<String, Object> memberValues;
        try
        {
            memberValues = (Map<String, Object>) f.get(handler);
        }
        catch (IllegalArgumentException | IllegalAccessException e)
        {
            throw new IllegalStateException(e);
        }
        Object oldValue = memberValues.get(key);
        if (oldValue == null)
        {
            throw new IllegalArgumentException();
        }
        memberValues.put(key, newValue);
        memberValues.put("path", newValue);
        
        System.out.println("New Annotation Value " + requestMapping.value()[0]);
}

The things is that I do see it printing the updated values on console, but when I check the actual endpoint in postman or browser, still the old path works and not the new one. JDK 17.

I know that many would suggest to set the prefixed path at API level for all the controllers and all, but in my case, each controller might have a different prefix based upon some annotation. If you have some other suggestions, please suggest.





Aucun commentaire:

Enregistrer un commentaire