2011-11-21 15 views
6

Nelle nostre applicazioni utilizziamo molto i file di proprietà. Da alcuni mesi ho iniziato a imparare Guava e mi è piaciuto molto.Creazione di oggetti con Guava da file di proprietà

Qual è il modo migliore per creare uno Map<String, Datasource>?

Il formato del file di proprietà non è rigido. Può essere cambiato se può essere espresso meglio con un altro formato?

Esempio file di proprietà:

datasource1.url=jdbc:mysql://192.168.11.46/db1 
datasource1.password=password 
datasource1.user=root 
datasource2.url=jdbc:mysql://192.168.11.45/db2 
datasource2.password=password 
datasource2.user=root 

risposta

5

proprietà di classe è una sottoclasse di HashTable, che a sua volta implementa Map.

si carica come al solito con:

Properties properties = new Properties(); 
    try { 
     properties.load(new FileInputStream("filename.properties")); 
    } catch (IOException e) { 
} 

Edit: Ok così si vuole trasformarlo alla mappa < String, Origine dati >;)

//First convert properties to Map<String, String> 
Map<String, String> m = Maps.fromProperties(properties); 

//Sort them so that password < url < user for each datasource and dataSource1.* < dataSource2.*. In your case default string ordering is ok so we can take a normal treemap 
Map<String, String> sorted = Maps.newTreeMap(); 
sorted.putAll(m); 

//Create Multimap<String, List<String>> mapping datasourcename->[password,url, user ] 

    Function<Map.Entry<String, String>, String> propToList = new Function<String, Integer>() { 
     @Override 
     public String apply(Map.Entry<String, String> entry) { 
      return entry.getKey().split("\\.")[0]; 
     } 
    }; 

Multimap<Integer, String> nameToParamMap = Multimaps.index(m.entrySet(), propToList); 

//Convert it to map 
Map<String, Collection<String>> mm = nameToParamMap.asMap(); 

//Transform it to Map<String, Datasource> 
Map<String, Datasource> mSD = Maps.transformEntries(mm, new EntryTransformer<String, Collection<String>, DataSource>() { 
     public DataSource transformEntry(String key, Collection<String> value) { 
      // Create your datasource. You know by now that Collection<String> is actually a list so you can assume elements are in order: [password, url, user] 
      return new Datasource(.....) 
     } 
     }; 

//Copy transformed map so it's no longer a view 
Map<String, Datasource> finalMap = Maps.newHashMap(mSD); 

C'è probabilmente un modo più semplice, ma questo dovrebbe funzionare :)

Ancora stai meglio con json o xml. È inoltre possibile caricare proprietà di origini dati diverse da file diversi.

EDIT2: con meno guava, più Java:

//Sort them so that password < url < user for each datasource and dataSource1.* < dataSource2.*. In your case default string ordering is ok so we can take a normal SortedSet 
SortedSet <String> sorted = new SortedSet<String>(); 
sorted.putAll(m.keySet); 

//Divide keys into lists of 3 
Iterable<List<String>> keyLists = Iterables.partition(sorted.keySet(), 3); 


Map<String, Datasource> m = new HashMap<String, Datasource>(); 
for (keyList : keyLists) { 
    //Contains datasourcex.password, datasroucex.url, datasourcex.user 
    String[] params = keyList.toArray(new String[keyList.size()]); 
    String password = properties.get(params[0]); 
    String url = properties.get(params[1]); 
    String user = properties.get(params[2]); 
    m.put(params[0].split("\\.")[0], new DataSource(....) 
} 
+0

Sono consapevole di questo, ma dopo ciò che stai suggerendo di creare Map Cemo

+0

puoi salvare un paio di linee nella mia soluzione. Li ho lasciati quindi è più leggibile. – soulcheck

+0

Ho votato :) Ma mi piacerebbe aspettare ancora un po '. Grazie :) Tra l'altro mi dispiace per la domanda poco chiara alla prima volta. Stackoverflow lo ha ignorato :) – Cemo

0

Se il file che si sta utilizzando per la configurazione non è rigoroso, è possibile utilizzare un file XML per archiviare il defintion.

definizione Esempio:

<resources> 
<configuration> 
    <datasrouce> 
    <connection name="" url="" password="" user=""/> 
    <connection name="" url="" password="" user=""/> 
    </datasource> 
</configuration> 
</resources> 

L'utilizzo di una classe Gestione connessioni si può solo leggere il codice XML per ottenere informazioni di connessione e creare un'istanza di connessioni e di rogna.

6

La cosa più semplice è probabilmente quello di usare JSON, piuttosto che un file di proprietà per questo:

{ 
    "datasources": [ 
    { 
     "name": "datasource1", 
     "url": "jdbc:mysql://192.168.11.46/db1", 
     "user": "root", 
     "password": "password" 
    }, 
    { 
     "name": "datasource2", 
     "url": "jdbc:mysql://192.168.11.46/db2", 
     "user": "root", 
     "password": "password" 
    } 
    ] 
}

allora si può solo usare una libreria come Gson convertire in oggetti:

public class DataSources { 
    private List<DataSourceInfo> dataSources; 

    public Map<String, DataSource> getDataSources() { 
    // create the map 
    } 
} 

public class DataSourceInfo { 
    private String name; 
    private String url; 
    private String user; 
    private String password; 

    // constructor, getters 
} 

Quindi per ottenere la mappa:

Gson gson = new Gson(); 
Map<String, DataSource> dataSources = gson.fromJson(/* file or stream here */, 
    DataSources.class).getDataSources(); 
+0

Ho votato per l'idea e la soluzione elegante e probabilmente userò la soluzione anche per quello che mi viene suggerito, ma per rispondere alla domanda ne scelgo un'altra. :) Tra l'altro Colin, anch'io sono un grande fan di te. :) Grazie per il tuo contributo. Tuttavia, vorrei anche vedere la tua altra meravigliosa implementazione per imparare meglio. ;) – Cemo

+0

@Sessizlik Credo che il mio punto qui sia utilizzare lo strumento giusto per il lavoro.Quello che hai qui sono alcuni dati strutturati che vuoi leggere. I file delle proprietà sono piatti e non esprimono bene la struttura. Guava non cambia questo fatto. Gson (la libreria di conversione JSON di Google, per inciso) sembra più appropriata e lo rende decisamente semplice. – ColinD

Problemi correlati