Skip to main content

JAX-WS + CDI in Java EE 6

Posted by jitu on February 19, 2010 at 11:35 AM PST


JAX-WS + CDI in Java EE 6

One of the big features in Java EE 6 is dependency injection(yeah, 330 & 299 stuff!!). It pretty much integrated with the every EE component. That means you can nicely use all the CDI features with JAX-WS web services. Let us see a simple shopping cart web service that uses CDI.

@WebService
public class ShoppingCart {
    @Inject
    private CartData cart;

    public List<String> addCart(String item) {
        return cart.addCart(item);
    }
}

@SessionScoped
public class CartData implements Serializable {
    private List<String> items = new ArrayList<String>();

    public List<String> addCart(String item) {
        items.add(item);
        return items;
    }
}

First, you may have noticed the two unfamiliar annotations: @Inject, @SessionScoped. As you may have guessed from @Inject annotation, a CartData instance would be injected into ShoppingCart instance. Right, but what is the lifecycle of a CartData instance ? A CartData instance is tied to a client's HTTP session scope since it uses @SessionScoped annotation. If a client uses the web service after its session expires, the container creates a new CartData instance behind the scenes. One needs to write a lot of code to do this in Java EE 5, now it is that simple in Java EE 6 !

To try the service, let us specify in web.xml that a HTTP session timeout is a minute.

<web-app ...>
    <session-config>
        <session-timeout>1</session-timeout>
    </session-config>
</web-app>

Also, to enable CDI, one needs to package an empty beans.xml. So our war file would like the following:

WEB-INF/beans.xml
WEB-INF/classes/pkg/CartData.class
WEB-INF/classes/pkg/ShoppingCart.class
WEB-INF/web.xml

Note that the above war is portable across all Java EE 6 implementations. Also, the war doesn't contain any wrapper bean classes(usually generated by wsgen). No need to run wsgen and package those classes in a bundle anymore in Java EE 6.

Let us a write a sample client to access the ShoppingCartService and see what happens.

public class Main {

    public static void main(String[] args) throws Exception {    
        ShoppingCart cart = new ShoppingCartService().getShoppingCartPort();
        Map requestContext =
            ((BindingProvider) cart).getRequestContext();
        requestContext.put(
            BindingProvider.SESSION_MAINTAIN_PROPERTY, Boolean.TRUE);

        List<String> items = cart.addCart("mango");
        items = cart.addCart("apple");
        System.out.println("Sleeping 5 secs");
        Thread.sleep(5*1000);
        items = cart.addCart("pear");
        System.out.println("cart ..."+items);
        System.out.println("Sleeping 60 secs. Should create a new cart ...");
        Thread.sleep(60*1000);

        items = cart.addCart("beef");
        items = cart.addCart("chicken");
        System.out.println("Sleeping 5 secs");
        Thread.sleep(5*1000);
        items = cart.addCart("pork");
        System.out.println("cart ..."+items);
    }

}

Client execution output:

cart ...[mango, apple]
Sleeping 5 secs
cart ...[mango, apple, pear]
Sleeping 60 secs. Should create a new cart ...
cart ...[beef, chicken]
Sleeping 5 secs
cart ...[beef, chicken, pork]

As you see the client execution output, new cart is automatically created after a minute. That's it for now, keep exploring the other features of CDI in Java EE 6. Try this in GlassFish v3

Technorati: jaxws metro webservices glassfish v3 cdi jsr299 weld


Comments

Where is your implementation class ShoppingCartService ? You ...

Where is your implementation class ShoppingCartService ? You did not mention anything about the this. Please clarify.

Thanks.

In a JAX-WS SE class I have a field in wich I inject a ...

In a JAX-WS SE class I have a field in wich I inject a @Resource to finally get the client's IP address. All is ok until I make this SE a CDI managed bean

@WebService
public class AImpl implements A {
</pre>
<pre>    @Resource

    private WebServiceContext wsContext;
</pre>
<pre>    @Inject

    private ADelegated delegated;
</pre>
<pre>        ...

}

I deploy this app in a WebLogic 12c and I get this error

java.lang.IllegalArgumentException: Can not set javax.xml.ws.WebServiceContext field AImpl.wsContext to weblogic.jndi.internal.WLEventContextImpl

What is incorrect in my code?