web-dev-qa-db-fra.com

Plusieurs noms de propriété peuvent-ils être spécifiés dans l'annotation Spring @Value?

Je connais déjà le comportement de base de l'annotation @Value De Spring pour définir un champ à la valeur d'une propriété de projet comme ceci:

Fichier de propriétés du projet

foo.bar=value

Classe de configuration du projet

@Configuration
public class MyConfig {
    @Value("${foo.bar}")
    private String myValue;
}

Cependant, j'essaie de créer un projet de démarrage SpringBoot avec une configuration conditionnelle et j'aimerais normaliser les noms de propriété en quelque chose d'utile comme "com.mycompany.propertygroup.propertyname", mais pour faciliter la transition et encourager l'adoption, je souhaite prendre en charge le les anciens noms de propriété pendant un certain temps également, et se demandait donc s'il y avait un moyen d'autoriser plusieurs noms de propriété à définir le même champ? Par exemple:

Ma configuration théorique de démarrage

@Configuration
public class MyConfig {
    @Value("${com.mycompany.propertygroup.propertyname}" || "${oldconvention.property}")
    private String myValue;
}

Propriété du projet A

oldconvention.property=value

Propriété du projet B

com.mycompany.propertygroup.propertyname=value

Je n'arrive pas à trouver de documentation ou SO répond si c'est possible ou non et comment y arriver si c'est le cas ... Alors je me demande si c'est possible, ou si ce n'est pas le cas, existe-t-il une alternative à l'annotation @Value qui peut être utilisée pour obtenir le même effet?

Modifier pour clarifier: Je ne voudrais pas garder une trace de plusieurs valeurs, donc je n'ai pas besoin d'instructions sur la façon d'obtenir plusieurs valeurs ... l'objectif est de consolider en SINGLE VALUE celui qui peut avoir plusieurs noms. En pratique, il n'y aurait qu'une seule valeur de nom par projet qui utilise le démarreur ... seulement dans de rares cas où quelqu'un a peut-être oublié de supprimer l'ancienne propriété, chaque nom de propriété serait utilisé (et il aurait probablement de toute façon la même valeur ). Dans de tels cas, la NOUVELLE VALEUR DU NOM DE LA CONVENTION SERAIT SEULEMENT UNE UTILISÉE.

Mettre à jour

Alors que l'expression SpEL répond aux réponses fournies, fonctionne lorsque les deux propriétés sont présentes, le contexte d'application ne peut pas se charger lorsqu'un seul des noms de propriété est présent. Exemple:

Classe de configuration mise à jour

@Value("#{'${com.mycompany.propertygroup.propertyname}' != null ? '${com.mycompany.propertygroup.propertyname}' : '${oldconvention.propertyname}'}"
private String myProperty;

Fichier de propriété mis à jour

com.mycompany.propertygroup.propertyname=somevalue

Erreur

Caused by: Java.lang.IllegalArgumentException: 
Could not resolve placeholder 'oldconvention.propertyname' in value
"#{'${com.mycompany.propertygroup.propertyname}' != null ? '${com.mycompany.propertygroup.propertyname}' : '${oldconvention.propertyname}'}"

La présence des deux noms de propriété est contraire à l'objectif, qui est de permettre à un projet d'implémentation de configurer ce démarreur en utilisant SOIT l'ancienne convention OR la nouvelle convention ...

ne autre mise à jour ...

J'ai un peu joué avec l'expression SpEL, et le contrôle conditionnel fonctionne lorsque la propriété est présente et quand elle ne l'est pas, mais j'ai des problèmes avec la résolution de la propriété après coup. Je pense que le problème est dû au fait que les propriétés par défaut et les expressions SpEL complexes ne jouent pas Nice ensemble.

@Value("#{${com.mycompany.propertygroup.propertyname:null} != null ? '${com.mycompany.propertygroup.propertyname}' : '${oldconvention.propertyname}'}")
private String myProperty;

Lorsque mon SpEL est écrit comme ci-dessus, j'obtiens une exception d'espace réservé de propriété ne peut pas résoudre, ce qui signifie que les deux propriétés doivent être présentes pour que l'expression SpEL puisse être évaluée. J'ai donc réfléchi, je pourrais utiliser la syntaxe de propriété par défaut que j'ai vue pour résoudre les propriétés facultatives: @Value("${myoptionalproperty:defaultValue}")

Voici donc ma tentative de combiner la résolution de propriété par défaut avec l'expression SpEL:

@Value("#{${com.mycompany.propertygroup.propertyname:null} != null ? '${com.mycompany.propertygroup.propertyname:}' : '${oldconvention.propertyname:}'}")
private String myProperty;

Lorsque j'utilise la notation de propriété par défaut, je reçois toujours cette erreur:

org.springframework.expression.spel.SpelParseException: 
EL1041E: After parsing a valid expression, there is still more data in the expression: 'colon(:)'

et quand j'ai googlé cette erreur, la réponse populaire était que les propriétés devaient être encapsulées entre guillemets afin qu'elles évaluent en une chaîne ... mais elles sont déjà encapsulées (sauf la première .. j'ai dû déballer celle-ci depuis Je voulais que cela donne une valeur littérale nulle pour la vérification nulle). Je pense donc que les valeurs par défaut ne peuvent pas être utilisées avec des propriétés lorsqu'elles sont enveloppées dans une expression orthographique. En vérité, je n'ai vu le jeu de propriétés par défaut que lorsqu'une annotation @Value Est définie avec uniquement un détenteur de propriété pur, et toutes les propriétés que j'ai vues utilisées dans une expression SpEL n'ont jamais eu de jeu par défaut.

9
AEvans

Vous pouvez utiliser les éléments suivants @Value annotation:

@Configuration
public class MyConfig {

    @Value("#{'${com.mycompany.propertygroup.propertyname:${oldconvention.propertyname:}}'}")
    private String myValue;
}

Ce @Value l'annotation utilise com.mycompany.propertygroup.propertyname s'il est fourni et par défaut à oldconvention.property si com.mycompany.propertygroup.propertyname n'est pas fourni. Si aucun n'est fourni, la propriété est définie sur null. Vous pouvez définir cette valeur par défaut sur une autre valeur en remplaçant null par une autre valeur souhaitée.

Pour plus d'informations, consultez les informations suivantes:


Comme alternative, vous pouvez capturer les deux valeurs et effectuer une sélection avant de renvoyer la valeur:

@Configuration
public class MyConfig {

    @Value("${com.mycompany.propertygroup.propertyname:}")
    private String newValue;

    @Value("${oldconvention.propertyname:}")
    private String oldValue;

    public String getValue() {

        if (newValue != null && !newValue.isEmpty()) {
            // New value is provided
            System.out.println("New Value: " + newValue);
            return newValue;
        }
        else {
            // Default to the old value
            return oldValue;
       }
    }
}
7
Justin Albano

L'utilisation de SPEL est le meilleur moyen de résoudre ce problème. Cela devrait fonctionner

@Value("#{'${com.mycompany.propertygroup.propertyname}' != null ? '${com.mycompany.propertygroup.propertyname}' : '${oldconvention.property}'}")
private String myValue;
5
pvpkiran