Описание проблемы
Пусть у нас есть некоторый класс X, параметризующийся из контейнера свойств PX и есть класс Y, расширяющий X, параметризующийся контейнером PY, расширяющим PX.
Если контейнерами свойств выступают аннотации, то мы имеем два класса:
@PX(propertyX1 = <valueX1>, ..., propertyXN = <valueXN>)
class X {
...
}
И есть класс:
@PY(propertyY1 = <valueY1>, ..., propertyYN = <valueYN>)
class Y extends X {
...
}
Java (в том числе и Java 8) не предоставляют возможность наследования аннотаций, поэтому написать что-то вроде примера ниже нельзя:
public @interface PX extends PY {
}
Разумеется, это не проблема, вот решение:
@PX
class X {
protected final ... propertyX1;
...
protected final ... propertyY1;
X() {
final PX px = getClass().getAnnotation(PX.class);
propertyX1 = px.propertyX1();
...
propertyXN = px.propertyXN();
}
}
@PY
class Y extends X {
Y() {
final PY py = getClass().getAnnotation(PY.class);
propertyY1 = px.propertyY1();
...
propertyYN = px.propertyYN();
}
}
В чем здесь недостаток? Недостаток в том, что мы обрекаем себя на то, что если у класса не будет аннотаций, то он будет сконфигурирован дефолтными значениями (аннотации PX и PY должны быть @Inherited для этого).
Как быть, если нам, к примеру, надо инжектировать проперти из файла .properties или взять их из какого-либо другого источника, например из спрингового Environment?
Если не прибегать к изощренным трюкам типа создания аннотированных классов «на лету» с подстановкой параметров аннотаций, то ничего.
Читать полностью »