Общий метод производителя CDI не работает, как и ожидалось
Вопрос
У меня есть метод продюсера CDI, который - в зависимости от некоторых условий, не имеющих отношение к этому примеру - создает объекты разных типов:
public class TestProducer {
@Produces @TestQualifier
public Object create(InjectionPoint ip) {
if(something) {
return "a String";
} else {
return Integer.valueOf(42);
}
}
Но при использовании этого производителя я всегда получаю ошибку в следующей ситуации:
@Named("test")
public class TestComponent {
...
@Inject public void setA(@TestQualifier String stringValue) {
...
@Inject public void setB(@TestQualifier Integer integerValue) {
Он работает только тогда, когда метод создания производителя имеет ожидаемый тип в методе подпись:
public class TestProducer {
@Produces @SpringBean
public String create(InjectionPoint ip) {
Теперь строка вводится правильно, но у меня нет возможности также генерировать целое число из метода производителя. Но это именно то, чего я хочу избежать, так как сам производитель должен быть полностью общим.
Я делаю что-то не так или нет никакого способа достичь поведения, которое я хочу?
Решение
Вся документация CDI дает понять, что CDI делает Типов Инъекция зависимости - и это возвышенное свойство CDI. ИМХО, то, что вы пытаетесь сделать, это то, что CDI пытается избежать. Вы хотите, чтобы контейнер разыграл Object
К каждому типу и CDI не работает так.
Инъекции указывают stringValue
и integerValue
может получить только боб, которая имеет java.lang.String
и java.lang.Integer
в своем списке Типы бобов соответственно. java.lang.Object
не удовлетворяет этому критерию.
У меня есть два предложения. Во -первых, поскольку у вас есть две или более точек впрыска разных типов, создайте два или более методов производителя для этих типов:
public class TestProducer {
@Produces @TestQualifier
public String createString(InjectionPoint ip) {
if(something) {
return "a String";
} else {
// Some other value
}
}
@Produces @TestQualifier
public int createInt(InjectionPoint ip) {
if(something) {
return 42;
} else {
// Some other value
}
}
// ...
Это работает, если something
Условие просто для проверки типа точки впрыска (то, что я делаю, так, как в этом случае).
Однако, если something
Состояние определяет тип, используя другие критерии, чем тип впрыска, я бы предложил сделать «грязную работу» самостоятельно: ввести возвращенное значение в Object
-typed впрыска и делает актерский состав вручную:
@Named("test")
public class TestComponent {
...
@Inject public void setA(@TestQualifier Object value) {
String stringValue = (String) value;
...
@Inject public void setB(@TestQualifier Object value) {
int intValue = (Integer) value;
Главный момент заключается в том, что, в отличие от некоторых других DI -структур, CDI не работает против системы типа Java - напротив, он широко использует ее. Не пытайтесь бороться с этим, но используйте этот аспект CDI в вашу пользу :)
Другие советы
Производитель для Object
все равно странно. Я не уверен, запрещено ли это спецификацией, или это ошибка, но я думаю, что вы можете сделать какой -то умный обходной путь:
public class ValueHolder<T> {
private T value;
public T getValue() {
return value;
}
}
А затем внесите ValueHolder<String>
и ValueHolder<Integer>
Возможны возможные создающие общие объекты с CDI, как это производит:
// the wrapper class
public class Wrapper<T> {
public final T bean;
public Wrapper(T bean){
this.bean = bean;
}
}
// the producer inside some class
@Produces
public <T> Wrapper<T> create(InjectionPoint p){
// with parameter 'p', it is possible retrieve the class type of <T>, at runtime
}
// the bean example 1
public class BeanA {
public void doFoo(){
// ...
}
}
// the bean example 2
public class BeanB {
public void doBar(){
// ...
}
}
// the class that uses the produced beans
public class SomeBean{
//// There on producer method, do you can retrieve the Class object of BeanA and BeanB, from type parameters of Wrapper.
@Inject
private Wrapper<BeanA> containerA;
@Inject
private Wrapper<BeanB> containerB;
public void doSomeThing(){
containerA.doFoo();
containerB.doBar();
}
}
Работает на сварке 2.2.0. Я думаю, что это работает и на некоторых предыдущих версиях.
Ваши методы инициализатора будут искать управляемых бобов с строкой и целым числом API, но ваш метод производителя имеет только тип API (в случае метода производителя, возврата типа) объект.
Поэтому вы можете использовать только объект в полях INATIVER INATIVER, а затем дискриминировать типы int тело ресивера или просто обернуть их и метод производителя в фактическом типе, который может возвращать строки или INT (но я бы избегал Дженерики)