webentwicklung-frage-antwort-db.com.de

Wie interagiert die Ausdruckssprache von Spring 3 mit Platzhaltern von Eigenschaften?

Spring 3 hat ein neues Ausdruckssprache (SpEL) eingeführt, das in Bean-Definitionen verwendet werden kann. Die Syntax selbst ist ziemlich genau angegeben.

Unklar ist, wie, wenn überhaupt, SpEL mit der in früheren Versionen bereits vorhandenen Eigenschaftsplatzhalter-Syntax interagiert. Hat SpEL Unterstützung für Platzhalter für Eigenschaften, oder muss ich die Syntax beider Mechanismen kombinieren und hoffen, dass sie kombiniert werden?

Lassen Sie mich ein konkretes Beispiel geben. Ich möchte die Eigenschaftssyntax ${x.y.z} verwenden, jedoch mit der hinzugefügten "default value" -Syntax, die vom elvis-Operator zur Verfügung gestellt wird, um Fälle zu behandeln, in denen ${x.y.z} nicht definiert ist.

Ich habe die folgenden Syntaxen ohne Erfolg ausprobiert:

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

Der erste gibt mir 

Feld oder Eigenschaft 'x' kann nicht gefunden werden auf Objekt vom Typ 'org.springframework.beans.factory.config.BeanExpressionContext'

was darauf hindeutet, dass SpEL dies nicht als Platzhalter für Eigenschaften erkennt.

Die zweite Syntax löst eine Ausnahme aus, die besagt, dass der Platzhalter nicht erkannt wird. Der Platzhalterauflöser wird jedoch aufgerufen, schlägt jedoch wie erwartet fehl, da die Eigenschaft nicht definiert ist.

Die Dokumente erwähnen diese Interaktion nicht, daher ist dies entweder nicht möglich oder es ist nicht dokumentiert.

Jemand hat das geschafft?


OK, ich habe mir dazu einen kleinen, in sich geschlossenen Testfall ausgedacht. Das alles funktioniert wie es ist:

Zuerst die Bean-Definitionen:

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

Dann die triviale Bohnenklasse:

pakettest;

public class Bean {

    String value;

    public void setValue(String value) {
        this.value = value;
    }
}

Und zum Schluss noch der Testfall:

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

Die Herausforderung - einen SpEL-Ausdruck in der Beans-Datei aufzurufen, der es mir ermöglicht, einen Standardwert anzugeben, wenn ${x.y.z} nicht aufgelöst werden kann und dieser Standardwert muss als Teil des Ausdrucks angegeben werden muss, nicht in einem anderen Eigenschaftssatz.

52
skaffman

Für den Zugriff auf den Eigenschaftsplatzhalter über den SpEL-Ausdruck kann die folgende Syntax verwendet werden: #{'${x.y.z}'}. Das Problem mit dem elvis-Operator und den Standardwerten kann jedoch nicht gelöst werden, da eine Ausnahme ausgelöst wird, wenn ${x.y.z} nicht aufgelöst werden kann.

Sie müssen jedoch keine Standardwerte für Eigenschaften von SpEL angeben:

<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>
27
axtavt

Es scheint, dass Sie den Doppelpunkt verpasst haben:

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

Wenn Sie nur den Standardwert für Platzhalter festlegen möchten, lesen Sie this :

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

Wenn Sie die Interaktion zwischen SpEL und Platzhalter testen möchten, verwenden Sie Folgendes:

   <!-- 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"/>
8
btpka3

${myProps.item:defaultValue} bedeutet, dass defaultValue verwendet wird, wenn myProps.item nicht existiert. Dies ist das Standardverhalten eines Eigenschaftsplatzhalters. 

#{defaultValue} bedeutet SpEL für den Literalwert. 

Also, ${myProps.item:#{defaultValue}} bedeutet, wenn myProps.item nicht existiert, dann den Wert von SpEL berechnen und dem Zielfeld zuweisen.

Beispiel:

${redis.auth:#{null}} bedeutet, wenn redis.auth-Eigenschaften nicht vorhanden sind, setzen Sie ihn auf null.

7
smartwjw

Sie müssen dies hinzufügen, damit es in Ihrem Beispiel ausgeführt werden kann

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

Ihr Ansatz funktioniert nicht, da Spring versucht, ${a.b.c} zu einem Objekt a mit Member b mit Member c auszuwerten, was zu einer NPE führt, da a nicht vorhanden ist.

3
micfra

Eigentlich kann der Property-Placeholder Ihre Probleme selbst lösen. Sie können die Standardeinstellungen explizit im Spring-Kontext angeben, indem Sie die Eigenschaft properties verwenden. Dann können Sie den Speicherort für die Einstellungen angeben, die verwendet werden sollen, und die Eigenschaft localOverride auf true setzen. In diesem Fall überschreiben alle Eigenschaften, die in externen Ressourcen (in der location-Eigenschaft angegeben) gefunden werden, die Standardeinstellungen (explizit im Kontext definiert).

Hoffe ich habe geholfen.

3
Myron

du darfst:

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

oder

 ...
 <!-- 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}"/> 
 ...

oder ...

   <!-- 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}' }"/> 
   ...
1
qxo

Es ist nicht notwendig, Elvis zu verwenden. Geben Sie einfach den Standardwert nach einem Doppelpunkt an.

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

oder

@Retryable(maxAttemptsExpression = "#{${my.max.attempts:10}}")
public void myRetryableMethod() {
    // ...
}
0

Ich habe Folgendes versucht und es hat funktioniert (obwohl ziemlich hässlich):

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

0
Gergely Toth