Не удается вызвать SPeL Expression.setValue () с картой - PullRequest
0 голосов
/ 03 апреля 2019

Я пишу некоторый код, чтобы разрешить динамические изменения свойств, используя язык выражений Spring.Я передаю имя компонента, имя свойства и выражение для нового значения, все строки.

Это прекрасно работает для свойств типа string, int, boolean и list.Я не могу заставить свойство карты работать.Я посмотрел на документацию SPeL, включая примеры, но я не вижу ничего плохого в том, что я делаю.Исключение, которое я получаю, бесполезно.

Игнорирование блоков try / catch, основной код выглядит так:

ExpressionParser parser = new SpelExpressionParser();
Expression parsedPropertyNameExpression = parser.parseExpression(propertyName);
SimpleEvaluationContext evalContext = SimpleEvaluationContext.forReadWriteDataBinding().build();
Object currentValue = parsedPropertyNameExpression.getValue(evalContext, bean);
parsedPropertyNameExpression.setValue(evalContext, bean, expression);

Когда мое "выражение" равно "789, 0123, 345"и свойство, которое я устанавливаю, является списком, это прекрасно работает.

Однако, когда я устанавливаю свойство типа Map (""), где значение выражения равно "{abc: 'def', ghi:' jkl '} ", я получаю следующее исключение:

 org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [java.util.Map<java.lang.String, java.lang.String>]

Я пробовал разные варианты этой строки выражения, в основном с тем же результатом.

Обновление :

Я заметил следующее сообщение SO: Как добавить карту с помощью аннотации @Value Spring? .

Упоминается один из непринятых ответовопределяя Map в свойствах и добавляя ее с помощью аннотации @Value, которая, я думаю, использует аналогичный механизм.Как я могу сделать это в коде?

1 Ответ

1 голос
/ 03 апреля 2019

Исключение, которое я получаю, бесполезно.

Не найден конвертер, способный преобразовать тип [java.lang.String] в тип [java.util.Map]

Кажется, мне ясно.

Нет встроенной поддержки преобразования строкового представления карты в Map объект.

Вы можете зарегистрировать пользовательскую функцию или использовать ссылку на бин Джексона ObjectMapper в выражении SpEL.

EDIT

Вот один из способов сделать это (с помощью пользовательского Converter с использованием Джексона) ...

public class So55485198Application {

    public static void main(String[] args) {
        Bean bean = new Bean();
        getAndSet("list", bean, "abc, def");
        getAndSet("map", bean, "{'abc':'def'}");
    }

    public static void getAndSet(String propertyName, Bean bean, String expression) {
        ExpressionParser parser = new SpelExpressionParser();
        Expression parsedPropertyNameExpression = parser.parseExpression(propertyName);
        DefaultConversionService conversionService = new DefaultConversionService();
        conversionService.addConverter(new StringToMapConverter());
        SimpleEvaluationContext evalContext = SimpleEvaluationContext.forReadWriteDataBinding()
                .withConversionService(conversionService)
                .build();
        Object currentValue = parsedPropertyNameExpression.getValue(evalContext, bean);
        System.out.println("old:" + currentValue);
        parsedPropertyNameExpression.setValue(evalContext, bean, expression);
        System.out.println("new:" + parsedPropertyNameExpression.getValue(evalContext, bean));
    }

    static class StringToMapConverter implements Converter<String, Map<String, String>> {

        private static final ObjectMapper objectMapper = new ObjectMapper();

        static {
            objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        }

        @SuppressWarnings("unchecked")
        @Override
        public Map<String, String> convert(String source) {
            try {
                return this.objectMapper.readValue(source, LinkedHashMap.class);
            }
            catch (IOException e) {
                e.printStackTrace();
                throw new IllegalStateException(e);
            }
        }

    }

    static class Bean {

        private List<String> list = new ArrayList<>(Arrays.asList("foo", "bar"));

        private Map<String, String> map = new HashMap<>(Collections.singletonMap("foo", "bar"));

        public List<String> getList() {
            return this.list;
        }

        public void setList(List<String> list) {
            this.list = list;
        }

        public Map<String, String> getMap() {
            return this.map;
        }

        public void setMap(Map<String, String> map) {
            this.map = map;
        }

    }

}
...