Изменение значения аннотации Spring RequestMapping во время выполнения - PullRequest
0 голосов
/ 23 апреля 2020

Я пытаюсь изменить значение аннотации RequestMapping во время выполнения для метода HTTP GET - привет (который возвращает простую строку) внутри класса обслуживания отдыха - SpringRestController .

Значение uri, определенного в аннотации @RequestMapping для метода hello, равно "/ hello / {name}" . Я могу изменить значение аннотации во время выполнения на "hi / {name}" , используя отражение в конструкторе класса SpringRestController.

Я могу проверить измененное значение, напечатав значение аннотации внутри метода init, аннотированного аннотацией @PostConstruct, а также внутри другого контроллера. Однако, когда я пытаюсь получить доступ к методу GET в браузере: с измененным значением - http://localhost: 9090 / пружинный ботинок-упор / отдых / привет / Pradeep ( не работает )

с исходным значением - http://localhost: 9090 / пружинный ботинок-отдых / отдых / привет / Pradeep ( отлично работает )

Я ожидаю, что метод HTTP GET hello будет доступен с использованием измененного значения пути во время выполнения - "/ hi / {name}" вместо исходного значения пути - "/ hello / {name}" . PS - Это требование для нас, и оно должно быть сделано таким образом, чтобы значение @RequestMapping можно было настраивать извне без изменений в исходном коде. Вот код - SpringRestController. java

package com.example.spring.rest.controller;
import javax.annotation.PostConstruct;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.spring.rest.custom.annotations.ConfigurableRequestMapping;
import com.example.spring.rest.reflection.ReflectionUtils;
@RestController
@RequestMapping("/rest")
public class SpringRestController {

    public SpringRestController() {
            RequestMapping rm = SpringRestController.class.getAnnotation(RequestMapping.class);
            System.out.println("Old annotation : " + rm.value()[0]);
            RequestMapping rmNew = new ConfigurableRequestMapping("/rest");
            ReflectionUtils.alterAnnotationValueJDK8_v2(SpringRestController.class, RequestMapping.class, rmNew);
            RequestMapping rmModified = SpringRestController.class.getAnnotation(RequestMapping.class);
            System.out.println("Constructor -> New annotation : " + rmModified.value()[0]);
    }

    @RequestMapping(value = "/hello/{name}")
    public String hello(@PathVariable String name) {
        System.out.println("Name : " + name);
        return "Hello " + name;
    }

    @PostConstruct
    private void init(){
        System.out.println("Annotations initialization post construct.");
        RequestMapping rmModified = SpringRestController.class.getAnnotation(RequestMapping.class);
        System.out.println("Init method -> New annotation : " + rmModified.value()[0]);
    }
}

Код для изменения значения аннотации -

ReflectionUtils. java

package com.example.spring.rest.reflection;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.spring.rest.controller.SpringRestController;
import com.example.spring.rest.custom.annotations.ConfigurableRequestMapping;
import com.example.spring.rest.utils.PropertyReader;

public class ReflectionUtils {

    @SuppressWarnings("unchecked")
    public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue){
        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 || oldValue.getClass() != newValue.getClass()) {
            throw new IllegalArgumentException();
        }
        memberValues.put(key,newValue);
        return oldValue;
    }
}

1 Ответ

0 голосов
/ 23 апреля 2020

Невозможно изменить значение аннотации во время выполнения, поскольку Spring уже зарегистрировал это значение. Помимо интереса к тому, чего вы действительно пытаетесь достичь, не стесняйтесь использовать несколько параметров @PathVariable и самостоятельно выполнять оценку.

// Either hardcoded values or loaded from elsewhere
private static List<String> GREETINGS = Arrays.asList("Hello", "Hi");

...

@GetMapping(value = "/{greeting}/{name}")
public String greeting(@PathVariable String greeting, @PathVariable String name) {
    System.out.println("Name : " + name);
    if (GREETINGS.stream().anyMatch(greeting::equalsIgnoreCase)) {
        return greeting + " " + name;
    }
    throw new ResponseStatusException(HttpStatus.BAD_REQUEST, 
        "Unknown greeting " + greeting, e);
}

Кроме того, цель конечных точек API REST заключается в том, чтобы предсказуемы . То, что вы пытаетесь достичь, кажется противоречием. У вас может быть несколько конечных точек, таких как /hi/{name} и /hello/{name}, однако в этом конкретном случае либо использование нескольких параметров является правильным, либо эта следующая конечная точка, которая учитывает ресурс и использует @RequestParam. Я бы скорее разработал его таким образом, поскольку ресурс приветствие .

  • Пример конечной точки: /greeting?greeting={greeting}&name={name}
  • Пример вызова: /greeting?greeting=Hello&name=Pradeep%20Prabhakaran
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...