Child pages
  • Apache CXF Tutorial - Building JAX-WS, JAXB and JPA-based web service with Apache CXF, Spring and Hyperjaxb3
Skip to end of metadata
Go to start of metadata
Icon

Since 0.5.5.

Introduction

This tutorial demonstrates the usage of Hyperjaxb3 with Apache CXF in a WSDL-first scenario.

Assume we need to implement a very simple "customer service" as a JAX-WS service; this service must provide following operations to manage customer instances:

  • getCustomerById - gets a customer id, returns the customer with given id or throws a NoSuchCustomerException if customer could not be found;
  • updateCustomer - gets the customer object, inserts or updates it in the the database, returns the customer id;
  • deleteCustomerById - gets a customer id and removes the customer object from the database or throws NoSuchCustomerException if customer with this id could not be found.

In this tutorial we'll use Apache CXF to build this service. We'll use JPA for the persistence layer whereas entity annotations will be generated by Hyperjaxb3.

Defining the service

First of all we'll need to define the service.

The customer schema

We'll start with the XML schema for customer objects:

src/main/wsdl/customer.xsd

WSDL

Next, we'll need to write a WSDL file:

src/main/wsdl/CustomerService.wsdl

Adding customizations

JAX-WS binding customizations

In order to simplify the generated code a bit, it may make sense to customize the binding of XML Schema date and dateTime types to map onto java.util.Date instead of javax.xml.datatype.XMLGregorianCalendar:

src/main/wsdl/binding.xml

Hyperjaxb3 binding customizations

If you look at the generated files, you may notice that Hyperjaxb3 has generated annotation not only in the com.example.customerservice.model.Customer class, but also in the classes of the com.example.customerservice.service package (com.example.customerservice.service,GetCustomerById and so on). Since we only want to persiste the customer, the latter is not desirable, so we'll need to customize the bindings in order to disable Hyperjaxb3 for the com.example.customerservice.service package. To achieve this, we'll need to use the hj:ignored-package customization (see Ignoring packages for more information).

Another customization would be to use the customerId element as identifier property (see Selecting the identifier property for more information).

Finally, we'll enable eager fetching by default with hj:default-one-to-many element (see Customizing default mappings for more information).

Below is the binding.xjb file with these customizations:

src/main/wsdl/binding.xjb

Generating the code

Invoking Hyperjaxb3 from cxf-codegen-plugin

Apache CXF implements WSDL-to-Java code generation with the cxf-codegen-plugin. Hyperjaxb3 can be invoked from this plugin as a normal XJC plugin.

Icon

See the Using Hyperjaxb3 with Apache CXF for more information.

Here's how this plugin will be configured in our case (within project/build/plugins):

A fragment of pom.xml/build/plugins

Note that we'll also need to make configure the maven-compiler-plugin to the 1.5 compatibility level (project/build/pluginManagement):

A fragment of pom.xml/project/build/pluginManagement

Since Hyperjaxb3 generates certain resources which must be included into the resulting artifact (for instance, the META-INF/persistence.xml descriptor), we have to configure the resources of our build:

A fragment of pom.xml/project/build

What was generated?

Now if you generate the sources using the mvn clean generate-sources command, CXF will create the target/generated-sources/cxf directory with the following sub-directories:

  • com/example/customerservice/model - customer model classes. Hyperjaxb3 has annotated the Customer class with JPA annotations.
  • META-INF/persistence.xml - JPA persistence descriptor generated by Hyperjaxb3.
  • com/example/customerservice/service - customer service classes. CustomerService is the interface we'll need to implement, it is annotated with JAX-WS annotations.
  • org/w3/_2001/xmlschema - artificial package with date and dateTime adapters.

Implementing the service

Writing the service implementation

During the code generation step CXF has generated the customer service interface which we'll need to implement for the server side. Here's this interface (annotations are removed for better readability:

CustomerService.java

Since Hyperjaxb3 has turned the Customer class into a compliant JPA entity, we can implement the customer service as a simple JPA DAO:

CustomerServiceImpl.java

Configuring the service

Application context configuration

Now that customer service is implemented, we'll need to configure this service in the Spring application context.

First of all, we'll need to configure the persistence layer: data source, entity manager factory, transaction manager:

applicationContext.xml

Note the usage of the com.example.customerservice.model persistence unit - this persistence unit was generated by Hyperjaxb3.

In this sample setup we use an embedded HSQLDB database which will be stored under WEB-INF/database directory of the web application. The org.jvnet.hyperjaxb3.ejb.samples.customerservicecxf.webAppRoot property will be provided by the org.springframework.web.util.WebAppRootListener configured in the web.xml.

What we need to do next is to configure the customer service and to add the JAX-WS endpoint for this service:

web.xml configuration

In the web.xml we'll need to configure the CXFServlet with the appropriate application context:

A minor addition is the WebAppRootListener which exposes the location of the web application via the webAppRootKey property. As mentione above, we'll need this in order to place the HSQLDB database files under WEB-INF/database.

Testing the service

Now it's high time to do some testing. I will not demonstrate unit testing since it's quite trivial. Instead, we'll take a look into integration testing, with a real server instance.

For this purpose we'll use the Hifaces20 Testing package which provides convenient infrastructure for starting a servlet container (like Jetty) directly from tests.

Smoke test

First of all, let's check that our application starts at all:

ApplicationStartsIT.java

This test uses the web application configuration from the main-web.properties file:

src/test/resource/main-web.properties

If everything is configured allright, the application should start without any problems.

More thorough customer service test

Now let's implement a more complicated test which inserts, queries and deletes a customer. For such a test, it makes sense to create a "test" configuration of the application which uses an in-memory HSQL database instead of the file-based configured by default:

src/test/resources/com/example/customerservice/service/test/applicationContext.xml

To use this "testing" applicationContext.xml we'll need to add a testing configuration of the web application:

Fragment of src/test/webapp/web.xml
src/test/resources/test-web.properties

Note the webapp.home pointing to a different web app location.

Now we can implement the test. First of all we'll need to create the client-side instance of the customer service. We'll do this manually using the JaxWsProxyFactoryBean:

After that we can use the customer service to perform some operations - insert, retrieve and remove the customer. Here's the full test:

CustomerServiceIT.java

Configuring integration tests in the Maven build

The integration tests we've implemented won't run by default in Maven builds. In order to invoke them, we'll need to configure the maven-failsafe-plugin in the integration-test phase:

pom.xml/project/build/plugins

Resources

TODO

  • No labels