Статьи

Типизированные свойства в Java

мотивация

В типичных Java-приложениях, особенно в веб-приложениях, у вас будут некоторые свойства.
Часто у вас будет несколько файлов свойств для разных сред.

Часто есть много кода котельной плиты, чтобы пойти с этим. 

Пример:

//Often with problems with paths etc.
Properties properties = ClassLoader.getResource("app.properties");
int myint = 0;
try {
	myint = Integer.parseInt(properties.getProperty("myint"));
	if ((myint<22) && (myint>658)) {
		//should I use default value?
		//should I throw exception ?
		//throw new IllegalArgumentException("myint property is outside valid range [23-657]");
	}
} catch (NumberFormatException e) {
	//Should we use default?
	//Should we just log the error?
	//Should we close application because of invalid property?
} catch (IllegalArgumentException e) {
	//Should we use default?
	//Should we just log the error?	
	//Should we close application because of invalid property?
}

цели


Мы хотим :

  • Иметь четкое однострочное определение свойства.
  • Загрузите Свойство как тип, который он был предназначен.
  • Есть простой способ инициализировать коллекцию свойств.

Решение


Использование
JHPropertiesTyped (
Link
)
определяется 3 шагами:
  • Определите ваши свойства, с именем, типом, ограничениями, описанием — типично для интерфейса.
  • Определите свою коллекцию свойств, используя уже определенные свойства.
  • Определите свой PropertyIO.
    • Это может включать PropertyValidationHandler для недопустимых свойств.
    • Это может включать до и после установки.

Определение будет выглядеть так:

public interface MyPropertiesDef {
	public static final Property<Integer> MYINT = new Property<Integer>("myint",new IntegerPropertyType(23,657));
	public static final Property<Locale> MYLOCALE = new Property<Locale>("mylocale", new LocalePropertyType());
	public static final Property<MyColors> MYCOLORS = new Property<MyColors>("mycolor",new EnumPropertyType(MyColors.class));
}

Класс будет выглядеть так:

public class MyProperties extends PropertyStaticCollection implements MyPropertiesDef {

	private static MyProperties instance=null;
	
	public MyProperties() {
		//Per default a collection has a "new LoggingPropertyValidationHandler(false)" instance.
		super(new ResourceFilePropertyIO("app.properties"),new LoggingPropertyValidationHandler(true));
	}
	
	public MyProperties getInstance() {
		//Call this method at startup to initialize the properties
		if (instance==null) {
			instance = new MyProperties();
		}
		return instance;
	}
	@Override
	public void preValidation() {
	}
	@Override
	public void postValidation() throws PropertyException {
	}	
}

«PropertyValidationHandler» выполняет действие, когда одно или несколько свойств недопустимы. Это может быть регистрация сообщения, отправка сообщения, остановка приложения. Это легко реализовать свой собственный PropertyValidationHandler.

В коллекции есть два метода, которые вы можете переопределить. 

  • preValidation: обычно для установки глобальных параметров, если это необходимо.
  • postValidation: обычно для проверки зависимостей свойств используется класс ActivationValidator. Пример: некоторые свойства должны быть четко определены, если определенное свойство определено правильно.

Свойство определяется как:
  • Свойство <Type> NAME = Свойство <Type> (имя строки, тип PropertyType <тип>, логическое значение nullAllowed, логическое значение только для чтения, описание строки);
    • nullAllowed : необязательно; по умолчанию ложь .
    • только для чтения : необязательно; по умолчанию ложь .
    • описание : необязательно; по умолчанию ноль .

Доступ к данным


Как только коллекция инициализирована, вы можете получить доступ к значениям.
Вы знаете, что они действительны, в противном случае PropertyValidationHandler должен был позаботиться об этом. В любом случае, если есть свойство, которое не является допустимым,
nullвозвращается, так что вы скоро узнаете. Но есть быстрый способ настроить модульный тест, который будет проверять все ваши различные свойства среды. (Подробнее читайте ниже) 

Integer v1 = MyPropertiesDef.MYINT.getTypedValue();
Locale v2 = MyPropertiesDef.MYLOCALE.getTypedValue();
MyColors v3 = MyPropertiesDef.MYCOLORS.getTypedValue();

Вы также можете установить значение, используя введенное значение или строковый эквивалент. Значение НЕ будет установлено, если PropertyType считает его недействительным. 

MyPropertiesDef.MYINT.setTypedValue(437);
MyPropertiesDef.MYINT.setValue("437");

Вы можете получить доступ к методам в коллекции. 

//For reloading
MyProperties.getInstance().getIo().reload();

//For getting backup
MyProperties.getInstance().getIo().backup();

//Getting property validation list
List<PropertyValidationDTO> list = MyProperties.getInstance().validation();

//Last saved
Date lastSaved = MyProperties.getInstance().getIo().getLastSaved();

Доступные типы

В настоящее время существует 39 различных типов собственности: 

  • BooleanPropertyType
  • ByteSizePropertyType
  • CharsetPropertyType
  • ClassnamePropertyType
  • ColorPropertyType
  • DateFormatPropertyType
  • DateTimePropertyType
  • DecimalFormatPropertyType
  • DirectoryPropertyType
  • DoublePropertyType
  • EmailPropertyType
  • EnumPropertyType
  • EnvironmentPropertyType
  • FilenameFilterPropertyType
  • FilePropertyType
  • FileStructurePropertyType
  • HourIntervalsPropertyType
  • InetAddressPropertyType
  • IntegerPropertyType
  • IP4AddressPropertyType
  • LdapNamePropertyType
  • ListKeyValuePropertyType
  • ListPropertyType
  • LocalePropertyType
  • LongPropertyType
  • MonthPropertyType
  • PasswordPropertyType — в настоящее время с методами AES, MD5 или SHA512.
  • RegularExpressionPropertyType
  • SequencePropertyType
  • StringPropertiesPropertyType
  • StringPropertyType
  • TimeUnitPropertyType
  • TimeZonePropertyType
  • URIPropertyType
  • URLPropertyType
  • VersionPropertyType
  • WeekdayPropertyType

В настоящее время существует 16 различных PropertyIO: 

  • AbstractPropertyIO
  • AbstractJDBCPropertyIO
  • AbstractXMLFilePropertyIO
  • AbstractXMLInputStreamPropertyIO
  • DatasourceJDBCPropertyIO
  • FilePropertyIO
  • InputStreamPropertyIO
  • JBossSystemPropertiesPropertyIO
  • MemoryPropertyIO
  • ResourceFilePropertyIO
  • ServletContextPropertyIO
  • UrlJDBCPropertyIO
  • WebContextParamsPropertyIO
  • CompositePropertyIO

Это легко сделать свой собственный PropertyType и PropertyIO.
Это легко проверить все ваши различные свойства среды. (Подробнее читайте ниже)

Модульное тестирование

Скорее всего, у вас есть одно или несколько свойств для разных сред. Чтобы проверить их все:

public class EnvironmentPropertyDataTest {	
	@Test
	public void testAllEnvironmentProperties() {
	
		PropertyFrameworkGlobals.setAutoEncryptPasswords(false);
		PropertyFrameworkGlobals.setValidateIPathPropertyTypes(false);
		
		File[] files = FilePropertyIOFactory.findPropertyFiles(new File("/config/environments"),"myapp.properties");		
		for (File file : files) {			
			MockTestCollection collection = new MockTestCollection(file);
			try {
				collection.validate();
			} catch (PropertyException e) {				
				fail("Property file ["+file.getAbsolutePath()+"] failed with message:"+e.getMessage());				
			}			
		}			
	}
	
	@After
	public void after() {
		PropertyFrameworkGlobals.resetGlobalSettings();
	}
	
	class MockTestCollection extends PropertyStaticCollection implements MyPropertiesDef {
		public MockTestCollection(File file) {
			super(new FilePropertyIO(file));
		}		
	}
}

Генерация определений

Вы можете легко создавать определения для ваших существующих свойств. Есть два способа: 

  • Использование основного класса в PropertiesJavaDefinitionPrinter.
  • Разверните «JHPropertiesTypedWebDemo» и перейдите на страницу создания.

Пример генерации, где ввод:

my.email=email@email.com
my.int=123445
my.color=RED
my.list=PI;E;COS;SIN

В результате чего:

//Value=[RED] - Suggesting type Color.
public final static Property<Color> MY_COLOR = new Property<Color>("my.color",new ColorPropertyType());

//Value=[email@email.com] - Suggesting type String.
public final static Property<String> MY_EMAIL = new Property<String>("my.email",new EmailPropertyType());

//Value=[123445] - Suggesting type Integer.
public final static Property<Integer> MY_INT = new Property<Integer>("my.int",new IntegerPropertyType());

//Value=[PI;E;COS;SIN] - Suggesting type List of String.
public final static Property<List<String>> MY_LIST = new Property<List<String>>("my.list",new ListPropertyType<String>(new StringPropertyType(),";"));

Библиотеки

В настоящее время я выпустил 3 библиотеки в версии 1.5:

  • JHPropertiesTyped- <версия> .jar
    • Основной каркас размером около 200 кб.
    • Единственная зависимость — это Java JDK 1.6, протоколирование Apache Commons и API Java Servlet (если вы используете классы, зависящие от этого API)
  • JHPropertiesTypedWeb- <версия> .jar
    • Рендереры для всех ProepertyTypes, абстрактная версия.
    • Зависимости — это Java JDK 1.6, ведение журнала Apache Commons и API сервлетов Java 
  • JHPropertiesTypedWebDemo- <версия> .war
    • Демонстрация всех PropertyTypes, только для чтения и записи, страница генерации.
    • Зависимости — это Java JDK 1.6, ведение журнала Apache Commons и API сервлетов Java 

В конвейере есть четвертая библиотека, в которой нет ограничений на зависимости.
Но это еще не выпущено; это зависит от отзывов пользователей.

Веб-включение

Библиотека JHPropertiesTypedWeb- <версия> .jar представляет собой реализацию средства визуализации всех типов PropertyTypes, как для реализации только для чтения, так и для записи. Это очень легко интегрировать в собственное веб-приложение. Вам нужно всего лишь написать 3 тега таблицы стилей и предоставить две картинки.

Заключительные комментарии и ссылки

Фреймворк имеет полный Javadoc и обширную документацию. В настоящее время охват тестами составляет около 75%. Вы можете найти рамки здесь:

Полное раскрытие

Я разработчик JHPropertiesTyped. Я пишу эту статью, потому что я горжусь своей работой и думаю, что многие найдут это полезным. Программное обеспечение с открытым исходным кодом и бесплатно по лицензии LGPLv3.