Как добавить объект без конструктора в список с помощью Spring Expression Language
Я хочу добавить BigDecimal
в список с помощью Spring Expression Language.
public class SpelTest {
public List<BigDecimal> values;
StandardEvaluationContext context;
SpelExpressionParser parser;
@Before
public void setup() {
values = new ArrayList<>();
context = new StandardEvaluationContext(this);
parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
}
@Test
public void shouldChangeValue() {
values.add(BigDecimal.ONE);
parser.parseExpression("values[0]").setValue(context, "123.4");
assertThat(values.get(0)).isEqualTo(BigDecimal.valueOf(123.4)); // passes
}
@Test
public void shouldAddValue() {
parser.parseExpression("values[0]").setValue(context, "123.4");
assertThat(values.get(0)).isEqualTo(BigDecimal.valueOf(123.4)); // fails
}
}
Изменение первой записи проходит, но добавить запись не удается с
Caused by: java.lang.NoSuchMethodException: java.math.BigDecimal.<init>()
at java.base/java.lang.Class.getConstructor0(Class.java:3349)
at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2553)
at org.springframework.util.ReflectionUtils.accessibleConstructor(ReflectionUtils.java:185)
at org.springframework.expression.spel.ast.Indexer$CollectionIndexingValueRef.growCollectionIfNecessary(Indexer.java:715)
... 55 more
Не уверен, почему SpEL не может правильно инициализировать BigDecimal
когда список пуст. Удивительно, но я ничего не нашел об этой проблеме.
Спасибо за помощь!
3 ответа
Вы можете избежать этой проблемы, установив весь список вместо отдельных (не инициализированных) элементов. Вместо того
parser.parseExpression("values[0]").setValue(context, "123.4");
использование:
parser.parseExpression("values").setValue(context, "123.4");
Это также работает для нескольких элементов, довольно аккуратно:
parser.parseExpression("values").setValue(context, "123.4, 456.7");
Проблема в том, что вы активировали autoGrowCollections
на SpelParserConfiguraion
. Поэтому он пытается создать элемент с конструктором по умолчанию, если вы пытаетесь получить доступ к несуществующему элементу коллекции с помощью оператора индекса[]
. BigDecimal
не имеет конструктора по умолчанию и из-за этого не работает.
Что вы можете сделать, так это создать объект в самом SpEL. НАПРИМЕР:
@Test
public void shouldAddValue() {
parser.parseExpression("values.add(0, new java.math.BigDecimal(\"123.4\"))").getValue(context);
assertThat(values.size() > 0);
assertThat(values.get(0)).isEqualTo(BigDecimal.valueOf(123.4));
}
Или вы можете создать подкласс BigDecimal
ведьма имеет конструктор по умолчанию и использует этот класс.
Как отметил @Nirud, проблема в том, что BigDecimal
не имеет конструктора по умолчанию. Я расширил SpEL, чтобы добавитьnull
в список, когда нет конструктора по умолчанию. См. Этот запрос на перенос: https://github.com/spring-projects/spring-framework/pull/25367