- Defining the service
- Adding customizations
- Generating the code
- Implementing the service
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
getCustomerById- gets a customer id, returns the customer with given id or throws a
NoSuchCustomerExceptionif 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
NoSuchCustomerExceptionif 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
Next, we'll need to write a WSDL file:
JAX-WS binding customizations
In order to simplify the generated code a bit, it may make sense to customize the binding of XML Schema
dateTime types to map onto
java.util.Date instead of
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:
Generating the code
Invoking Hyperjaxb3 from
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.
Here's how this plugin will be configured in our case (within
Note that we'll also need to make configure the
maven-compiler-plugin to the 1.5 compatibility level (
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:
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
Customerclass with JPA annotations.
META-INF/persistence.xml- JPA persistence descriptor generated by Hyperjaxb3.
com/example/customerservice/service- customer service classes.
CustomerServiceis the interface we'll need to implement, it is annotated with JAX-WS annotations.
org/w3/_2001/xmlschema- artificial package with
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:
Since Hyperjaxb3 has turned the
Customer class into a compliant JPA entity, we can implement the customer service as a simple JPA DAO:
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:
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
What we need to do next is to configure the customer service and to add the JAX-WS endpoint for this service:
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
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.
First of all, let's check that our application starts at all:
This test uses the web application configuration from the
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:
To use this "testing"
applicationContext.xml we'll need to add a testing configuration of the web application:
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
After that we can use the customer service to perform some operations - insert, retrieve and remove the customer. Here's the full test:
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