2015-02-06 8 views
22

Ist es möglich, Spring @ Value zu verwenden, um Werte aus der Eigenschaftendatei der HashMap zuzuordnen.Ausfüllen von HashMap aus der Java-Eigenschaftendatei mit Spring @Value

Momentan habe ich so etwas, und die Zuordnung eines Wertes ist kein Problem. Aber ich muss benutzerdefinierte Werte in HashMap Verfälle zuordnen. Ist so etwas möglich?

@Service 
@PropertySource(value = "classpath:my_service.properties") 
public class SomeServiceImpl implements SomeService { 


    @Value("#{conf['service.cache']}") 
    private final boolean useCache = false; 

    @Value("#{conf['service.expiration.[<custom name>]']}") 
    private final HashMap<String, String> expirations = new HashMap<String, String>(); 

Property-Datei: 'my_service.properties'

service.cache=true 
service.expiration.name1=100 
service.expiration.name2=20 

Ist es posible wie dieser Schlüssel zur Karte: Wert

gesetzt
  • name1 = 100

  • name2 = 20

+0

neue und Spring Bohnenfabrik sind orthogonal. new bedeutet "no Spring" – duffymo

+0

@duffymo kann nicht so verallgemeinert werden. new Entity, das neue ValueObject fällt nicht darunter – madhairsilence

Antwort

13

Ich mache eine Lösung inspiriert durch den vorherigen Beitrag.

Register Eigenschaftendatei in der Spring-Konfiguration:

<util:properties id="myProp" location="classpath:my.properties"/> 

Und ich schaffen Komponente:

@Component("PropertyMapper") 
public class PropertyMapper { 

    @Autowired 
    ApplicationContext applicationContext; 

    public HashMap<String, Object> startWith(String qualifier, String startWith) { 
     return startWith(qualifier, startWith, false); 
    } 

    public HashMap<String, Object> startWith(String qualifier, String startWith, boolean removeStartWith) { 
     HashMap<String, Object> result = new HashMap<String, Object>(); 

     Object obj = applicationContext.getBean(qualifier); 
     if (obj instanceof Properties) { 
      Properties mobileProperties = (Properties)obj; 

      if (mobileProperties != null) { 
       for (Entry<Object, Object> e : mobileProperties.entrySet()) { 
        Object oKey = e.getKey(); 
        if (oKey instanceof String) { 
         String key = (String)oKey; 
         if (((String) oKey).startsWith(startWith)) { 
          if (removeStartWith) 
           key = key.substring(startWith.length()); 
          result.put(key, e.getValue()); 
         } 
        } 
       } 
      } 
     } 

     return result; 
    } 
} 

Und wenn ich will alle Eigenschaften abzubilden, die mit SpeciFix Wert HashMap beginnen, mit @Value Anmerkung:

@Service 
public class MyServiceImpl implements MyService { 

    @Value("#{PropertyMapper.startWith('myProp', 'service.expiration.', true)}") 
    private HashMap<String, Object> portalExpirations; 
17

Kann Spring @ Value verwendet werden, um Werte von der Eigenschaftendatei zur HashMap zuzuordnen?

Ja, ist es. Mit ein wenig Hilfe von Code und Spel.

Erstens betrachten diese Singleton Frühling-Bohne (Sie sollten es scannen):

@Component("PropertySplitter") 
public class PropertySplitter { 

    /** 
    * Example: one.example.property = KEY1:VALUE1,KEY2:VALUE2 
    */ 
    public Map<String, String> map(String property) { 
     return this.map(property, ","); 
    } 

    /** 
    * Example: one.example.property = KEY1:VALUE1.1,VALUE1.2;KEY2:VALUE2.1,VALUE2.2 
    */ 
    public Map<String, List<String>> mapOfList(String property) { 
     Map<String, String> map = this.map(property, ";"); 

     Map<String, List<String>> mapOfList = new HashMap<>(); 
     for (Entry<String, String> entry : map.entrySet()) { 
      mapOfList.put(entry.getKey(), this.list(entry.getValue())); 
     } 

     return mapOfList; 
    } 

    /** 
    * Example: one.example.property = VALUE1,VALUE2,VALUE3,VALUE4 
    */ 
    public List<String> list(String property) { 
     return this.list(property, ","); 
    } 

    /** 
    * Example: one.example.property = VALUE1.1,VALUE1.2;VALUE2.1,VALUE2.2 
    */ 
    public List<List<String>> groupedList(String property) { 
     List<String> unGroupedList = this.list(property, ";"); 

     List<List<String>> groupedList = new ArrayList<>(); 
     for (String group : unGroupedList) { 
      groupedList.add(this.list(group)); 
     } 

     return groupedList; 

    } 

    private List<String> list(String property, String splitter) { 
     return Splitter.on(splitter).omitEmptyStrings().trimResults().splitToList(property); 
    } 

    private Map<String, String> map(String property, String splitter) { 
     return Splitter.on(splitter).omitEmptyStrings().trimResults().withKeyValueSeparator(":").split(property); 
    } 

} 

Hinweis:PropertySplitter Klasse verwendet Splitter Dienstprogramm von Guava. Weitere Informationen finden Sie unter its documentation.

Dann in einiger Bohne von Ihnen:

@Component 
public class MyBean { 

    @Value("#{PropertySplitter.map('${service.expiration}')}") 
    Map<String, String> propertyAsMap; 

} 

Und schließlich die Eigenschaft:

service.expiration = name1:100,name2:20 

Es ist nicht genau das, was Sie gefragt haben, weil diese PropertySplitter Arbeiten mit einer einzigen Eigenschaft, dass ist umgewandelt in eine Map, aber ich denke, Sie könnten entweder auf diese Weise der Angabe von Eigenschaften wechseln, oder ändern Sie die PropertySplitter-Code, so dass es die hierarchischere Weise entspricht Verlangen.

3

Der schnellste Frühling Boot basierte Lösung kann ich mir vorstellen, folgt.In meinem speziellen Beispiel migriere ich Daten von einem System zu einem anderen. Deshalb benötige ich ein Mapping für ein Feld Priorität.

my.prefix.priority.0:0 
my.prefix.priority.10:1 
my.prefix.priority.15:2 
my.prefix.priority.20:2 
another.prefix.foo:bar 

und es auf dem Classpath setzen:

Zuerst habe ich die Eigenschaften Datei (priority-migration.properties) wie solche geschaffen.

Vorausgesetzt, dass Sie die Karte in einer Feder Managed Bean/Komponente, mit Anmerkungen versehen Sie Ihre Klasse mit verwenden möchten:

@Component 
@PropertySource("classpath:/priority-migration.properties") 

Was Sie wollen, tatsächlich in der Karte ist natürlich nur die Schlüssel/Wert-Paare, die Präfix mit my.prefix, also diesen Teil:

{ 
    0:0 
    10:1 
    15:2 
    20:2 
} 

um das zu erreichen, dass Sie Ihre Komponente mit Anmerkungen versehen müssen mit

@ConfigurationProperties("my.prefix") 

und erstellen Sie einen Getter für die Priorität Infix. Letztere in meinem Fall sein zwingend erwiesen (obwohl die Sring Doc sagt, ist es genug, um eine Eigenschaft Priorität zu haben und initialisieren es mit einem wandelbaren Wert)

private final Map<Integer, Integer> priorityMap = new HashMap<>(); 

public Map<Integer, Integer> getPriority() { 
    return priorityMap; 
} 

In the End

Es sieht in etwa so aus:

@Component 
@ConfigurationProperties("my.prefix") 
@PropertySource("classpath:/priority-migration.properties") 
class PriorityProcessor { 

    private final Map<Integer, Integer> priorityMap = new HashMap<>(); 

    public Map<Integer, Integer> getPriority() { 
     return priorityMap; 
    } 

    public void process() { 

     Integer myPriority = priorityMap.get(10) 
     // use it here 
    } 
} 
+0

'@ ConfigurationProperties' ist eine Spring-Boot-Annotation, keine Spring-Annotation –