Java的类型安全配置读/写库?

时间:2011-05-14 23:00:32

标签: java configuration

是否有一个很好的Java配置库,它允许我以类型安全的方式读取设置?例如,通过我的精心设计的IConfiguration接口声明getter和setter,并允许我通过它读/写配置。

使用properties.getProperty("group.setting")读取设置然后将其转换为所需类型有点无聊。 Apache commons配置允许使用config.getDouble("number")之类的东西,但这里的“number”再次是一个字符串,我希望能够做double value = config.GetNumber()之类的事情。

7 个答案:

答案 0 :(得分:8)

OWNER库可以满足您的需求。

答案 1 :(得分:4)

我认为typesafe的配置库是您可能需要的。这是link

这是一个类型安全的库。以下是如何使用此库的示例:

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文件。它代表"人类优化的配置对象表示法"并且是JSON的超集:

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

它具有许多功能,使其更具可读性。与省略特殊字符(,:{})一样。而最酷的事情就是继承:

standard-timeout = 10ms
foo.timeout = ${standard-timeout}
bar.timeout = ${standard-timeout}

如果您复制带有对象值的字段,则对象将与last-one-wins合并。所以:

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

表示与:

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

请查看该项目的自述文件,以了解有关此出色配置库的更多信息https://github.com/typesafehub/config

答案 2 :(得分:3)

您可以使用XSD定义XML配置文件,然后使用XJC生成JAXB源代码。每个XSD类型都映射到一个Java类,您可以轻松地编组/解组

一个例子。 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/

答案 3 :(得分:2)

如果您有配置界面,例如:

public interface IConfig {
  int getNumber();
  void setNumber(int number);

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

然后您可以使用Proxy将方法映射到属性:

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对象在他们可以描述的配置方面相当有限。

答案 4 :(得分:2)

我的Config4J库(已成熟且记录完备,但未广为人知)提供了您想要的大部分内容。

特别是,Config4J为内置类型提供了类型安全的“查找”(即“get”)操作,例如string,boolean,int,float和durations(例如"500 milliseconds"或{ {1}})。持续时间字符串会自动转换为表示(您选择的)毫秒或秒的整数值。

该库还提供了构建块,因此您可以对"2.5 days"形式的字符串执行类型安全查找(例如,"<float> <units>""2 cm"距离)或{{1} (例如,"10.5 meters""<units> <float>"为了钱)。

该库还提供了一个简单易用的模式验证器(如果您感兴趣的话)。

Config4J无法满足您声明的要求的方式是库的“插入”(即“put”)功能仅在字符串方面有效。因此,您必须将int / boolean / float / int-denoting-duration / whatever值转换为字符串,然后将其“插入”到Config4J对象中。但是,这种到字符串的转换通常不是一项繁重的任务。

在将一些 name = value 对插入Config4J对象后,您可以调用"$0.99"将整个对象序列化为一个字符串,然后您可以将其写回配置文件。

阅读“入门指南”(PDFHTML)的第2章和第3章,应该为您提供一个足够好的Config4J概述,以确定它是否符合您的需求。您可能还想查看源代码下载(compressed tarzip)中提供的“简单封装”演示。

答案 5 :(得分:0)

我不这么认为,因为java不是动态语言。这是可以实现的唯一方法是,如果您有一个代码生成器,它将获取您的属性文件并生成配置类。或者,如果您为每个属性手动添加一个getter。

我认为

commons-configuration是最好的方法。

答案 6 :(得分:0)

通过使用XStream序列化配置类,您应该能够获得一些牵引力。但缺点是:

  • 配置文件不是标准属性文件格式之一。它将是任意的XML。
  • 序列化格式将是脆弱的。对配置类的微小更改可能会使旧配置文件无法读取。

从好的方面来看,基于任意XML的格式可以表示结构比标准属性文件格式更好的配置项。