jtls - lenguaje de expresiones java
¿Cómo interactúa el lenguaje de expresión de Spring 3 con los marcadores de posición de propiedades? (8)
Spring 3 ha introducido un nuevo lenguaje de expresión (SpEL) que se puede usar en las definiciones de bean. La sintaxis en sí está bastante bien especificada.
Lo que no está claro es cómo, en todo caso, SpEL interactúa con la sintaxis del marcador de posición de la propiedad que ya estaba presente en las versiones anteriores. ¿SpEL tiene soporte para marcadores de posición de propiedad, o tengo que combinar la sintaxis de ambos mecanismos y espero que se combinen?
Déjame dar un ejemplo concreto. Quiero usar la sintaxis de la propiedad ${xyz}
, pero con la adición de la sintaxis de "valor predeterminado" proporcionada por el operador elvis para manejar casos donde ${xyz}
no está definido.
He intentado las siguientes sintaxis sin éxito:
-
#{xyz?:''defaultValue''}
-
#{${xyz}?:''defaultValue''}
El primero me da
No se puede encontrar el campo o la propiedad ''x'' en el objeto del tipo ''org.springframework.beans.factory.config.BeanExpressionContext''
lo que sugiere que SpEL no reconoce esto como un marcador de posición de propiedad.
La segunda sintaxis arroja una excepción que dice que el marcador de posición no se reconoce, por lo que se invoca el marcador de posición, pero está fallando como se esperaba, ya que la propiedad no está definida.
Los documentos no mencionan esta interacción, por lo que tal cosa no es posible o no está documentada.
¿Alguien logró hacer esto?
De acuerdo, se me ocurrió un caso de prueba pequeño e independiente para esto. Todo esto funciona como está:
Primero, las definiciones de frijol:
<?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>
Entonces, la clase trivial de frijoles:
prueba del paquete;
public class Bean {
String value;
public void setValue(String value) {
this.value = value;
}
}
Y, por último, el caso de prueba:
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"));
}
}
El reto: crear una expresión SpEL en el archivo beans que me permita especificar un valor predeterminado en los casos en que ${xyz}
no se pueda resolver, y este valor predeterminado se debe especificar como parte de la expresión, no se debe externalizar en otra propiedad conjunto.
En realidad, Property-Placeholder puede resolver sus problemas por sí mismo. Es decir, puede especificar configuraciones predeterminadas de forma explícita en el contexto de Spring, utilizando las propiedades de properties
. Luego puede especificar la ubicación de la configuración que se debe usar y establecer la propiedad localOverride
en true
. En tal caso, todas las propiedades que se encontrarán en los recursos externos (especificadas en propiedad de location
) anularán las predeterminadas (explícitamente definidas dentro del contexto).
Espero que haya ayudado.
He intentado lo siguiente y funcionó (aunque bastante feo):
#{ myProps.getProperty(''xyz'')?:''Value B'' }
Necesita agregar esto para ejecutarlo dentro de su ejemplo
<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>
Su enfoque no funciona, porque Spring intenta evaluar ${abc}
a un objeto a
con miembro b
con miembro c
que da como resultado un NPE porque a
no existe.
Para acceder al marcador de posición de propiedad de la expresión SpEL, se puede usar la siguiente sintaxis: #{''${xyz}''}
. Hovewer, no puede resolver su problema con el operador elvis y los valores predeterminados, ya que arrojaría una excepción cuando ${xyz}
no se pueda resolver.
Pero no necesita SpEL para declarar valores predeterminados para las propiedades:
<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>
Parece que te perdiste el colon:
#{ ${x.y.z} ?: ''defaultValue'' }
Si solo desea establecer el valor predeterminado para marcador de posición, vea this :
<property name="value" value="${x.y.z:defaultValue}"/>
Si desea probar la interacción entre SpEL y el marcador de posición, use esto:
<!-- 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"/>
puedes:
<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>
o
...
<!-- 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}"/>
...
o ...
<!-- 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}'' }"/>
...
${myProps.item:defaultValue}
significa que cuando myProps.item
no existe, use defaultValue
. Ese es el comportamiento predeterminado del marcador de posición de propiedad.
#{defaultValue}
significa SpEL para el valor literal.
Por lo tanto, ${myProps.item:#{defaultValue}}
significa que myProps.item
no existe, luego calcule el valor de SpEL y asígnelo al campo de destino.
Ejemplo:
${redis.auth:#{null}}
significa que cuando redis.auth
propiedades redis.auth
no existen, redis.auth
como null
.