-
Notifications
You must be signed in to change notification settings - Fork 99
HyperJAXB3 Apache CXF Tutorial Building JAX WS, JAXB and JPA based web service with Apache CXF, Spring and Hyperjaxb3
Since 0.5.5.
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 aNoSuchCustomerException
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 throwsNoSuchCustomerException
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.
First of all we'll need to define the service.
We'll start with the XML schema for customer
objects:
src/main/wsdl/customer.xsd
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://customerservice.example.com/model"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
targetNamespace="http://customerservice.example.com/model">
<xs:complexType name="customer">
<xs:sequence>
<xs:element name="customerId" type="xs:int" minOccurs="0"/>
<xs:element minOccurs="0" name="name" type="xs:string" />
<xs:element maxOccurs="unbounded" minOccurs="0" name="address"
nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="numOrders" type="xs:int" />
<xs:element name="revenue" type="xs:double" />
<xs:element minOccurs="0" name="test" type="xs:decimal" />
<xs:element minOccurs="0" name="birthDate" type="xs:date" />
<xs:element minOccurs="0" name="type" type="tns:customerType" />
</xs:sequence>
</xs:complexType>
<xs:simpleType name="customerType">
<xs:restriction base="xs:string">
<xs:enumeration value="PRIVATE" />
<xs:enumeration value="BUSINESS" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
Next, we'll need to write a WSDL file:
src/main/wsdl/CustomerService.wsdl
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="CustomerServiceService"
targetNamespace="http://customerservice.example.com/service"
xmlns:tns="http://customerservice.example.com/service"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://customerservice.example.com/service"
xmlns:cns="http://customerservice.example.com/model"
attributeFormDefault="unqualified"
elementFormDefault="qualified"
targetNamespace="http://customerservice.example.com/service">
<xs:import schemaLocation="customer.xsd" namespace="http://customerservice.example.com/model" />
<!-- ... -->
<xs:element name="getCustomerById" type="tns:getCustomerById" />
<xs:complexType name="getCustomerById">
<xs:sequence>
<xs:element minOccurs="0" name="customerId" type="xs:int" />
</xs:sequence>
</xs:complexType>
<xs:element name="getCustomerByIdResponse" type="tns:getCustomerByIdResponse" />
<xs:complexType name="getCustomerByIdResponse">
<xs:sequence>
<xs:element minOccurs="0" name="return" type="cns:customer" />
</xs:sequence>
</xs:complexType>
<!-- ... -->
<xs:element name="updateCustomer" type="tns:updateCustomer" />
<xs:complexType name="updateCustomer">
<xs:sequence>
<xs:element minOccurs="0" name="customer" type="cns:customer" />
</xs:sequence>
</xs:complexType>
<xs:element name="updateCustomerResponse" type="tns:updateCustomerResponse" />
<xs:complexType name="updateCustomerResponse">
<xs:sequence>
<xs:element minOccurs="0" name="customerId" type="xs:int" />
</xs:sequence>
</xs:complexType>
<!-- ... -->
<xs:element name="deleteCustomerById" type="tns:deleteCustomerById" />
<xs:complexType name="deleteCustomerById">
<xs:sequence>
<xs:element minOccurs="0" name="customerId" type="xs:int" />
</xs:sequence>
</xs:complexType>
<!-- ... -->
<xs:element name="NoSuchCustomer" type="tns:NoSuchCustomer" />
<xs:complexType name="NoSuchCustomer">
<xs:sequence>
<xs:element name="customerId" nillable="true" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:schema>
</wsdl:types>
<wsdl:message name="getCustomerById">
<wsdl:part name="parameters" element="tns:getCustomerById"/>
</wsdl:message>
<wsdl:message name="getCustomerByIdResponse">
<wsdl:part name="parameters" element="tns:getCustomerByIdResponse"/>
</wsdl:message>
<wsdl:message name="updateCustomer">
<wsdl:part name="parameters" element="tns:updateCustomer"/>
</wsdl:message>
<wsdl:message name="updateCustomerResponse">
<wsdl:part name="parameters" element="tns:updateCustomerResponse"/>
</wsdl:message>
<wsdl:message name="deleteCustomerById">
<wsdl:part name="parameters" element="tns:deleteCustomerById"/>
</wsdl:message>
<wsdl:message name="NoSuchCustomerException">
<wsdl:part name="NoSuchCustomerException" element="tns:NoSuchCustomer"/>
</wsdl:message>
<wsdl:portType name="CustomerService">
<wsdl:operation name="updateCustomer">
<wsdl:input name="updateCustomer" message="tns:updateCustomer"/>
<wsdl:output name="updateCustomerResponse" message="tns:updateCustomerResponse"/>
</wsdl:operation>
<wsdl:operation name="deleteCustomerById">
<wsdl:input name="deleteCustomerById" message="tns:deleteCustomerById"/>
<wsdl:fault name="NoSuchCustomerException" message="tns:NoSuchCustomerException"/>
</wsdl:operation>
<wsdl:operation name="getCustomerById">
<wsdl:input name="getCustomerById" message="tns:getCustomerById"/>
<wsdl:output name="getCustomerByIdResponse" message="tns:getCustomerByIdResponse"/>
<wsdl:fault name="NoSuchCustomerException" message="tns:NoSuchCustomerException"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="CustomerServiceServiceSoapBinding"
type="tns:CustomerService">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="updateCustomer">
<soap:operation soapAction="" style="document" />
<wsdl:input name="updateCustomer">
<soap:body use="literal" />
</wsdl:input>
<wsdl:output name="updateCustomerResponse">
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="deleteCustomerById">
<soap:operation soapAction="" style="document" />
<wsdl:input name="deleteCustomerById">
<soap:body use="literal" />
</wsdl:input>
<wsdl:fault name="NoSuchCustomerException">
<soap:fault name="NoSuchCustomerException" use="literal" />
</wsdl:fault>
</wsdl:operation>
<wsdl:operation name="getCustomerById">
<soap:operation soapAction="" style="document" />
<wsdl:input name="getCustomerById">
<soap:body use="literal" />
</wsdl:input>
<wsdl:output name="getCustomerByIdResponse">
<soap:body use="literal" />
</wsdl:output>
<wsdl:fault name="NoSuchCustomerException">
<soap:fault name="NoSuchCustomerException" use="literal" />
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="CustomerServiceService">
<wsdl:port name="CustomerServicePort" binding="tns:CustomerServiceServiceSoapBinding">
<soap:address location="http://localhost:8080/CustomerServicePort" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
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
<jaxws:bindings
wsdlLocation="CustomerService.wsdl"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<jaxws:bindings node="wsdl:definitions/wsdl:types/xs:schema">
<jaxb:globalBindings>
<jaxb:javaType name="java.util.Date" xmlType="xs:dateTime"
parseMethod="org.apache.cxf.tools.common.DataTypeAdapter.parseDateTime"
printMethod="org.apache.cxf.tools.common.DataTypeAdapter.printDateTime"/>
<jaxb:javaType name="java.util.Date" xmlType="xs:date"
parseMethod="org.apache.cxf.tools.common.DataTypeAdapter.parseDate"
printMethod="org.apache.cxf.tools.common.DataTypeAdapter.printDate"/>
</jaxb:globalBindings>
</jaxws:bindings>
</jaxws:bindings>
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
<jaxb:bindings version="1.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:hj="http://hyperjaxb3.jvnet.org/ejb/schemas/customizations"
xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
jaxb:extensionBindingPrefixes="xjc hj orm"
xmlns:test="urn:test">
<jaxb:bindings schemaLocation="customer.xsd" node="/xsd:schema">
<hj:ignored-package name="com.example.customerservice.service"/>
<hj:persistence>
<hj:default-one-to-many fetch="EAGER"/>
</hj:persistence>
<jaxb:bindings node="xsd:complexType[@name='customer']/xsd:sequence/xsd:element[@name='customerId']">
<hj:id>
<orm:generated-value strategy="AUTO"/>
</hj:id>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
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.
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
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>2.2.6</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
<configuration>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/wsdl/CustomerService.wsdl</wsdl>
<bindingFiles>
<bindingFile>${basedir}/src/main/wsdl/binding.xml</bindingFile>
<bindingFile>${basedir}/src/main/wsdl/binding.xjb</bindingFile>
</bindingFiles>
<extraargs>
<extraarg>-xjc-XhashCode</extraarg>
<extraarg>-xjc-Xequals</extraarg>
<extraarg>-xjc-Xhyperjaxb3-ejb</extraarg>
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.5.3</version>
</dependency>
<dependency>
<groupId>org.jvnet.hyperjaxb3</groupId>
<artifactId>hyperjaxb3-ejb-plugin</artifactId>
<version>0.5.5</version>
</dependency>
</dependencies>
</plugin>
Note that we'll also need to make configure the maven-compiler-plugin
to the 1.8 compatibility level (project/build/pluginManagement
):
A fragment of pom.xml/project/build/pluginManagement
<plugins>
<plugin>
<inherited>true</inherited>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
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
<resources>
<resource>
<directory>src/main/wsdl</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>target/generated-sources/cxf</directory>
<includes>
<include>META-INF/persistence.xml</include>
</includes>
</resource>
</resources>
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 theCustomer
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 withdate
anddateTime
adapters.
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
public interface CustomerService {
public Customer getCustomerById(Integer customerId) throws NoSuchCustomerException;
public Integer updateCustomer(Customer customer);
public void deleteCustomerById(Integer customerId) throws NoSuchCustomerException;
}
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
@Transactional
public class CustomerServiceImpl extends JpaDaoSupport implements
CustomerService {
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void deleteCustomerById(final Integer customerId)
throws NoSuchCustomerException {
final Customer customer = getCustomerById(customerId);
getJpaTemplate().remove(customer);
}
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public Customer getCustomerById(final Integer customerId)
throws NoSuchCustomerException {
final Customer customer = getJpaTemplate().find(Customer.class,
customerId);
if (customer == null) {
NoSuchCustomer noSuchCustomer = new NoSuchCustomer();
noSuchCustomer.setCustomerId(customerId);
throw new NoSuchCustomerException(
"Did not find any matching customer for id [" + customerId
+ "].", noSuchCustomer);
} else {
return customer;
}
}
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public Integer updateCustomer(Customer customer) {
final Customer mergedCustomer = getJpaTemplate().merge(customer);
return mergedCustomer.getCustomerId();
}
}
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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:soap="http://cxf.apache.org/bindings/soap"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<bean
class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer" />
<!-- ... -->
<bean name="javax.persistence.EntityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="javax.sql.DataSource" />
<property name="persistenceUnitName" value="com.example.customerservice.model" />
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" />
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
</props>
</property>
</bean>
<bean name="javax.sql.DataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url"
value="jdbc:hsqldb:file:${org.jvnet.hyperjaxb3.ejb.samples.customerservicecxf.webAppRoot:target/temp}/WEB-INF/database/database" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean name="org.springframework.transaction.PlatformTransactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="javax.persistence.EntityManagerFactory" />
</bean>
<tx:annotation-driven
transaction-manager="org.springframework.transaction.PlatformTransactionManager" />
</beans>
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:
<jaxws:endpoint
name="com.example.customerservice.service.CustomerServiceServer"
xmlns:customer="[http://customerservice.example.com/service"](https://web.archive.org/web/20150926050825mp_/http://customerservice.example.com/service)
address="/CustomerServicePort"
serviceName="customer:CustomerServiceService"
endpointName="customer:CustomerServiceEndpoint">
<jaxws:implementor>
<ref bean="com.example.customerservice.service.CustomerService" />
</jaxws:implementor>
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature" />
</jaxws:features>
</jaxws:endpoint>
<bean name="com.example.customerservice.service.CustomerService"
class="com.example.customerservice.service.CustomerServiceImpl">
<property name="entityManagerFactory" ref="javax.persistence.EntityManagerFactory" />
</bean>
In the web.xml
we'll need to configure the CXFServlet
with the appropriate application context:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
version="2.4"
xmlns="[http://java.sun.com/xml/ns/j2ee"](https://web.archive.org/web/20150926050825mp_/http://java.sun.com/xml/ns/j2ee) xmlns:xsi="[http://www.w3.org/2001/XMLSchema-instance"](https://web.archive.org/web/20150926050825mp_/http://www.w3.org/2001/XMLSchema-instance)
xsi:schemaLocation="[http://java.sun.com/xml/ns/j2ee](https://web.archive.org/web/20150926050825mp_/http://java.sun.com/xml/ns/j2ee) [http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"](https://web.archive.org/web/20150926050825mp_/http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd)>
<display-name>CXF Customer Service Sample</display-name>
<!-- ... -->
<servlet>
<servlet-name>org.apache.cxf.transport.servlet.CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<init-param>
<param-name>config-location</param-name>
<param-value>classpath:com/example/customerservice/service/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>org.apache.cxf.transport.servlet.CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
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
.
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>org.jvnet.hyperjaxb3.ejb.samples.customerservicecxf.webAppRoot</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.WebAppRootListener</listener-class>
</listener>
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:
ApplicationStartsIT.java
public class ApplicationStartsIT {
@Rule
public MethodRule webAppEnvironmentRule = WebAppEnvironmentRule.INSTANCE;
@PropertiesWebAppEnvironmentConfig("src/test/resources/main-web.properties")
public WebAppEnvironment webAppEnvironment;
@Test
public void checkApplicationStarts() throws IOException{
Assert.assertTrue(webAppEnvironment.isStarted());
Assert.assertNotNull(URLUtils.getContentAsString(new URL(webAppEnvironment.getBaseUrl() + "/CustomerServicePort?wsdl")));
}
}
This test uses the web application configuration from the main-web.properties
file:
src/test/resource/main-web.properties
webapp.host=127.0.0.1
webapp.port=8080
webapp.contextPath=
webapp.home=src/main/webapp
If everything is configured allright, the application should start without any problems.
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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<import resource="classpath*:com/example/customerservice/service/applicationContext.xml"/>
<bean name="javax.sql.DataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url"
value="jdbc:hsqldb:mem:WEB-INF/database/database" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
</beans>
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
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- ... -->
<servlet>
<servlet-name>org.apache.cxf.transport.servlet.CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<init-param>
<param-name>config-location</param-name>
<param-value>
classpath:com/example/customerservice/service/test/applicationContext.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- ... -->
</web-app>
src/test/resources/test-web.properties
webapp.host=127.0.0.1
webapp.port=8080
webapp.contextPath=
webapp.home=src/test/webapp
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
:
final JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
jaxWsProxyFactoryBean.setServiceClass(CustomerService.class);
jaxWsProxyFactoryBean.setAddress(webAppEnvironment.getBaseUrl()
+ "/CustomerServicePort");
final CustomerService customerService = (CustomerService) jaxWsProxyFactoryBean
.create();
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
public class CustomerServiceIT {
@Rule
public MethodRule webAppEnvironmentRule = WebAppEnvironmentRule.INSTANCE;
@PropertiesWebAppEnvironmentConfig("src/test/resources/test-web.properties")
public WebAppEnvironment webAppEnvironment;
@Test
public void checkCustomerService() throws Exception {
final JaxWsProxyFactoryBean jaxWsProxyFactoryBean = new JaxWsProxyFactoryBean();
jaxWsProxyFactoryBean.setServiceClass(CustomerService.class);
jaxWsProxyFactoryBean.setAddress(webAppEnvironment.getBaseUrl()
+ "/CustomerServicePort");
final CustomerService customerService = (CustomerService) jaxWsProxyFactoryBean
.create();
final Customer originalCustomer = new Customer();
// originalCustomer.setCustomerId(1);
originalCustomer.setName("Scott Tiger");
originalCustomer.getAddress().add("Hauptstr. 6");
originalCustomer.getAddress().add("76133 Karlsruhe");
originalCustomer.getAddress().add("Germany");
originalCustomer.setNumOrders(15);
originalCustomer.setRevenue(1234.56);
originalCustomer.setTest(BigDecimal.valueOf(7890));
originalCustomer.setBirthDate(DataTypeAdapter.parseDate("1970-01-01"));
originalCustomer.setType(CustomerType.BUSINESS);
final Integer customerId = customerService
.updateCustomer(originalCustomer);
assertNotNull(customerId);
final Customer retrievedCustomer = customerService
.getCustomerById(customerId);
assertEquals(originalCustomer.getName(), retrievedCustomer.getName());
assertEquals(originalCustomer.getAddress(), retrievedCustomer
.getAddress());
customerService.deleteCustomerById(retrievedCustomer.getCustomerId());
}
}
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
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<id>integration-test</id>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
</plugin>
TODO
- Home
- Migration guide
-
JAXB Maven Plugin
- Quick Start
-
User Guide
- Basic Usage
- Specifying What To Compile
- Referencing Resources in Maven Artifacts
- Using Catalogs
- Using Episodes
- Modular Schema Compilation
- Controlling the Output
- Using JAXB Plugins
- Using a Specific JAXB Version
- Configuring Extension, Validation and XML Security
- IDE Integration
- Miscellaneous
- Configuring Proxies
- Maven Documentation
- Configuration Cheat Sheet
- Common Pitfalls and Problems
-
JAXB2 Basics Plugins
- Using JAXB2 Basics Plugins
- JSR-305 Support
-
JAXB2 Basics Plugins List
- SimpleEquals Plugin
- SimpleHashCode Plugin
- Equals Plugin
- HashCode Plugin
- ToString Plugin
- Copyable Plugin
- Mergeable Plugin
- Inheritance Plugin
- AutoInheritance Plugin
- Wildcard Plugin
- Setters Plugin
- Simplify Plugin
- EnumValue Plugin
- JAXBIndex Plugin
- FixJAXB1058 Plugin
- Commons Lang Plugin
- Default Value Plugin
- Fluent API Plugin
- Namespace Prefix Plugin
- Value Constructor Plugin
- Boolean Getter Plugin
- CamelCase Plugin
- XML ElementWrapper Plugin
- Parent Pointer Plugin
- Property Listener Injector Plugin
- Annox
- JAXB Annotate Plugin
-
HyperJAXB3
- Build System Support
- Customization Guide
- Databases
- Development guide
- Extension guide
- FAQ
- IDE Support
- Java Persistence
- JAXB
- JDK Support
- Project Templates
-
Reference
- Adding vendor-specific annotations
- Features
- Integrating Hyperjaxb3 in builds
- Introduction
- Making schema-derived classes ready for JPA
- Adding required properties
- Applying workarounds for JAXB vs. JPA conflicts
- Enforcing top-level classes
- Generating equals and hashCode methods
- Generating ORM metadata
- Generating persistence unit descriptor
- JPA 2 Support
- Making classes serializable
- Testing generated mappings
- Reference - single page
- Related Projects
- Sample projects
- Solutions
- Target Scenarios
- Test Projects
- Tutorials
- Best Practices
- FAQ
- Sample Projects
- Support
- License
- Distribution