一般的な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が行っていることが明らかになります TypeSafe 依存関係注射 - そして、それはCDIの高貴な特性です。私見、あなたがやろうとしていることは、CDIが避けようとしていることです。コンテナにキャストしたい Object
各タイプとCDIはそのように機能しません。
注入ポイント stringValue
と integerValue
持っている豆のみを受け取ることができます java.lang.String
と java.lang.Integer
のリストに 豆タイプ それぞれ。 java.lang.Object
この基準を満たしていません。
2つの提案があります。まず、異なるタイプの2つ以上の注入ポイントがあるため、そのタイプの2つ以上のプロデューサー方法を作成します。
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
- タイプの注入ポイントで、キャストを手動で行います。
@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;
}
}
そして、aを注入します 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タイプの文字列と整数を備えたマネージドビーンを探しますが、プロデューサーメソッドBeanにはAPIタイプのみ(プロデューサーメソッド、リターンタイプの場合)オブジェクトがあります。
したがって、fiiltizerメソッド注入フィールドでのみオブジェクトを使用してから、受信機の本文をint int int int in specring in and wrap and wrap in strings or intで包みます(ただし、intを返すことができます(ただし、ジェネリック)