CDI object not proxyable with injected constructor

前端 未结 5 1979
广开言路
广开言路 2021-02-20 01:07

When trying to inject arguments into the constructor of a CDI bean (ApplicationScoped), I\'m encountering the following issue:

Caused by: org.jboss.weld.exceptio         


        
相关标签:
5条回答
  • 2021-02-20 01:50

    I think Vladimir is pointing you to the right direction.

    I'm just learning CDI (and Weld) therefore my answer might not be 100% accurate in all aspects, but it seems like you need to pick a type at injection point that has a no arg constructor.

    I hit the same error today with the next type hierarchy:

    • there is a provided IServerInterceptor interface,
    • there is a custom implementation AuthenticationInterceptor that has one constructor that takes dependencies (fun fact: this knows nothing about (C)DI),
    • there is an InjectableAuthenticationInterceptor which has only one injected constructor.

    I have another bean where I would like to inject an instance of AuthenticationInterceptor. It works, when I define the field as type IServerInterceptor (as it is an interface and weld can create a proxy for it(?)), but it stops working when I define the field as AuthenticationInterceptor.

    With some code:

    // 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);
        }
    }
    

    Now,

    @Inject private IServerInterceptor authenticationInterceptor;
    

    works great, but

    @Inject private AuthenticationInterceptor authenticationInterceptor;
    

    does not.

    0 讨论(0)
  • 2021-02-20 01:54

    We resolved similar problem splitting class into interface and implementation. In your case something like this:

    public interface Config
    {
      // API here
    }
    
    @ApplicationScoped @Priority(0)
    public class ConfigImpl implements Config
    {
      @Inject
      public ConfigImpl(ConfigLocator configLocator) { ... }
    
      // API implementation here
    }
    
    0 讨论(0)
  • 2021-02-20 02:00

    Splitting in interface and implementation won't solve the problem completely. The Problem is that the interface will not be ApplicationScoped, because an ApplicationScoped Bean needs a Default "no args" Construcutor, to be proxyable. Like this it will always create a new instance of the implementation. So the implementation behaves like a @Dependent annotated bean.

    If you want to solve it this way, you need to use a method with @PostConstruct to handle the inject of the argument and only use a non arg constructor.

    0 讨论(0)
  • 2021-02-20 02:02

    This example might help you :

    @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() {
        }
    
    }
    

    You need to have a public non-args constructor in the @ApplicationScoped bean.

    Note : The bean for this class will created only once and is maintained for the entire life of an application. This bean will shared among all the managed beans. @ApplicationScoped beans are singleton in nature.

    The mentioned issue:

    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].
    

    The possible reason for this is that a non-dependent scoped bean is required to provide a public no-args constructor for CDI, so that it can pick up the desired proxy bean at runtime.

    0 讨论(0)
  • 2021-02-20 02:09

    The non-private, no-arg constructor is needed for the implementation to create a proxy to your managed bean You don't lose the functionality of your injected constructor based on the presence of the non-private, no-arg constructor.

    The container uses proxies to allow things like interception, decoration, and to retrieve the right contextual instance when the bean is dereferenced. It's also needed to allow circular injection between beans.

    0 讨论(0)
提交回复
热议问题