【问题标题】:Creating objects with Guava from property files使用 Guava 从属性文件创建对象
【发布时间】:2011-11-21 10:00:15
【问题描述】:

在我们的应用程序中,我们经常使用属性文件。几个月以来,我开始学习番石榴,实际上我非常喜欢它。

创建Map<String, Datasource> 的最佳方法是什么?

属性文件格式不严格。如果可以用另一种格式更好地表达,可以改变吗?

示例属性文件:

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

【问题讨论】:

    标签: java collections properties guava


    【解决方案1】:

    最简单的可能是为此使用 JSON 而不是属性文件:

    { “数据源”: [ { “名称”:“数据源1”, "url": "jdbc:mysql://192.168.11.46/db1", “用户”:“根”, “密码”:“密码” }, { “名称”:“数据源2”, "url": "jdbc:mysql://192.168.11.46/db2", “用户”:“根”, “密码”:“密码” } ] }

    然后您可以使用诸如Gson 之类的库将其转换为对象:

    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
    }
    

    然后获取地图:

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

    【讨论】:

    • 我投了赞成票,因为这个想法和优雅的解决方案,而且我可能会使用您建议的解决方案,但为了适合问题的答案,我选择了另一个。 :) 顺便说一句,科林,我也是你的忠实粉丝。 :) 感谢您的贡献。但是,我也希望看到您的另一个出色的实现,以便更好地学习。 ;)
    • @Sessizlik 我想我的意思是使用正确的工具来完成这项工作。你这里有一些你想读入的结构化数据。属性文件是扁平的,不能很好地表达结构。番石榴并没有改变这个事实。 Gson(顺便说一下,Google 的 JSON 转换库)似乎更合适,它使这变得非常容易。
    【解决方案2】:

    Properties 类是 HashTable 的子类,HashTable 又实现了 Map。

    你像往常一样加载它:

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

    编辑:好的,所以您想将其转换为 Map ;)

    //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);
    

    可能有一种更简单的方法,但这应该可行:)

    你还是用 json 或 xml 更好。您还可以从不同的文件加载不同数据源的属性。

    edit2:少用番石榴,多用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(....)
    }
    

    【讨论】:

    • 我知道这一点,但在此之后你建议创建 Map
    • 您可以在我的解决方案中保存几行。我留下了它们,所以它更具可读性。
    • 我投了赞成票 :) 但我想再等一会儿。谢谢:)顺便说一下,对于第一次不清楚的问题感到抱歉。 Stackoverflow 忽略了它:)
    • 没问题。我添加了更清洁的解决方案。
    • 您应该关闭用于加载属性的FileInputStream
    【解决方案3】:

    如果您用于配置的文件不严格,您可以使用 XML 文件来存储定义。

    示例定义:

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

    使用连接管理器类,您可以只读取 XML 以获取连接信息并创建连接实例并管理它们。

    【讨论】:

      猜你喜欢
      • 2022-01-17
      • 1970-01-01
      • 2017-08-11
      • 2012-03-13
      • 2016-06-14
      • 2018-12-19
      • 1970-01-01
      • 2014-07-10
      • 2014-03-01
      相关资源
      最近更新 更多