JavaEE Wildfly EJB not injected, war-only project

2019-05-26 01:53发布

问题:

I'm new to JavaEE and I created a "hello world" project, using Hibernate as JPA provider, build using gradle and deployed to Wildfly. I want to use @Stateless bean for database-aware class, that will do all operations on DB, and then inject it to all "JAX-RS" classes, that contain REST endpoints.

Database class:

@Stateless
public class DatabaseManager {

    @PersistenceContext
    EntityManager entityManager;

    public DatabaseManager() {
    }

    public String sayHello() {
        // do some db-stuff
        return "EHLO";
    }
}

REST class:

@Path("/")
@SessionScoped
public class RestMainEndpoint implements Serializable {

    @EJB
    private DatabaseManager databaseManager;

    public RestMainEndpoint() {
    }

    @GET
    @Path("/hello")
    @Produces("text/plain")
    public String helloFromDb() {
        return databaseManager.sayHello();
    }
}

Problem is that @EJB private DatabaseManager databaseManager; is always null. It never gets injected.

I know that the REST is working, since all non-db related endpoints are working fine. I also assume that DatabaseManager bean is created and initialized, since I can see it on Wildfly admin panel.

I'm not sure if I'm packaging and deploying it right - it's all packed to single war and deployed. Is it necessary for me to use ear or create separate project? I tried, but I was unable to successfully convert it to ear project with gradle.


edit: in WEB-INF directory of my source files I won't have any jars, only web.xml and recently added beans.xml (which doesn't seem to have any effect). Is it necessary?

web.xml content:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Desktopeo</display-name>
    <servlet>
        <servlet-name>desktopeo</servlet-name>
        <servlet-class>
            org.glassfish.jersey.servlet.ServletContainer
        </servlet-class>
        <init-param>
            <param-name>
                jersey.config.server.provider.packages
            </param-name>
            <param-value>
                edu.desktopeo.server
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>desktopeo</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app>

beans.xml content:

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
      http://xmlns.jcp.org/xml/ns/javaee
      http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" bean-discovery-mode="all">
</beans>

However, in output war archive (which is really a zip archive), I have a lot of jars:

My project jars: Commons-1.0.jar (few POJO classes)

My lib jars: (libs I added by myself using gradle)

commons-codec-1.10.jar
commons-collections4-4.0.jar
commons-io-2.4.jar
commons-lang3-3.4.jar
guava-19.0-rc2.jar

My Database-related jars:

hibernate-commons-annotations-5.0.0.Final.jar
hibernate-core-5.0.2.Final.jar
hibernate-entitymanager-5.0.2.Final.jar
hibernate-jpa-2.1-api-1.0.0.Final.jar
sqljdbc4.jar // JDBC driver for MS SQL

Other jars: (probably mostly other dependencies)

javaee-api-7.0.jar
activation-1.1.jar
antlr-2.7.7.jar
aopalliance-repackaged-2.4.0-b31.jar
dom4j-1.6.1.jar
genson-1.3.jar
geronimo-jta_1.1_spec-1.1.1.jar
hk2-api-2.4.0-b31.jar
hk2-locator-2.4.0-b31.jar
hk2-utils-2.4.0-b31.jar
jandex-1.2.2.Final.jar
javassist-3.18.1-GA.jar
javax.annotation-api-1.2.jar
javax.inject-1.jar
javax.inject-2.4.0-b31.jar
javax.mail-1.5.0.jar
javax.ws.rs-api-2.0.1.jar
jboss-logging-3.3.0.Final.jar
jersey-client-2.22.1.jar
jersey-common-2.22.1.jar
jersey-container-servlet-2.22.1.jar
jersey-container-servlet-core-2.22.1.jar
jersey-guava-2.22.1.jar
jersey-media-jaxb-2.22.1.jar
jersey-server-2.22.1.jar
jsoup-1.8.3.jar
log4j-1.2.17.jar
slf4j-api-1.7.2.jar
slf4j-log4j12-1.7.2.jar
osgi-resource-locator-1.0.1.jar
validation-api-1.1.0.Final.jar
xml-apis-1.0.b2.jar

PROBLEM SOLVED

As Steve C wrote in the answer, the problem was related to unnecessary jars in output war. I changed scope of few of them to provided and it helped (and also made war 4 times smaller).

Server side gradle build, for future reference:

apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'idea'

repositories {
    mavenCentral()
}

buildscript {
    repositories {
        jcenter()
    }
}

configurations {
    provided
}

sourceSets {
    main.compileClasspath += configurations.provided
    test.compileClasspath += configurations.provided
    test.runtimeClasspath += configurations.provided
}

idea {
    module {
        scopes.PROVIDED.plus += [configurations.provided]
    }
}

dependencies {
    provided 'javax:javaee-api:7.0'
    provided 'org.hibernate:hibernate-core:5.0.2.Final'
    provided 'org.hibernate:hibernate-entitymanager:5.0.2.Final'

    // other libs, with regular "compile"
}

回答1:

Your EJB is not being injected because you have packaged your own copy of a JAX-RS implementation into your web app. This implementation does not know how to inject EJBs.

As this is WildFly 9, you can get rid of all the jersey jars, their dependencies and the complete web.xml.

In your gradle file you need to ensure that the javaee-api-7.0 dependency is given a scope of provided. It should not be packaged with your application as the server provides these classes. You also need to completely remove gradle references to:

  • activation-1.1.jar
  • geronimo-jta_1.1_spec-1.1.1.jar
  • javax.annotation-api-1.2.jar
  • java.inject-1.jar
  • javax.inject-2.4.0-b31.jar
  • javax.mail-1.5.0.jar
  • javax.ws.rs-api-2.0.1.jar
  • validation-api-1.1.0.Final.jar
  • xml-apis-1.0.b2.jar

because these classes are all provided by the javaee-api-7.0 dependency.

Finally, add a java source file containing:

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/rest")
public class JaxRsActivator extends Application {
}

which provides the configuration removed with the web.xml and you should be good to go.