Задать вопрос
@jenya7771

Как использовать SpEL в собственных аннотациях?

Здравствуйте, у меня есть собственная аннотация, в которую я хочу передать значение из properties, но это никак не получается. Как можно это сделать?

Сама аннотация
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ServerNameMapping {
    String[] value();
}


Место где получаю значение
public class ServerNameRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    @Override
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        ServerNameMapping serverNameMapping = AnnotationUtils.findAnnotation(handlerType, ServerNameMapping.class);

        if (serverNameMapping != null) {
            return new ServerNameRequestConditional(new HashSet<>(List.of(serverNameMapping.value())));
        }

        return super.getCustomTypeCondition(handlerType);
    }


    @Override
    protected RequestCondition<?> getCustomMethodCondition(Method method) {
        ServerNameMapping serverNameMapping = AnnotationUtils.findAnnotation(method, ServerNameMapping.class);

        if (serverNameMapping != null) {
            return new ServerNameRequestConditional(new HashSet<>(List.of(serverNameMapping.value())));
        }

        return super.getCustomMethodCondition(method);
    }
}


Вот так использую
@ServerNameMapping("${app.externalApiHostname}")
@RequestMapping("/api/v1")
@RestController
public class ExternalApiController {
    @GetMapping
    public void test() {
        System.out.println("ExternalApiController");
    }
}
  • Вопрос задан
  • 66 просмотров
Подписаться 1 Сложный 1 комментарий
Пригласить эксперта
Ответы на вопрос 2
jaxtr
@jaxtr
JavaEE/Spring-разработчик
Для парсинга и выполнения SpEL-выражений используется SpelExpressionParser, но ему нужно в процессе дать объект, откуда требуется получить требуемое значение, что-то вроде:
SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
Expression expression = spelExpressionParser.parseExpression("getAge() > 18");
String value = expression.getValue(object, String.class);


Но что-то мне подсказывает, что в данном случае нужно получить значение некоторой переменной из конфига. Если это так, то значительно проще в ServerNameRequestMappingHandlerMapping добавить свойство, в которое будет заранее внедрено значение свойства app.externalApiHostname при помощи `@Value("${app.externalApiHostname}")` или `@ConfigurationProperties`. Следовательно вычислять фактическое значение аннотации ServerNameMapping не нужно будет
Ответ написан
Комментировать
@jenya7771 Автор вопроса
Вот это помогло мне!

public class ServerNameRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
    private final EmbeddedValueResolver embeddedValueResolver;

    public ServerNameRequestMappingHandlerMapping(ConfigurableBeanFactory beanFactory) {
        this.embeddedValueResolver = new EmbeddedValueResolver(beanFactory);
    }

    @Override
    protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        ServerNameMapping serverNameMapping = AnnotationUtils.findAnnotation(handlerType, ServerNameMapping.class);

        if (serverNameMapping != null) {
            String host = embeddedValueResolver.resolveStringValue(serverNameMapping.value());
            if (host == null) throw new RuntimeException("Not passed hostname param");

            System.out.println(new HashSet<>(List.of(host)));
            return new ServerNameRequestConditional(new HashSet<>(List.of(host)));
        }

        return super.getCustomTypeCondition(handlerType);
    }

    @Override
    protected RequestCondition<?> getCustomMethodCondition(Method method) {
        ServerNameMapping serverNameMapping = AnnotationUtils.findAnnotation(method, ServerNameMapping.class);

        if (serverNameMapping != null) {
            return new ServerNameRequestConditional(new HashSet<>(List.of(serverNameMapping.value())));
        }

        return super.getCustomMethodCondition(method);
    }
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы