Как язык выражений Spring 3 взаимодействует с заполнителями свойств? - PullRequest
53 голосов
/ 11 января 2010

Spring 3 представил новый язык выражений (SpEL), который можно использовать в определениях бинов. Сам синтаксис довольно хорошо указан.

Что не ясно, так это то, как, если вообще, SpEL взаимодействует с синтаксисом заполнителя свойства, который уже присутствовал в предыдущих версиях. Есть ли в SpEL поддержка заполнителей свойств или мне нужно объединить синтаксис обоих механизмов и надеяться, что они объединятся?

Позвольте мне привести конкретный пример. Я хочу использовать синтаксис свойства ${x.y.z}, но с добавлением синтаксиса «значение по умолчанию», как это предусмотрено оператором elvis *1009*, для обработки случаев, когда ${x.y.z} не определено.

Я пробовал следующие синтаксисы без успеха:

  • #{x.y.z?:'defaultValue'}
  • #{${x.y.z}?:'defaultValue'}

Первый дает мне

Поле или свойство 'x' не найдено на объекте типа 'Org.springframework.beans.factory.config.BeanExpressionContext'

, что говорит о том, что SpEL не распознает это как заполнитель свойства.

Второй синтаксис генерирует исключение, говорящее о том, что заполнитель не распознан, поэтому распознаватель заполнителя вызывается , но происходит сбой, как и ожидалось, поскольку свойство не определено.

В документах не упоминается об этом взаимодействии, поэтому либо такая вещь невозможна, либо она недокументирована.

Кому-нибудь удалось это сделать?


ОК, я придумал небольшой автономный тестовый пример для этого. Это все работает как есть:

Сначала определения бинов:

<?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>

Затем тривиальный класс бобов:

пакетный тест;

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"));
    }
}

Задача - найти в файле beans выражение SpEL, которое позволяет мне указать значение по умолчанию в случаях, когда ${x.y.z} не может быть разрешено, и это значение по умолчанию должно быть указано как часть выражение, не экстернализованное в другом наборе свойств.

Ответы [ 9 ]

27 голосов
/ 11 января 2010

Чтобы получить доступ к заполнителю свойства из выражения SpEL, можно использовать следующий синтаксис: #{'${x.y.z}'}. Однако, это не может решить вашу проблему с оператором 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>
11 голосов
/ 11 января 2010

Кажется, вы пропустили двоеточие:

#{ ${x.y.z} ?: 'defaultValue' }
9 голосов
/ 13 апреля 2015

${myProps.item:defaultValue} означает, что когда myProps.item не существует, используйте defaultValue. Это стандартное поведение заполнителя свойства.

#{defaultValue} означает SpEL для буквального значения.

Итак, ${myProps.item:#{defaultValue}} означает, что myProps.item не существует, затем рассчитать значение SpEL и присвоить его целевому полю.

Пример:

${redis.auth:#{null}} означает, что когда свойства redis.auth не существуют, установите для него значение null.

8 голосов
/ 13 июня 2013

Если вы просто хотите установить значение по умолчанию для заполнителя, см. this :

   <property name="value" value="${x.y.z:defaultValue}"/> 

Если вы хотите проверить взаимодействие между SpEL и заполнителем, используя это:

   <!-- 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"/>
3 голосов
/ 15 марта 2012

Вы должны добавить это, чтобы запустить его в вашем примере

<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 не существует.

3 голосов
/ 01 февраля 2011

На самом деле Property-Placeholder может решить ваши проблемы самостоятельно. То есть Вы можете явно указать настройки по умолчанию в контексте Spring, используя свойство properties. Затем вы можете указать расположение для настроек, которые должны использоваться, и установить для свойства localOverride значение true. В этом случае все свойства, которые будут найдены во внешних ресурсах (указанных в location свойство), будут заменять свойства по умолчанию (явно определенные в контексте).

Надеюсь, я помог.

1 голос
/ 06 июля 2016

Вы можете:

<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}' }"/> 
   ...
0 голосов
/ 09 октября 2018

Нет необходимости использовать Элвиса, просто укажите значение по умолчанию после двоеточия.

@Value("${my.connection.timeout:5000}")
private int myTimeoutMillis;

или

@Retryable(maxAttemptsExpression = "#{${my.max.attempts:10}}")
public void myRetryableMethod() {
    // ...
}
0 голосов
/ 24 июля 2012

Я попробовал следующее, и это сработало (хотя и ужасно):

#{ myProps.getProperty('x.y.z')?:'Value B' }

...