Kohei Nozaki's blog 

Entries tagged [ear]

Arquillian EJB-JAR/EAR testing examples


Posted on Friday Mar 20, 2015 at 10:33AM in Arquillian


There are plenty of examples of Arquillian testing with WAR deployments, but not for other deployments such as EJB-JAR or EAR. so I created some examples. these examples were tested against Arquillian 1.1.7.Final, using WildFly 8.2.0.Final as remote container. the entire project can be obtained from GitHub.

Testing against EJB-JAR deployment

Assume we have a simple EJB in a EJB-JAR project as follows:

@Stateless
@LocalBean
public class SomeEjb {
    public String hello(String name) {
        return "Hello, " + name;
    }
}

Test class:

@RunWith(Arquillian.class)
public class EjbJarIT {
    @Deployment
    public static Archive<?> createDeploymentPackage() {
        final Archive archive = ShrinkWrap.create(JavaArchive.class).addClass(SomeEjb.class);
        return archive;
    }

    @EJB
    private SomeEjb someEjb;

    @Test
    public void test() {
        Assert.assertEquals("Hello, Kyle", someEjb.hello("Kyle"));
    }
}

The deployment will be a WAR through Arquillian’s automatic enrichment process while the method annotated as @Deployment produced JavaArchive.

Testing against EAR deployment

Assume we have a simple EAR project which depends on the preceding EJB-JAR project.

Test class:

@RunWith(Arquillian.class)
public class EarIT {

    @Deployment
    public static Archive<?> createDeploymentPackage() throws IOException {
        final JavaArchive ejbJar = ShrinkWrap.create(JavaArchive.class, "ejb-jar.jar").addClass(SomeEjb.class);

        // Embedding war package which contains the test class is needed
        // So that Arquillian can invoke test class through its servlet test runner
        final WebArchive testWar = ShrinkWrap.create(WebArchive.class, "test.war").addClass(EarIT.class);
        final EnterpriseArchive ear = ShrinkWrap.create(EnterpriseArchive.class)
                .setApplicationXML("test-application.xml")
                .addAsModule(ejbJar)
                .addAsModule(testWar);
        return ear;
    }

    @EJB
    private SomeEjb someEjb;

    @Test
    public void test() {
        Assert.assertEquals("Hello, Kyle", someEjb.hello("Kyle"));
    }
}

test-application.xml which will be embed as application.xml:

<application>
    <display-name>ear</display-name>
    <module>
        <ejb>ejb-jar.jar</ejb>
    </module>
    <module>
        <web>
            <web-uri>test.war</web-uri>
            <context-root>/test</context-root>
        </web>
    </module>
</application>

Also I have an another example that uses the EAR which Maven has produced because creating EAR with ShrinkWrap would be annoying in some complex cases. the @Deployment method will embed the test WAR into the EAR, and add a module element into existing application.xml before returning the archive to Arquillian runtime. the @Deployment method would be something like this:

...
@Deployment
public static Archive<?> createDeploymentPackage() throws IOException {
    final String testWarName = "test.war";

    final EnterpriseArchive ear = ShrinkWrap.createFromZipFile(
            EnterpriseArchive.class, new File("target/ear-1.0-SNAPSHOT.ear"));

    addTestWar(ear, EarFromZipFileIT.class, testWarName);
...


An example of Maven EAR project consists of an EJB interface, an EJB implementation and a WAR


Posted on Friday Mar 06, 2015 at 10:43PM in Maven


The project consists of following principal modules:

  • eartest-ejb-api: holds an EJB local interface named Hello. packaging=jar. no dependency.

  • eartest-ejb-impl: holds an EJB implementation named HelloImpl which implements Hello. packaging=ejb. depends on eartest-ejb-api.

  • eartest-war: holds an Servlet which has an injection point of Hello interface. depends on eartest-ejb-api.

  • eartest-ear: holds above 3 modules in the EAR.

Whole project is can be obtained from https://github.com/lbtc-xxx/eartest .

Structure of eartest-ear module

$ tree eartest-ear/target/eartest-ear
eartest-ear/target/eartest-ear
|-- META-INF
|   `-- application.xml
|-- eartest-ejb-impl-1.0-SNAPSHOT.jar
|-- eartest-war-1.0-SNAPSHOT.war
`-- lib
    `-- eartest-ejb-api-1.0-SNAPSHOT.jar

2 directories, 4 files

Structure of eartest-war module

$ tree eartest-war/target/eartest-war
eartest-war/target/eartest-war
|-- META-INF
`-- WEB-INF
    `-- classes
        `-- eartest
            `-- war
                `-- MyServlet.class

5 directories, 1 file

MyServlet can reference eartest-ejb-api-1.0-SNAPSHOT.jar because it’s placed under lib directory in the parent EAR. this packaging style is called as Skinny WAR.

Structure of eartest-ejb-api

$ tree eartest-ejb-api/target/classes
eartest-ejb-api/target/classes
`-- eartest
    `-- ejb
        `-- api
            `-- Hello.class

3 directories, 1 file

Structure of eartest-ejb-impl

$ tree eartest-ejb-impl/target/classes
eartest-ejb-impl/target/classes
|-- META-INF
|   `-- ejb-jar.xml
`-- eartest
    `-- ejb
        `-- impl
            `-- HelloImpl.class

4 directories, 2 files

A problem with IntelliJ IDEA

IntelliJ has an annoying issue: Maven support cannot handle skinny wars for EAR deployments : IDEA-97324. this brings unnecessary eartest-ejb-api into WEB-INF/lib inside the WAR and brings following exception. to avoid this, I need to put <scope>provided</scope> in dependency declaration for eartest-ejb-api in pom.xml of eartest-war.

Caused by: java.lang.IllegalStateException: JBAS011048: Failed to construct component instance
	at org.jboss.as.ee.component.BasicComponent.constructComponentInstance(BasicComponent.java:162)
	at org.jboss.as.ee.component.BasicComponent.constructComponentInstance(BasicComponent.java:133)
	at org.jboss.as.ee.component.BasicComponent.createInstance(BasicComponent.java:89)
	at org.jboss.as.ee.component.ComponentRegistry$ComponentManagedReferenceFactory.getReference(ComponentRegistry.java:149)
	at org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$5.createInstance(UndertowDeploymentInfoService.java:1233)
	at io.undertow.servlet.core.ManagedServlet$DefaultInstanceStrategy.start(ManagedServlet.java:215) [undertow-servlet-1.1.0.Final.jar:1.1.0.Final]
	... 27 more
Caused by: java.lang.IllegalArgumentException: Can not set eartest.ejb.api.Hello field eartest.war.MyServlet.hello to eartest.ejb.api.Hello$$$view17
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167) [rt.jar:1.8.0_20]
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171) [rt.jar:1.8.0_20]
	at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81) [rt.jar:1.8.0_20]
	at java.lang.reflect.Field.set(Field.java:758) [rt.jar:1.8.0_20]
	at org.jboss.as.ee.component.ManagedReferenceFieldInjectionInterceptorFactory$ManagedReferenceFieldInjectionInterceptor.processInvocation(ManagedReferenceFieldInjectionInterceptorFactory.java:108)
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.invocation.WeavedInterceptor.processInvocation(WeavedInterceptor.java:53)
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.as.ee.component.AroundConstructInterceptorFactory$1.processInvocation(AroundConstructInterceptorFactory.java:28)
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45) [wildfly-ee-8.2.0.Final.jar:8.2.0.Final]
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:64)
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:326)
	at org.jboss.invocation.PrivilegedWithCombinerInterceptor.processInvocation(PrivilegedWithCombinerInterceptor.java:80)
	at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
	at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
	at org.jboss.as.ee.component.BasicComponent.constructComponentInstance(BasicComponent.java:160)
	... 32 more