Search code examples
ejbwebsphere

Why does WebSphere create duplicate EJB environment entries?


I specified a String resource in an EJB with the @Resource annotation. The EJB is packaged within an EJB module. The ejb.jar has an ejb-jar.xml which specifies a default value for the String resource. The ejb.jar is packaged in an ear archive together with a web module.

When the ear is deployed to WebSphere, the Environment entries for EJB modules section shows three EJB entries:

  1. The String resource I mapped for the ejb module;
  2. The String resource I mapped for the ejb module, only this time it is called EJB_fully_qualified_name/resource_name;
  3. The same fully qualified name of the resource but now mapped for the web module.

Unless I provide a default value for all the variants above the resource is not injected. If I add an ejb-jar.xml to the web module, WebSphere displays four entries (one simple name and one fully qualified name of the resource per module). Is this a WebSphere quirk or am I doing something wrong? I am using WebSphere 8.5.5.3 in a cluster environment.

Here is the bean:

@Singleton
@Startup
public class ConfigSingleton { 
    @Resource
    private String serviceLookup;
}

Here is the ejb-jar.xml:

<ejb-jar>
    <enterprise-beans>
            <session>
                <ejb-name>ConfigSingleton</ejb-name>    
                <env-entry>
                    <env-entry-name>serviceLookup</env-entry-name>
                    <env-entry-type>java.lang.String</env-entry-type>
                    <env-entry-value>value</env-entry-value>
                </env-entry>                
            </session>
    </enterprise-beans>
</ejb-jar>

Solution

  • You have defined 2 completely different resources; either may be looked up.

    Per the Java EE specifications, when you don't use the 'name' attribute of the @Resource annotation a default name is provided for you, which is the fully qualified class name where the annotation exists followed by the JavaBeans property name (which is basically either the name of the field, or the name of the method with 'set' removed and the next character in lowercase). The javadoc for the @Resource annotation is a little misleading as it just says the default is the field name; but does not clarify exactly what the field name is; it is in fact the class name followed by the field name, much like you would see if you printed out the java.lang.reflect.Field that would represent it.

    When combining annotations and XML, the XML overrides the annotation only when the 'name' matches. In the sample provided, the names do not match, so you actually have 2 different resources.

    If you want your <env-entry> in XML to override the @Resource annotation, so that you can inject a value, then you either need to change your annotation to look like this:

    @Resource(name="serviceLookup")
    

    Or change the <env-entry-name> to the fully qualified class name / serviceLookup.

    Also, when the EJB module is included in a WAR modules things get a bit more complicated. Not the 'name' aspect, but where you can provide the value. In addition to providing a value in ejb-jar.xml, WebSphere also allows you to provide a value in ibm-ejb-jar-bnd.xml. However, when the EJB modules is in a WAR, then it may also be provided in ibm-web-bnd.xml... since all of the resources for all of the EJBs are visible in the java:comp/env name space for the entire WAR module. So, in the sample, you are getting two different names because of the defaults, and what appears to be two additional copies which are really just provided in case you want to override the values in ibm-web-bnd.xml.