JEE : Using EJB and Context annotations in a JAX-RS Provider class

A lot of new annotations have been introduced since the JEE6 spec. Before we had EJBs and servlets to cover most of our server-side objects in a JEE application. But in JEE6, CDI and JAX-RS have been added, along with a few other JSRs that are implemented using annotations. This results in a long list of annotations, where – in my opinion – it is not always clear which one to use, nor to understand how they work together.

In this blog, I would like to show you how EJB and CDI work or don’t work together, in combination with a JAX-RS Resource.

JAX-RS is used for writing REST-services. It allows you to create these services, simply by annotating a Java class.

This is our REST service class aka “resource class”. It will create a REST service on the /test url, an it returns a String. Here, for test purposes, we always generate a RuntimeException.


@Path("/test")
public class TestResource {
@GET
public String getCustomer() {
if (1==1) throw new RuntimeException("Whoops, something goes wrong");

return "Customer ABC";
}
}

Because we don’t want to send a stack trace to the client, but a meaningful response in the form of an Error class, we use a provider class and annotate it with @Provider (javax.ws.rs.ext.Provider). This annotation is part of the JAX-RS spec.

Annotating a class with @Provider – according to the API-documentation – “marks an implementation of an extension interface that should be discoverable by JAX-RS runtime during a provider scanning phase.”

Our provider class will catch any exception thrown by the resource class, and send a proper response object to the client instead.

The returned Error class, that will be marshalled to an xml object and returned to the client :

@XmlRootElement

public class Error {
private String desc;
public Error() {
super();
}

public Error(String desc) {
super();
this.desc = desc;
}

public String getDesc() {
return desc;
}

public void setDesc(String desc) {
this.desc = desc;
}

}

The provider class that will catch any exception and return the error class looks like :


@Provider

public class GenericExceptionMapper implements ExceptionMapper<Exception> {

@Context HttpServletRequest httpRequest;

public Response toResponse(Exception ex) {
return Response.status(500).entity(new Error("Error during call with method : "+httpRequest.getMethod())).build();

}

}

As you can, see, we use the @Context annotation to access the current http request. When an exception is thrown by the resource class, it will automatically be handled by the toResponse method of our provider class. It returns a response, containing the Error class, that will be sent to the client in xml format. This is done by the JAX-RS framework.

Now we have an EJB bean that we want to use in order to log this error to a database, before sending the response. So we will add this to the provider class as follows :


@Stateless

@Provider

public class GenericExceptionMapper implements ExceptionMapper<Exception> {

@Context HttpServletRequest httpRequest;

@EJB ErrorEJB errorEJB;

public Response toResponse(Exception ex) {
// log the error to the database
errorEJB.logError(ex));
// return the response
return Response.status(500)
.entity(new Error("Error during call with method : "+httpRequest.getMethod()))
.build();
}

We made the GenericExceptionMapper a stateless bean using @Stateless, in order to be able to inject the ErrorEJB into the provider.

But now, we will get a NullPointerException on the httpRequest.getMethod, as the @Context annotation won’t work  anymore.

This is because, before our update, we only used the @Provider annotation , so this class was a CDI bean. With CDI, the container looks up the injected classes in a “scope”, which will basically be a hashmap that exists for a specific period of time :

  • @RequestScoped : per request
  • @SessionScoped : per HTTP session
  • @ApplicationScoped : per application

Into that environment we can inject the HttpServletRequest using the @Context annotation

By adding the @Statefull annotation, we made an EJB from our CDI bean.

With EJBs, the container looks also into a hashmap, but checks if the bean is of type @Stateful, @Stateless or @Singleton. So it isn’t aware of any http context.

In order to solve this problem, we will inject the our ErrorEJB as CDI bean iso an EJB.

This can be done as follows :

  • replace the @Stateless by @RequestScoped
  • replace @EJB by @Inject
  • adding an empty beans.xml file to the WEB-INF

Which gives us :


@RequestScoped

@Provider

public class GenericExceptionMapper implements ExceptionMapper<Exception> {

@Context HttpServletRequest httpRequest;

@Inject ErrorEJB errorEJB;

public Response toResponse(Exception ex) {

errorEJB.logError(ex));

return Response.status(500)
.entity(new Error("Error during call with method : "+httpRequest.getMethod()))
.build();

}

Now for JEE7, there are even more annotations available, so make sure to check the docs before using them.

Oracle Forms File drag and drop javaBean

I created a JavaBean that implements a “dropbox” in Oracle Forms.
It can be downoaded from the PJC/JavaBean library of Francois Degrelle.

When dropping one or more files on it, Forms receives the path and filename of it.
In the following example video the JavaBean is used to upload a file to the database.
For the uploading part I used Webutil.