問題を説明するための語彙が不足しているため、失敗を再現し、原因を見つけるのに役立つ例を使用して説明します。
public interface BaseType<P> {}
public interface DerivedType<T> extends BaseType<T> {}
public interface SomeType1 {}
public interface SomeType2 {}
@Dependent
public static class BeanClass1 implements DerivedType<SomeType1> {}
@Dependent
public static class BeanClass2 implements DerivedType<SomeType2> {}
@ApplicationScoped
public static class Test implements Serializable {
@Inject
private BaseType<SomeType1> field; // if not commented throws following exception during deployment: org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [BaseType<SomeType1>] with qualifiers [@Default] at injection point [[field] @Inject private Test.field]. Possible dependencies [[Managed Bean [class BeanClass2] with qualifiers [@Any @Default], Managed Bean [class BeanClass1] with qualifiers [@Any @Default]]]
@Inject
private Instance<BaseType<SomeType1>> instance;
@Inject
private BeanManager bm;
@PostConstruct
private void postConstruct() {
// This block outputs two bean classes and it should be only one:
// beanClass: BeanClass1@11be5bab
// beanClass: BeanClass2@764a72e9
{
Iterator<BaseType<SomeType1>> iterator = instance.iterator();
while (iterator.hasNext()) {
System.out.println("beanClass: " + iterator.next().toString());
}
}
// And this block outputs:
//
// bean: Managed Bean [class BeanClass1] with qualifiers [@Any @Default]
// beanTypes:
// - class BeanClass1
// - DerivedType<SomeType1>
// - class java.lang.Object
// - BaseType<T>
//
// bean: Managed Bean [class BeanClass2] with qualifiers [@Any @Default]
// beanTypes:
// - DerivedType<SomeType2>
// - class java.lang.Object
// - class BeanClass2
// - BaseType<T>
{
Set<Bean<?>> beans = bm.getBeans(new ParameterizedTypeImpl(BaseType.class, new Type[] { SomeType1.class }, null));
for (Bean<?> bean : beans) {
System.out.println("\nbean: " + bean+"\nbeanTypes: ");
for (Type beanType : bean.getTypes()) {
System.out.println(" - " + beanType);
}
}
bm.resolve(beans); // if not commeted throws an AmbiguousResolutionException
}
}
}
2 番目のブロックは、 に従って、Bean クラスBeanClass1
およびの Bean タイプのセットを示しています。そこで、Bean タイプ セットにorの代わりにタイプが含まれていることがわかりました。BeanClass2
Weld
BaseType<T>
BaseType<SomeType1>
BaseType<SomeType2>
そのため、記憶BeanClass2
する間接インターフェースに対応するBaseType<P>
のBean タイプは、実際の型パラメーターではなく、型変数を持ちます。したがって、この仕様の最後の点によると、は誤って に割り当て可能と見なされます。Weld
T
SomeType2
BeanClass2
BaseType<SomeType1>
これは望ましい動作ですか、それともバグですか? 回避策はありますか? 新しいWeld
バージョンで修正されましたか。
テストは、maven アーティファクト org.jboss.as:jboss-as-weld:7.1.1 を使用する JBoss AS 7.1.1 で実行されました。
編集:この問題の原因は、最初の回答が示唆するように型の消去ではなく(削除されました)、のバグだと思いますWeld
。Bean タイプを生成するために必要なすべての情報は、実行時に利用できます。Weld
バグは、リフレクションによって Bean クラスの Bean タイプを生成するときだと思います。型変数の解決は再帰的であるべきですが、明らかにそうではありません。
ライブラリを使用してこれを達成するメソッドを作成およびテストしたため、間接インターフェイスの Bean タイプを生成するために必要な情報が実行時に利用できると確信しています。つまりType
、Java クラスの祖先ごとにインスタンスを生成/取得し、型変数を再帰的に解決します。関連するメソッドをここに書き込もうとしましたが、コードを貼り付けるときにフォーマットの問題がありました。そして、ライブラリが長く、文書化が不十分であるという事実が、私にあきらめる理由を与えました。
少なくとも、間接インターフェースの型変数を解決する方法の本質を示すために、次のコードを書きました。これは特定のクラスに対してのみ機能しますが、ある程度の努力で一般化できます。
public static Set<Type> getActualInterfacesOfBeanClass1() {
Set<Type> actualInterfaces = new HashSet<>();
ParameterizedType directInterface = (ParameterizedType) BeanClass1.class.getGenericInterfaces()[0]; // = DerivedType<SomeType1> ; assumes only one interface is extended
actualInterfaces.add(directInterface);
// because ParameterizedType doesn't have a method like Class.getGenericInterfaces(), we have to do it by hand
Type indirectInterface; // = BaseType<SomeType1>
{
Class<?> directInterfaceRaw = (Class<?>) directInterface.getRawType(); // = DerivedType<T>
Map<String,Type> resolutionMap = new HashMap<>(); // = { T -> SomeType1 }
for( int i=0; i<directInterfaceRaw.getTypeParameters().length;++i) {
resolutionMap.put(directInterfaceRaw.getTypeParameters()[i].getName(),directInterface.getActualTypeArguments()[i]);
}
ParameterizedType indirectInterfaceUnresolved = (ParameterizedType) directInterfaceRaw.getGenericInterfaces()[0]; // = BaseType<T> ; assumes only one interface is extended
ArrayList<Type> resolvedParameters = new ArrayList<>(); // = { SomeType1 }
for(Type param : indirectInterfaceUnresolved.getActualTypeArguments()) {
Type resolvedParam;
if( param instanceof TypeVariable) {
resolvedParam = resolutionMap.get(((TypeVariable<?>)param).getName());
} else {
resolvedParam = param;
}
resolvedParameters.add(resolvedParam);
}
indirectInterface = new ParameterizedTypeImpl(indirectInterfaceUnresolved.getRawType(), resolvedParameters.toArray(new Type[resolvedParameters.size()]),indirectInterfaceUnresolved.getOwnerType());
}
actualInterfaces.add(indirectInterface);
return actualInterfaces;
}
これにより、型の消去がこの問題の原因であると信じられなくなることを願っています。