2015-02-06 87 views
22

E 'possibile utilizzare Spring @ Value, per mappare i valori dal file delle proprietà a HashMap.Come compilare HashMap dal file di proprietà java con Spring @Value

Attualmente ho qualcosa del genere e mappare un valore non è un problema. Ma ho bisogno di mappare i valori personalizzati nelle scadenze di HashMap. È possibile qualcosa del genere?

@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>(); 

file di proprietà: '' my_service.properties

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

È posible per mappare come questa chiave: il valore impostato

  • nome1 = 100

  • nome2 = 20

+0

nuovo e Spring fabbrica di fagioli sono ortogonali. nuovi mezzi "no Spring" – duffymo

+0

@duffymo non può essere generalizzato in questo modo. nuova Entità, nuovo ValueObject non rientra in questo – madhairsilence

risposta

13

Faccio una soluzione ispirata al post precedente.

file di proprietà Register nella configurazione di primavera:

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

E creo componente:

@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; 
    } 
} 

E quando voglio mappare tutte le proprietà che iniziano con il valore SPECIFIX a HashMap, con @Value annotazione:

@Service 
public class MyServiceImpl implements MyService { 

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

È possibile utilizzare Spring @Value per mappare i valori dal file delle proprietà a HashMap?

Sì, lo è. Con un piccolo aiuto di codice e Spel.

In primo luogo, considerare questa primavera-bean Singleton (si dovrebbe eseguire la scansione):

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

} 

Nota:PropertySplitter classe utilizza Splitter utilità dal Guava. Si prega di fare riferimento a its documentation per ulteriori dettagli.

Poi, in qualche chicco di tuo:

@Component 
public class MyBean { 

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

} 

E, infine, la proprietà:

service.expiration = name1:100,name2:20 

Non è esattamente quello che hai chiesto, perché questa PropertySplitter opere con una sola proprietà che è trasformato in un Map, ma penso che sia possibile passare a questo modo di specificare le proprietà o modificare il codice PropertySplitter in modo che corrisponda al modo più gerarchico di desiderio.

3

Il più veloce Primavera Boot La soluzione basata su a cui posso pensare segue.Nel mio particolare esempio sto migrando i dati da un sistema all'altro. Ecco perché ho bisogno di una mappatura per un campo chiamato priorità.

Prima ho creato il file di proprietà (priority-migration.properties) come ad esempio:

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

e lo misi nel classpath.

Supponendo che si desidera utilizzare la mappa in una molla gestito fagiolo/component, annotare la classe con:

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

Quello che effettivamente volete nella vostra mappa è ovviamente solo le coppie chiave/valore, che sono preceduti con my.prefix, cioè questa parte:

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

per raggiungere questo è necessario annotare il componente con

@ConfigurationProperties("my.prefix") 

e creare un getter per la priorità priorità. Quest'ultima si è rivelata obbligatoria nel mio caso (anche se il Sring Doc dice che è sufficiente avere una proprietà priorità e inizializzare con un valore mutevole)

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

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

Nel finale

Assomiglia a questo:

@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' è un'annotazione Spring Boot, non un'annotazione Spring –