CDI Bean(ApplicationScoped)のコンストラクターに引数を挿入しようとすると、次の問題が発生します。
Caused by: org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001435: Normal scoped bean class xx.Config is not proxyable because it has no no-args constructor - Managed Bean [class xx.Config] with qualifiers [@Default @Named @Any].
at org.jboss.weld.bean.proxy.DefaultProxyInstantiator.validateNoargConstructor(DefaultProxyInstantiator.Java:50)
at org.jboss.weld.util.Proxies.getUnproxyableClassException(Proxies.Java:217)
at org.jboss.weld.util.Proxies.getUnproxyableTypeException(Proxies.Java:178)
ただし、クラスには注入可能なコンストラクターがあります。
@Inject
public Config(ConfigLocator configLocator) {
defaultConfigPath = configLocator.getPath();
doStuff();
}
デフォルトのコンストラクター、変数インジェクション、およびpostconstructメソッドを使用すると、これはすべて正常に機能しますが、この場合はコンストラクターインジェクションをお勧めします。
ここで何がうまくいかないのか考えはありますか?
クラスをインターフェースと実装に分割する同様の問題を解決しました。あなたの場合、次のようなものです。
public interface Config
{
// API here
}
@ApplicationScoped @Priority(0)
public class ConfigImpl implements Config
{
@Inject
public ConfigImpl(ConfigLocator configLocator) { ... }
// API implementation here
}
この例はあなたを助けるかもしれません:
@ApplicationScoped
public class Config {
private String defaultConfigPath;
@Inject
public Config(ConfigLocator configLocator) {
this.defaultConfigPath = configLocator.getPath();
doStuff();
}
// create a no-args constructor which is required for any scoped bean.
public Config() {
}
}
@ApplicationScoped
Beanにパブリック非引数コンストラクターが必要です。
注:このクラスのBeanは一度だけ作成され、アプリケーションの存続期間全体にわたって維持されます。このBeanはすべての管理対象Bean間で共有されます。@ ApplicationScopedBeanは本質的にシングルトンです。
言及された問題:
Caused by: org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001435: Normal scoped bean class xx.Config is not proxyable because it has no no-args constructor - Managed Bean [class xx.Config] with qualifiers [@Default @Named @Any].
これの考えられる理由は、実行時に目的のプロキシBeanを取得できるように、CDIのパブリックno-argsコンストラクターを提供するために非依存スコープBeanが必要であるためです。
実装がマネージドBeanへのプロキシを作成するには、非プライベートの引数なしのコンストラクターが必要です。非プライベートの引数なしのコンストラクターの存在に基づいて、注入されたコンストラクターの機能が失われることはありません。
コンテナはプロキシを使用して、インターセプトや装飾などを許可し、Beanが逆参照されたときに適切なコンテキストインスタンスを取得します。 Bean間の循環注入を可能にすることも必要です。
ウラジミールはあなたを正しい方向に向けていると思います。
私はCDI(およびWeld)を学習しているだけなので、私の答えはすべての面で100%正確ではないかもしれませんが、引数なしのコンストラクターを持つ注入ポイントで型を選択する必要があるようです。
今日、次のタイプ階層で同じエラーが発生しました。
IServerInterceptor
インターフェースがあります。AuthenticationInterceptor
があります(面白い事実:これは(C)DIについて何も知りません)、InjectableAuthenticationInterceptor
があります。AuthenticationInterceptor
のインスタンスを注入したい別のBeanがあります。フィールドをタイプIServerInterceptor
として定義すると機能しますが(インターフェイスであり、weldはそのプロキシを作成できるため(?))、フィールドをAuthenticationInterceptor
として定義すると機能しなくなります。
いくつかのコードで:
_// IServerInterceptor.Java
public interface IServerInterceptor {
}
// AuthenticationInterceptor.Java
public class AuthenticationInterceptor extends InterceptorAdapter {
private final Predicate<String> validAccessTokenString;
private final Function<String, AccessToken> toAccessTokenModel;
private final LoginManager<AccessToken> loginManager;
public AuthenticationInterceptor(Predicate<String> validAccessTokenString, Function<String, AccessToken> toAccessTokenModel, LoginManager<AccessToken> loginManager) {
this.validAccessTokenString = validAccessTokenString;
this.toAccessTokenModel = toAccessTokenModel;
this.loginManager = loginManager;
}
// ...
}
// InjectableAuthenticationInterceptor.Java
@ApplicationScoped
public class InjectableAuthenticationInterceptor extends AuthenticationInterceptor {
@Inject
public InjectableAuthenticationInterceptor(LoginManager<AccessToken> loginManager) {
super(isWelformedAccessToken(), toAccessToken(), loginManager);
}
}
_
さて、
_@Inject private IServerInterceptor authenticationInterceptor;
_
うまく機能しますが
_@Inject private AuthenticationInterceptor authenticationInterceptor;
_
ではない。
Splitting
のinterface
と実装では、問題を完全に解決することはできません。問題は、interface
Beanがプロキシ可能であるためにデフォルトの"no args" Construcutor
を必要とするため、ApplicationScoped
がApplicationScoped
にならないことです。このように、常に実装の新しいインスタンスを作成します。したがって、実装は@Dependent
アノテーション付きBeanのように動作します。
この方法で解決したい場合は、@PostConstruct
のメソッドを使用してargument
の挿入を処理し、non arg constructor
のみを使用する必要があります。