0

I am working in a Java EE maven project and I'm experiencing problems with dependency injection when attempting to deploy to a Glassfish4 server.

The maven project is structured in three separate modules under a top level pom like so:

kronos:

  • ear
  • ejb
  • web

Kronos is the parent module, web handles the front-end code (JSF, ManagedBeans), ejb has the back-end code (EJBs, JPA) and ear handles the ear artefact generation and deployment. The actual pom.xml files are listed at the end of this post.

Inside the ejb module we have a StaffDAO interface and a StaffDAOImpl stateless bean (annotated @javax.ejb.Stateless). At the moment this is the only EJB bean in the code and it is certainly the only bean implementing StaffDAO.

When attempting to inject the bean inside a ManagedBean (@ManagedBean, @RequestScoped) in the web component using the @Inject annotation on a field of type StaffDAO we get the following error when attempting to deploy to Glassfish:

    [glassfish 4.0] [SEVERE] [] [javax.enterprise.system.core] [tid: _ThreadID=35 _ThreadName=admin-listener(4)] [timeMillis: 1393775922183] [levelValue: 1000] [[
      Exception while loading the app : CDI deployment failure:WELD-001409 Ambiguous dependencies for type [StaffDAO] with qualifiers [@Default] at injection point [[BackedAnnotatedField] @Inject private managedbeans.DummyUserBean.staffDAO]. Possible dependencies [[Session bean [class persistence.dao.impl.StaffDAOImpl with qualifiers [@Any @Default]; local interfaces are [StaffDAO], Session bean [class persistence.dao.impl.StaffDAOImpl with qualifiers [@Any @Default]; local interfaces are [StaffDAO]]]
    org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [StaffDAO] with qualifiers [@Default] at injection point [[BackedAnnotatedField] @Inject private managedbeans.DummyUserBean.staffDAO]. Possible dependencies [[Session bean [class persistence.dao.impl.StaffDAOImpl with qualifiers [@Any @Default]; local interfaces are [StaffDAO], Session bean [class persistence.dao.impl.StaffDAOImpl with qualifiers [@Any @Default]; local interfaces are [StaffDAO]]]

Using the @EJB annotation instead gives us:

[glassfish 4.0] [SEVERE] [NCLS-CORE-00026] [javax.enterprise.system.core] [tid: _ThreadID=34 _ThreadName=admin-listener(3)] [timeMillis: 1393776686187] [levelValue: 1000] [[
  Exception during lifecycle processing
java.lang.IllegalArgumentException: Cannot resolve reference [Remote ejb-ref name=managedbeans.DummyUserBean/staffDAO,Remote 3.x interface =persistence.dao.StaffDAO,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session] because there are [2] ejbs in the application with interface persistence.dao.StaffDAO. 
Some of the possible causes: 
1. The EJB bean class was packaged in an ear lib library (or through any other library mechanism which makes the library visible to all component modules), this makes all the component modules include this bean class indirectly. 
2. The EJB bean class was packaged in a component module which references the EJB, either directly or indirectly through Manifest, WEB-INF/lib. 
The EJB bean class should only be packaged in the declaring ejb module and not the referencing modules. The referencing modules should only include EJB interfaces.

I believe, though I am not sure, that this is caused by a mistake in our artefact generation that results in the StaffDAOImpl EJB being packaged twice, but I am not sufficiently familiar with maven to confirm and fix that. Any help would be appreciated.

Code:

StaffDAO:

public interface StaffDAO {...}

StaffDAOImpl:

import javax.ejb.Stateless;

@Stateless
public class StaffDAOImpl implements persistence.dao.StaffDAO {...}

DummyUserBean:

import javax.faces.bean.ManagedBean;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;

@ManagedBean(name = "dummyUserBean")
@RequestScoped
public class DummyUserBean {

    @Inject
    private StaffDAO staffDAO;

    ...
}

The pom.xml files are:

kronos:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>kronos</groupId>
    <artifactId>kronos</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>ejb</module>
        <module>web</module>
        <module>ear</module>
    </modules>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
        </dependency>
    </dependencies>

    <properties>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <build>
        <finalName>HelloGlassfish4</finalName>
    </build>
</project>

ear:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>kronos</artifactId>
        <groupId>kronos</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>ear</artifactId>
    <packaging>ear</packaging>

    <dependencies>
        <dependency>
            <groupId>kronos</groupId>
            <artifactId>ejb</artifactId>
            <version>1.0-SNAPSHOT</version>
            <type>ejb</type>
        </dependency>

        <dependency>
            <groupId>kronos</groupId>
            <artifactId>web</artifactId>
            <version>1.0-SNAPSHOT</version>
            <type>war</type>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.glassfish.maven.plugin</groupId>
                <artifactId>maven-glassfish-plugin</artifactId>
                <version>2.1</version>
                <configuration>
                    <glassfishDirectory>${local.glassfish.home}</glassfishDirectory>
                    <user>${local.glassfish.user}</user>
                    <passwordFile>${local.glassfish.passfile}</passwordFile>
                    <domain>
                        <name>${local.glassfish.domain}</name>
                        <adminPort>${local.glassfish.adminPort}</adminPort>
                        <httpPort>${local.glassfish.httpPort}</httpPort>
                    </domain>
                    <components>
                        <component>
                            <name>${project.artifactId}</name>
                            <artifact>target/${project.build.finalName}.ear</artifact>
                        </component>
                    </components>
                    <debug>true</debug>
                    <terse>false</terse>
                    <echo>true</echo>
                </configuration>
            </plugin>

            <plugin>
                <artifactId>maven-ear-plugin</artifactId>
                <version>2.8</version>
                <configuration>
                    <modules>
                        <webModule>
                            <groupId>kronos</groupId>
                            <artifactId>web</artifactId>
                        </webModule>
                        <ejbModule>
                            <groupId>kronos</groupId>
                            <artifactId>ejb</artifactId>
                        </ejbModule>
                    </modules>
                    <defaultLibBundleDir>lib</defaultLibBundleDir>
                </configuration>
            </plugin>
        </plugins>
        <finalName>kronos</finalName>
    </build>
</project>

ejb:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>kronos</artifactId>
        <groupId>kronos</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>ejb</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>3.6.7.Final</version>
        </dependency>

        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.2-1003-jdbc4</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.6</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>

        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.9.5</version>
        </dependency>

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>16.0.1</version>
        </dependency>

        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.0.0.GA</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>4.1.0.Final</version>
        </dependency>

        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.3</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.16</version>
                <configuration>
                    <skipTests>true</skipTests>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-ejb-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <ejbVersion>3.2</ejbVersion>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

web:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>kronos</artifactId>
        <groupId>kronos</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>web</artifactId>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>kronos</groupId>
            <artifactId>ejb</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <version>4.0</version>
            <type>jar</type>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <webXml>src\main\webapp\WEB-INF\web.xml</webXml>
                </configuration>
            </plugin>
        </plugins>
        <finalName>web</finalName>
    </build>
</project>
Dalamar42
  • 107
  • 2
  • 8
  • I am looking at the Modules and Components view in the Glassfish admin web interface now and I see that StaffDAOImpl is included twice. Once in ejb-1.0-SNAPSHOT.jar and once in web-1.0-SNAPSHOT.war I believe that is due to the fact that both the ear and the web modules depend on ejb, but removing either dependency breaks the build. Should I create a third component to hold the common code for the ejb and web modules (interfaces, data model and exception classes) or is there a different solution recommended? – Dalamar42 Mar 02 '14 at 16:52
  • You can try using your EJB as provided, and it will look it up via remote. I am assuming that all of this is intended to be deployed inside an EAR, and all of your EJB references are within that EAR, right? – John Ament Mar 02 '14 at 21:08
  • That is correct. I actually managed to figure it out. Turns out the problem was what I suspected. The fact that the web module depends on ejb meant that the ejb classes were added to the ear package twice. Once in the ejb jar and once in the war. I'll just post this below as well and mark it in case it helps anyone else as well. – Dalamar42 Mar 03 '14 at 14:20

1 Answers1

2

It turns out my original suspicion was correct. Because the web module depended on the ejb module the ejb classes were added to the war archive. Because of that when the ear was built from the war and the ejb jar those classes ended up being packaged twice and that confused CDI.

I fixed it by making a fourth maven module to hold the code that is needed by both the ejb and web modules, adding it as a dependency to those two and breaking the web's dependency on the ejb. Now it works fine.

Dalamar42
  • 107
  • 2
  • 8
  • I always mark my EJB dependency in my Web module as provided to avoid this issue. Though I haven't seen it in practice. – Brian May 26 '14 at 23:13