Типобезопасная конфигурация библиотеки чтения / записи для Java? - PullRequest
9 голосов
/ 15 мая 2011

Есть ли хорошая библиотека конфигурации для Java, которая позволит мне читать настройки безопасным для типов способом?Например, взяв мой созданный интерфейс IConfiguration с объявленными получателями и установщиками и позволив мне читать / записывать конфигурацию через него.

Немного скучно читать настройки, используя properties.getProperty("group.setting"), а затем приводить их к нужному типу.Конфигурация Apache commons позволяет использовать что-то вроде config.getDouble("number"), но «число» снова представляет собой строку, и я хотел бы иметь возможность сделать что-то вроде double value = config.GetNumber().

Ответы [ 7 ]

8 голосов
/ 28 июня 2013

ВЛАДЕЛЕЦ библиотека делает то, что вы хотите.

4 голосов
/ 16 июля 2014

Я думаю, что вам может понадобиться библиотека настроек 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. Он обозначает «Оптимизированная для человека нотация объекта конфигурации» и является расширенным набором 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 } 

Пожалуйста, посмотрите файл readme проекта, чтобы узнать больше об этой замечательной библиотеке конфигурации https://github.com/typesafehub/config

3 голосов
/ 20 мая 2011

Вы можете определить файл конфигурации XML с помощью XSD, а затем создать исходный код JAXB с помощью XJC. Каждый тип 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/

2 голосов
/ 17 мая 2011

Моя Config4J библиотека (которая является зрелой и хорошо документированной, но не широко известной) предоставляет большую часть того, что вы хотите.

В частности, Config4J обеспечивает безопасный поиск по типу (то есть операции «get») для встроенных типов, таких как string, boolean, int, float и duration (например, "500 milliseconds" или "2.5 days").Строка длительности автоматически преобразуется в целочисленное значение, обозначающее (на ваш выбор) миллисекунды или секунды.

Библиотека также предоставляет строительные блоки, поэтому вы можете выполнять поиск по типу для строк типа "<float> <units>" (дляНапример, "2 cm" и "10.5 meters" для расстояний) или "<units> <float>" (например, "$0.99" или "£10.00" для денег).

В библиотеке также есть тривиальный валидатор схемы (в случае, если вас это интересует).

Способ, которым Config4J не удовлетворяет вашим заявленным требованиям, заключается в том, что функциональность библиотеки «вставлять» (то есть «ставить») работает только в терминах строк.Таким образом, вам придется преобразовать значение типа int / boolean / float / int-denoting-duration / в любое другое значение в строку, а затем «вставить» это значение в объект Config4J.Однако это преобразование в строку обычно не является обременительной задачей.

После вставки некоторых пар имя = значение в объект Config4J вы можете затем вызвать dump() для сериализации всегоОбъект в строку, которую можно затем записать обратно в файл конфигурации.

Чтение глав 2 и 3 «Руководства по началу работы» ( PDF , HTML )должен дать вам достаточно хороший обзор Config4J, чтобы решить, соответствует ли он вашим потребностям.Возможно, вы также захотите взглянуть на демонстрацию "simple-encapsulation", которая поставляется в загрузке исходного кода ( сжатый tar , zip ).

2 голосов
/ 15 мая 2011

Если у вас есть интерфейс конфигурации, такой как:

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 (в зависимости от того, вызвали ли вы метод получения или установки).

Обратите внимание, что эта реализация явно небезопасна , поскольку:

  • значения, уже находящиеся в объекте Properties, не проверяются до тех пор, пока не будет вызван метод получения
  • сеттер и геттер не должны принимать / возвращать один и тот же тип

Мне неизвестна существующая библиотека для этого, возможно, потому что объекты Properties довольно ограничены с точки зрения конфигурации, которую они могут описать.

0 голосов
/ 15 мая 2011

Вы должны быть в состоянии получить некоторую тягу, используя XStream для сериализации класса конфигурации.Но есть и недостатки:

  • Файл конфигурации не будет в одном из стандартных форматов файла свойств.Вместо этого это будет произвольный XML.
  • Формат сериализации будет хрупким.Незначительные изменения в классе конфигурации могут сделать старые файлы конфигурации нечитаемыми.

С другой стороны, формат, основанный на произвольном XML, может представлять элементы конфигурации, структура которых намного лучше, чем стандартные форматы файлов свойств.

0 голосов
/ 15 мая 2011

Я так не думаю, потому что Java не динамический язык. Это возможно только в том случае, если у вас есть генератор кода, который получит ваш файл свойств и сгенерирует класс конфигурации. Или если вы вручную добавляете геттер для каждого свойства.

конфигурация commons - лучший путь, я думаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...