Java的类型安全配置读写库是什么?

9
有没有一个适用于Java的好的配置库,可以让我以类型安全的方式读取设置?例如,通过使用我编写的带有声明的 getter 和 setter 的 IConfiguration 接口,并允许我通过它来读取/写入配置。
使用 properties.getProperty("group.setting") 读取设置有点无聊,然后将其转换为所需的类型。Apache commons configuration 允许使用类似 config.getDouble("number") 的东西,但是 "number" 再次是一个字符串,我想能够像这样做些什么:double value = config.GetNumber()。
7个回答

8

OWNER库可以实现你想要的功能。


4
我认为typesafe的配置库可能是你需要的。这里是链接
它是一种类型安全的库。这里是如何使用该库的示例:
import com.typesafe.config.ConfigFactory

Config conf = ConfigFactory.load();
int bar1 = conf.getInt("foo.bar");
Config foo = conf.getConfig("foo");
int bar2 = foo.getInt("bar");

我推荐这个库的主要原因是它可以读取HOCON文件。HOCON代表“人类优化配置对象表示法”,是JSON的超集:

{
    "foo" : {
        "bar" : 10,
        "baz" : 12
    }
}

它有许多功能使其更易读。例如省略特殊字符(如,:{})。最酷的功能是继承:
standard-timeout = 10ms
foo.timeout = ${standard-timeout}
bar.timeout = ${standard-timeout}

如果您复制带有对象值的字段,则这些对象会合并,后一个将覆盖前一个。因此:
foo = { a : 42, c : 5 }
foo = { b : 43, c : 6 }

意思与以下内容相同:

foo = { a : 42, b : 43, c : 6 } 

请查看项目的自述文件以了解更多关于这个优秀配置库的信息:https://github.com/typesafehub/config

3
您可以使用XSD定义XML配置文件,然后使用XJC生成JAXB源代码。每个XSD类型都映射到一个Java类,您可以轻松地进行marshal/unmarshal操作。
例如,XSD:
<xsd:simpleType name="GroupType">
  <xsd:restriction base="xsd:int">
    <xsd:minInclusive value="1"/>
    <xsd:maxInclusive value="255"/>
  </xsd:restriction>
</xsd:simpleType>

生成的Java代码:

public class ElementType {
    @XmlAttribute(name = "Group", required = true)
    protected int group;

    public int getGroup() {
        return group;
    }
    public void setGroup(int value) {
        this.group = value;
    }
}

从教程中获取:

http://jaxb.java.net/tutorial/


2
我的Config4J库(这是成熟且有良好文档的库,但并不被广泛知晓)提供了您想要的大部分功能。
特别是,Config4J提供了针对内置类型(如字符串、布尔、整数、浮点数以及持续时间(例如“500毫秒”或“2.5天”)的类型安全的“查找”(即“获取”)操作。持续时间字符串会自动转换为表示(您选择的)毫秒或秒的整数值。
该库还提供了构建块,使您可以对形式为“<float> <units>”(例如距离的“2 cm”和“10.5 meters”)或“<units> <float>”(例如货币的“$0.99”或“£10.00”)的字符串执行类型安全的查找。
此外,该库还提供了一个易于使用的模式验证器(如果您感兴趣的话)。
Config4J无法满足您所述的要求的方式是该库的“插入”(即“放置”)功能仅以字符串形式工作。因此,您必须将int / boolean / float / int-denoting-duration /任何值转换为字符串,然后将其“插入”到Config4J对象中。但是,这种-to-string转换通常不是一项繁重的任务。
在向Config4J对象中插入一些name=value对之后,您可以调用dump()来将整个对象序列化为一个字符串,然后将其写回配置文件。
阅读《入门指南》的第2和第3章(PDFHTML)应该足以让您了解Config4J,从而决定它是否符合您的需求。您还可以查看源代码下载中提供的“simple-encapsulation”演示(压缩tar文件zip文件)。

谢谢,我会看看。顺便问一下,在这个网站上第一章在哪里?:) 我只看到第二到第四章。 - Vladislav Rastrusny

2
如果您有这样的配置界面:
public interface IConfig {
  int getNumber();
  void setNumber(int number);

  String getSomeProperty();
  void setSomeProperty(String someProperty);
}

接下来,您可以使用代理将方法映射到属性:

public class ConfigWrapper implements InvocationHandler {
  @SuppressWarnings(value="unchecked")
  public static <T> T wrap(Class c, Properties p) {
    return (T)Proxy.newProxyInstance(c.getClassLoader(), new Class[] {c},
        new ConfigWrapper(p));
  }

  private final Properties properties;

  private ConfigWrapper(Properties p) {
    this.properties = p;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) {
    if(method.getName().startsWith("get")) {
      if(method.getReturnType().equals(int.class)) {
        return Integer.parseInt(
            this.properties.getProperty(method.getName().substring(3)));
      } else if(method.getReturnType().equals(String.class)) {
        return this.properties.getProperty(method.getName().substring(3));
      } else {
        // obviously in a real application you'd want to handle more than just
        // String and int
        throw new RuntimeException(method.getName() + " returns unsupported type: "
            + method.getReturnType());
      }
    } else if(method.getName().startsWith("set")) {
      this.properties.setProperty(method.getName().substring(3),
          args[0].toString());
      return null;
    } else {
      throw new RuntimeException("Unknown method: " + method.getName());
    }
  }
}

使用方法:

Properties p = new Properties();

IConfig config = wrap(IConfig.class, p);

config.setNumber(50);
config.setSomeProperty("some value");
System.out.println(config.getNumber());
System.out.println(config.getSomeProperty());
System.out.println(p);

调用接口方法会导致调用ConfigWrapper.invoke(),该方法会更新或检索Properties对象(具体取决于您是否调用了getter或setter)。
请注意,此实现明显是不安全的,因为:
  • 在getter被调用之前,已经存在于Properties对象中的值不会被验证
  • setter和getter不必接受/返回相同的类型
我不知道是否有现成的库可以实现这个功能,可能是因为Properties对象在描述配置方面相对有限。

0

我认为不行,因为Java不是一种动态语言。唯一可行的方法是使用代码生成器获取您的属性文件并生成配置类。或者手动为每个属性添加一个getter。

我认为commons-configuration是最好的选择。


0

你可以使用XStream来序列化配置类,从而获得一些进展。但是缺点是:

  • 配置文件不会采用标准属性文件格式之一,而是任意XML格式。
  • 序列化格式很脆弱。对配置类进行微小更改可能会导致旧的配置文件无法读取。

好处是,基于任意XML的格式可以更好地表示具有结构的配置项,而标准属性文件格式则无法做到。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接