Apache CXF Tutorial - Building JAX-WS, JAXB and JPA-based web service with Apache CXF, Spring and Hyperjaxb3
| 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:
<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>
WSDL
Next, we'll need to write a WSDL file:
<?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>
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:
<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>
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:
<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>
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.
| 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):
<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.5 compatibility level (project/build/pluginManagement):
<plugins> <plugin> <inherited>true</inherited> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</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:
<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>
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:
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:
@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(); } }
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:
<?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" 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>
web.xml configuration
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" 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"> <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>
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:
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:
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.
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:
<?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:
<?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>
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:
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()); } }
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:
<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>
Resources
TODO