Troubleshooting contexts and dependency injection

Use this task to troubleshoot errors related to Contexts and Dependency Injection (CDI) for the Java™ Platform, Enterprise Edition (Java EE) applications.

About this task

When you use a CDI implementation, you might experience errors during application deployment or when CDI interacts with other Java EE components. You might also experience problems with producers, interceptors and decorators or diagnostic trace. Use this task to fix these errors that might occur.

Procedure

  • Troubleshoot application deployment problems.
    At application deployment time, the container must validate each injection point in the application and is satisfied by only one source of that dependency.
    1. Resolve ambiguous dependency.

      An ambiguous dependency, or javax.enterprise.inject.AmbiguousResolutionException exception, occurs when the container resolves an injection points type and qualifiers to more than one managed bean, producer method, or producer field.

      The exception tells you the injection point that was being processed, and the candidate beans that remained at the end of the type-safe resolution process. Anything other than a single bean is an application error:
      javax.enterprise.inject.AmbiguousResolutionException: 
        There is more than one api type with : com.ibm.websphere.samples.AppObject 
           with qualifiers : Qualifiers: [@com.ibm.websphere.samples.MyQualifier()]
           for injection into Field Injection Point, field name :  loginCheck, 
             Bean Owner : [Name:loginBean,WebBeans Type:MANAGED,API Types:[java.lang.
      Object,com.ibm.websphere.samples.LoginBean],
               Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.
      Default,javax.inject.Named]]
      
      found beans: Name:newObject,WebBeans Type:PRODUCERMETHOD, API Types:[com.ibm.websphere.
      samples.AppObject,java.lang.Object], Qualifiers:[javax.enterprise.inject.
      Any,com.ibm.websphere.samples.MyQualifier,javax.inject.Named]
      
      Name:newObject2,WebBeans Type:PRODUCERMETHOD, API Types:[com.ibm.websphere.
      samples.AppObject,java.lang.Object], Qualifiers:[javax.enterprise.inject.
      Any,com.ibm.websphere.samples.MyQualifier,javax.inject.Named]
      To resolve the error complete one of the following actions:
      • Disambiguate the injection point by adding a qualifier to the injection point and if necessary, one source of the dependency.
      • If necessary, annotate one of the sources of contextual instances with @Alternative or @Specializes, if some of the dependencies should not be considered for injection.
    2. Resolve an unsatisfiable dependency.
      An unsatisfiable dependency, or javax.enterprise.inject.UnsatisfiedResolutionException, occurs when there is no corresponding source for objects matching an injection point in the application. The API type of the field, along with the optional set of qualifier annotations, dictates the set of beans that are valid to satisfy the dependency. Causes of unsatisfiable dependency are as follows:
      • There is no managed bean that is assignable to the type on the injection point.
      • There is no producer method of any managed bean whose return type is assignable to the injection point.
      • There is no producer field in any managed bean whose type is assignable to the injection point.
      • One of the previously mentioned scenarios are valid, but the Qualifier annotations on the injection point are not present on the bean or producer.
      • The CDI container does not scan shared libraries for CDI managed beans.
      Note: Resolve the error by making a dependency with the API type and qualifiers available by introducing a new bean, removing qualifiers, or adding producers fields or methods. Section 5.2 of the Contexts and Dependency Injection for Java specification describes the type-safe resolution in detail.
      javax.enterprise.inject.UnsatisfiedResolutionException: Api type 
      [com.ibm.websphere.samples.myType] is not found with the qualifiers 
        Qualifiers: [@javax.enterprise.inject.Default()] 
        for injection into Field Injection Point, field name :  loginCheck, 
          Bean Owner : [Name:loginBean,WebBeans Type:MANAGED,
            API Types:[java.lang.Object,com.ibm.websphere.samples.LoginBean],
            Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.
      inject.Default,javax.inject.Named]]

      If the dependency is an Enterprise JavaBean (EJB) in a separate EJB module, verify the EJB module is listed in the classpath of the META-INF/MANIFEST.MF directory that is inside of the web project with the failing @Inject annotation. In Eclipse, establish this relationship under Deployment Assembly properties of the web project.

    3. Resolve passivating scope dependencies.
      Passivation is the act of moving an idle object that is held in memory auxiliary storage. A passivating scope, such as the built-in scopes, @SessionScoped and @ConversationScoped, requires that any bean using the scope be passivation-capable. A bean is passivation-capable if it is either a stateful session bean or any other managed bean that is both serializable and has no non-serializable interceptors and decorators. Causes of passivating scope dependencies include the following:
      • Changing the scope of an existing bean to a passivating scope, such as @SessionScoped or @ConversationScoped.
      • Adding non-serializable decorators or interceptors to an existing passivation capable bean.
      Resolve the error as follows:
      • Ensure that the bean in question is serializable.
      • Ensure all interceptors and decorators of the bean implement serializable.
      • Change the scope of the managed bean to a non-passivating scope.
      In the following exception, the myCDIBean bean has java.io.Serializable as an API type, therefore, the problem is an interceptor or decorator of this bean:
      Caused by: org.apache.webbeans.exception.WebBeansConfigurationException: 
      Passivation scoped defined bean must be passivation
      capable, but bean : Name:myCDIBean,WebBeans Type:MANAGED,API 
        Types:[com.ibm.websphere.samples.myCDIBean java.io.Serializable,java.lang.
      Object,com.ibm.websphere.samples.myLocalIface],
        Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.
      Default,javax.inject.Named] is not passivation capable
  • Troubleshoot errors that result from CDI interacting with other Java EE components.

    The @Inject annotation provides an additional type of Java EE dependency injection. Its relation to injection that is defined in Java EE 5 is as follows:

    • Injection using annotations other than the @Inject annotation behave as in previous releases, and only dependencies injected using the @Inject annotation are contextual instances as defined by Contexts and Dependency Injection for Java (JSR299).
    • Use producer fields and producer methods to provide limited CDI features (such as type-safe injection) of Java EE dependencies obtained using the @Resource, @PersistenceContext, @PersistenceUnit, and @WebServiceRef annotations.
    If you cannot obtain a value for an Expression Language (EL) reference to a managed bean for JavaServer Pages (JSP) and JavaServer Faces (JSF) components, consider the following approaches:
    • Ensure that the bean class is annotated using the @Named annotation or is annotated with a stereotype that defines the @Named annotation.
    • Ensure that the EL expression matches the class name of the bean class, after converting the first character to lowercase. When you use the @Named annotation qualifier with a value member (for example, @Named("myName")), this specifies the bean name (a special case qualifier) but does not change the EL name of that bean.
    For EJB components:
    • You can inject session beans with the @Inject and @EJB annotations. When you inject stateful session beans with the @Inject annotation, the session beans can take advantage of type-safe injection using qualifiers, and can have their life cycle managed by their CDI scope.
    • Session beans are eligible for interception and decoration even when they are not obtained with the @Inject annotation, unlike other managed beans.
    • If the dependency is an Enterprise JavaBean (EJB) in a separate EJB module, verify the EJB module is listed in the classpath of the META-INF/MANIFEST.MF directory that is inside of the web project with the failing @Inject annotation. In Eclipse, establish this relationship under Deployment Assembly properties of the web project.
    For web service components:
    • To develop a JAX-WS client from a Web Services Description Language (WSDL) file, follow the steps outlined in the topic, Developing a JAX-WS client from a WSDL file.
      Tip: Use the wsimport tool to generate portable Java artifacts, including a service class.
    • If you want to inject the generated service class into a CDI-managed bean, using the @WebServiceRef annotation, you must invoke the wsimport tool using the -wsdllocation argument. As a result, the generated service class is portable to other systems because the service class references the WSDL file using a relative URI, instead of an absolute path.
  • Troubleshoot producer errors.
    1. Looping in producer methods.
      When you use a producer method, each parameter is treated as an injection point in which the container provides the dependency. Therefore, the source of contextual objects that fulfill those parameter injection points must not be the same class that contains the producer method.
    2. Duplicate producer methods (two @Produces annotations with same qualifiers in the same class).
      If a class has multiple producer fields, these fields cannot have the same API type and an identical set of qualifiers, as such a guaranteed ambiguous dependency would not be injectable.
      org.apache.webbeans.exception.definition.DuplicateDefinitionException: 
      PassivationCapable bean id is not unique: 
         PRODUCERFIELD#class#com.ibm.websphere.samples.AppObject#
           @javax.enterprise.inject.Any(),@com.ibm.websphere.samples.AppScopeBinding2
      (),@javax.inject.Named(value=), 
           bean:Name:a2b,WebBeans Type:PRODUCERFIELD,API Types:[java.lang.Object,
      com.ibm.websphere.samples.AppObject],
           Qualifiers:[javax.enterprise.inject.Any,com.ibm.websphere.samples
      .AppScopeBinding2,javax.inject.Named]
  • Troubleshoot interceptor and decorator errors.
    1. Enable interceptor, decorator enablement interceptors, and decorators in the beans.xml file. All except EJB session beans apply only to contextual instances of beans. Contextual instances are instances obtained using the @Inject annotation or by calling methods on the BeanManager interface.
    2. Interceptors and decorators in multiple bean deployment archives (BDA). The set of enabled interceptors and decorators of a bean class are a collection of the enabled interceptors and decorators across the entire EAR file. The order of interceptors and decorators that are defined in different beans.xml files is undefined.
  • Use diagnostic trace to help determine why an error occurred.
    1. Obtain a trace for CDI by specifying JCDI=all:com.ibm.ws.webbeans*=all:org.apache.webbeans*=all.
      • Obtain a list of all discovered managed beans by searching for org.apache.webbeans.config.BeansDeployer in trace.log file. Each managed bean, along with its type (interceptor, decorator, producer, enterprise (EJB)) is displayed.
      • Obtain a detailed listing of each bean and its type and qualifiers by searching for the getBeans string.
    2. Obtain an additional trace for interacting with Java EE injection and the EJB container by specifying EJBContainer=all:MetaData=all:Injection=all.
    3. Obtain an additional trace for interacting with web-related scopes and life cycles by specifying all:com.ibm.ws.wswebcontainer*=all.
  • Avoid heavyweight operations in default constructors of managed beans.

    Each injection point for a given managed bean receives a new client proxy that calls the default constructor of the underlying bean class, in addition to the actual bean instance that might be created when using the proxy. Additionally, because dependency injections occur after the constructor completes, constructors cannot use injected dependencies. See the @PostConstruct annotation life cycle callback for a place to put post-injection logic that runs in the underlying instance only.

  • Limitations imposed by OpenWebBeans and Javassist

    The CDI implementation uses OpenWebBeans and Javassist to create CDI proxy instances. Javassist does not proxy private methods so if a private method on a proxy instance is invoked, the method on the actual bean instance is never called. Since the method is being invoked on the proxy instance, it will only be able to access member variables for the proxy instance, not the actual bean instance. This is a Javassist limitation.

    In general, only the CDI container can call private methods on a bean. Therefore, this is only a problem for private methods which have been annotated with certain CDI annotations such as @PostConstruct, @PreDestroy, or @Produces.

    For example, if a proxied bean has a private @PostConstruct method which attempts to set the value of a class member variable, the variable it would be setting would be the one on the proxy instance. It would have no affect on the member variable on the actual bean instance.

    There are two ways to workaround this limitation:
    • Change the access modifier for the private method from private to non-private (specifically - public, protected). This will result in the method being correctly proxied.
    • Have the private method access member variables via non-private accessor methods. Those accessor methods would be proxied and have access to the member variables for the actual bean instance.