Hands-On Cloud Development with WildFly
上QQ阅读APP看书,第一时间看更新

Fraction detection

Let's return to our latest CatalogService. As you recall, it uses JAX-RS and CDI. We have provided the dependencies manually by editing the pom.xml file:

(...)

<dependencies>
<!-- 1 -->
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>jaxrs</artifactId>
<version>${version.wildfly.swarm}</version>
</dependency>

<!-- 2 -->
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>cdi</artifactId>
<version>${version.wildfly.swarm}</version>
</dependency>
</dependencies>

(...)

We have provided dependencies for two fractions: JAX-RS (1) and CDI (2). We can run the application and note that it is indeed working.

Let's continue our experiment now. What happens if we configure only one fraction?

(...)
<dependencyManagement>
<dependencies>
<!-- 2 -->
<dependency>
<groupId>org.jboss.spec</groupId>
<artifactId>jboss-javaee-7.0</artifactId>
<version>${version.jboss.spec.javaee.7.0}</version>
<type>pom</type>
<scope>import</scope>
</dependency
>
</dependencies>
</dependencyManagement>

<dependencies>

<!-- 1 -->
<dependency>
<groupId>org.wildfly.swarm</groupId>
<artifactId>jaxrs</artifactId>
<version>${version.wildfly.swarm}</version>
</dependency>

<!-- 2 -->
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

(...)

In the preceding code, only the JAX-RS dependency is configured (1). Note that in such a case we have to explicitly define a dependency on CDI-API (2). When we run the application, we see the following log:

You will see no errors yet, but the first few lines of your log already foretell that problems will occur. Although CDI is used, its fractions (and its dependents) have not been added. If we get into a browser and enter the address of our service, we will see a bad request error. Add a temporary log to service class:

package org.packt.swarm.petstore.catalog;

import org.jboss.logging.Logger;
import org.packt.swarm.petstore.catalog.model.Item;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@Path("/")
public class CatalogResource {

private final Logger log = Logger.getLogger(getClass());

@Inject
private CatalogService catalogService;

@GET
@Path("item/{itemId}")
@Produces(MediaType.APPLICATION_JSON)
public Response searchByName(@PathParam("itemId") String itemId) {
try {
Item item = catalogService.searchById(itemId);
return Response.ok(item).build();
} catch (Exception e) {
log.error("BAD REQUEST", e);
return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
}
}

}

We will be able to note the cause of our problem:

ERROR [org.packt.swarm.petstore.catalog.CatalogResource] (default task-1) Bad request: java.lang.NullPointerException
at org.packt.swarm.petstore.catalog.CatalogResource.searchByName(CatalogResource.java:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:140)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:295)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:249)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:236)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:406)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:213)
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:228)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)

Owing to missing CDI fraction, bean resolution and injection were not performed. As a result, the service object was not injected into the CatalogResource resource, resulting in NullPointerException.

Let's get one step further and remove all the fractions:


<dependencies>
<!-- 2 -->
<dependency>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- 1 -->
<!-- no fractions here ... -->

</dependencies>

(...)

We have removed all the fractions (1). Please note that in such a case we have to provide all of the Java EE APIs manually (2).

Example reference: chapter3/catalog-service-auto-detect/.

When we build the project configured this way, we will see something interesting in the log:

In the preceding example, Swarm has performed automatic fraction detection. How does it work?

Swarm found out that org.packt.swarm.petstore.catalog.CatalogResource is using the classes from the javax.ws.rs package, which resulted in the inclusion of JAX-RS. Similarly, usage of the javax.inject package led to the inclusion of the CDI fraction. Later, as in manual examples, Swarm has a build service that contains the detected fractions, their dependencies, and fractions that are always needed. If you run the service now, you will note that it is indeed working correctly.

In order to understand why Swarm behaved in the described way in the recent examples, we must learn about fraction detection mode. Let's do it now.