Как язык выражения Spring 3 взаимодействует с заполнителями свойств?
Spring 3 представил новый язык выражений (SpEL), который может использоваться в определениях bean. Сам синтаксис достаточно хорошо определен.
Не ясно, как, если вообще, SpEL взаимодействует с синтаксисом заполнителя свойства, который уже присутствовал в предыдущих версиях. Имеет ли SpEL поддержку заполнителей свойств, или мне нужно объединить синтаксис обоих механизмов и надеяться, что они объединятся?
Позвольте мне привести конкретный пример. Я хочу использовать синтаксис свойства ${x.y.z}
, но с добавлением синтаксиса "по умолчанию", предоставленного оператором elis для обработки случаев, когда ${x.y.z}
- undefined.
Я пробовал следующие синтаксисы без успеха:
-
#{x.y.z?:'defaultValue'}
-
#{${x.y.z}?:'defaultValue'}
Первый дает мне
Поле или свойство 'x' не могут быть найдены на объект типа 'Org.springframework.beans.factory.config.BeanExpressionContext'
который предполагает, что SpEL не признает это как заполнитель свойств.
Второй синтаксис выдает исключение, говорящее, что местозаполнитель не распознается, поэтому вызывающий объект-заполнитель вызывается, но не работает должным образом, поскольку свойство не определено.
В документах не упоминается об этом взаимодействии, поэтому либо такая вещь невозможна, либо недокументирована.
Кому это удалось?
Хорошо, я придумал небольшой, автономный тестовый пример. Это все работает как есть:
Сначала определения bean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
">
<context:property-placeholder properties-ref="myProps"/>
<util:properties id="myProps">
<prop key="x.y.z">Value A</prop>
</util:properties>
<bean id="testBean" class="test.Bean">
<!-- here is where the magic is required -->
<property name="value" value="${x.y.z}"/>
<!-- I want something like this
<property name="value" value="${a.b.c}?:'Value B'"/>
-->
</bean>
</beans>
Тогда тривиальный класс bean:
пакетный тест;
public class Bean {
String value;
public void setValue(String value) {
this.value = value;
}
}
И, наконец, тестовый пример:
package test;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class PlaceholderTest {
private @Resource Bean testBean;
@Test
public void valueCheck() {
assertThat(testBean.value, is("Value A"));
}
}
Задача - придумать выражение SpEL в файле beans, которое позволяет мне указать значение по умолчанию в случаях, когда ${x.y.z}
не может быть разрешено, и это значение по умолчанию должно быть указано как часть выражения, а не экстернализируется в другом наборе свойств.
Ответы
Ответ 1
Чтобы получить доступ к заполнителю свойств из выражения SpEL, можно использовать следующий синтаксис: #{'${x.y.z}'}
. Hovewer, он не может решить вашу проблему с помощью оператора elvis и значений по умолчанию, потому что он генерирует исключение, если ${x.y.z}
не может быть разрешено.
Но вам не нужно, чтобы SpEL объявлял значения по умолчанию для свойств:
<context:property-placeholder location="..." properties-ref="defaultValues"/>
<bean id = "defaultValues" class = "org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="x.y.z">ZZZ</prop>
</props>
</property>
</bean>
<bean ...>
<property name = "..." value = "${x.y.z}" />
</bean>
Ответ 2
Кажется, вы пропустили двоеточие:
#{ ${x.y.z} ?: 'defaultValue' }
Ответ 3
Если вы просто хотите установить значение по умолчанию для заполнителя, см. this:
<property name="value" value="${x.y.z:defaultValue}"/>
Если вы хотите протестировать взаимодействие между SpEL и placeholder, используя это:
<!-- set value "77-AA-BB-CC-88" when property "x.y.z" not exist -->
<property name="value" value="77-#{'AA-${x.y.z:BB}-CC'}-88"/>
Ответ 4
${myProps.item:defaultValue}
означает, что, когда myProps.item
не существует, используйте defaultValue
. Это поведение по умолчанию заполнитель свойств.
#{defaultValue}
означает значение SpEL для буквенного значения.
Итак, ${myProps.item:#{defaultValue}}
означает, что myProps.item
не существует, затем вычисляет значение SpEL и назначает его целевому полю.
Пример:
${redis.auth:#{null}}
означает, что когда свойства redis.auth
не существуют, установите его на null
.
Ответ 5
Фактически Property-Placeholder может самостоятельно решить ваши проблемы.
То есть вы можете явно указать параметры по умолчанию в контексте Spring, используя свойство properties
. Затем вы можете указать местоположение для параметров, которые должны использоваться, и установить свойство localOverride
на true
.
В этом случае все свойства, которые будут найдены во внешних ресурсах (указанные в свойстве location
), переопределяют значения по умолчанию (явно определенные в контексте).
Надеюсь, я помог.
Ответ 6
Вам нужно добавить это, чтобы запустить его в вашем примере
<bean id="testBean" class="elvis.Bean">
<!-- here is where the magic is required
<property name="value" value="${x.y.z}"/>
-->
<!-- I want something like this -->
<property name="value" value="#{myProps.get('a.b.c')?:'Value B'}"/>
</bean>
Ваш подход не работает, потому что Spring пытается оценить ${a.b.c}
объект a
с членом b
с элементом c
, который приводит к NPE, потому что a
не существует.
Ответ 7
вы можете:
<bean id="testBean" class="test.Bean">
<!-- if 'a.b.c' not found, then value="Value B" --->
<property name="value" value="${a.b.c:Value B}"/>
</bean>
или
...
<!-- if 'a.b.c' not found , but 'a.b' found ,then value=${a.b}
if 'a.b' also not found , then value="a"
-->
<property name="value" value="${a.b.c:${a.b:a}"/>
...
или ...
<!-- if 'a.b.c' not found , but 'a.b' found ,then value=${a.b}
if 'a.b' also not found , then value="a"
-->
<property name="value" value="#{ '${a.b.c:}' ?: '${a.b:a}' }"/>
...
Ответ 8
Я пробовал следующее, и это сработало (довольно уродливо):
#{ myProps.getProperty('x.y.z')?:'Value B' }