JAXBElement types generated when schema contain minOccurs=”0″ and nillable=”true”

November 1, 2009

Problem

JAXB is great for generating JAVA code necessary to support marshalling and unmarshalling of XML to Java Pojo’s particularly when working with web services. However with some WSDL’s the Java code generated contain JAXBElement types instead of Java data types. For example a schema fragment from a Salesforce notification wsdl:

        <schema elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:sobject.enterprise.soap.sforce.com">
            <import namespace="urn:enterprise.soap.sforce.com"/>
            <!-- Base sObject (abstract) -->
            <complexType name="sObject">
                <sequence>
                    <element name="fieldsToNull" type="xsd:string" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
                    <element name="Id" type="ent:ID" nillable="true" minOccurs="0" maxOccurs="1"/>
                </sequence>
            </complexType>
            <complexType name="Opportunity">
                <complexContent>
                    <extension base="ens:sObject">
                        <sequence>
                        <element name="Sales_Opportunity_Number__c" nillable="true" minOccurs="0" type="xsd:string"/>
                        </sequence>
                    </extension>
                </complexContent>
            </complexType>
        </schema>

would generate the following corresponding Java code fragments:

public class Opportunity
    extends SObject
{

    @XmlElementRef(name = "Sales_Opportunity_Number__c", namespace = "urn:sobject.enterprise.soap.sforce.com", type = JAXBElement.class)
    protected JAXBElement<String> salesOpportunityNumberC;

    /**
     * Gets the value of the salesOpportunityNumberC property.
     *
     * @return
     *     possible object is
     *     {@link JAXBElement }{@code <}{@link String }{@code >}
     *
     */
    public JAXBElement<String> getSalesOpportunityNumberC() {
        return salesOpportunityNumberC;
    }

    /**
     * Sets the value of the salesOpportunityNumberC property.
     *
     * @param value
     *     allowed object is
     *     {@link JAXBElement }{@code <}{@link String }{@code >}
     *
     */
    public void setSalesOpportunityNumberC(JAXBElement<String> value) {
        this.salesOpportunityNumberC = ((JAXBElement<String> ) value);
    }
}

The JAXBElementsalesOpportunityNumberC type is a bit cumbersome to work with your Java code.

Solution

A simple solution to this problem is to edit a copy of your wsdl. Do the following:

  • Replace all nillable=”true” to nillable=”false”

The desired side effect of this generating Java code with the desired Java types in place. See corresponding example:

public class Opportunity
    extends SObject
{

    @XmlElement(name = "Sales_Opportunity_Number__c", namespace = "urn:sobject.enterprise.soap.sforce.com")
    protected String salesOpportunityNumberC;

    /**
     * Gets the value of the SalesOpportunityNumberC property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getSalesOpportunityNumberC() {
        return salesOpportunityNumberC;
    }

    /**
     * Sets the value of the salesOpportunityNumberC property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setSalesOpportunityNumberC(String value) {
        this.salesOpportunityNumberC = value;
    }

}

Props

Brian Dussault and Julie Dougherty word on this problem and came up with the solution documented and currently used by my team.

Spring Web Service Client – EightBallDemo

September 22, 2009

Introduction

This is a followup to my previous blog on Spring Web Service’s with JAXB, Maven & Eclipse and the Magic 8-Ball demo as a sample. Here we will use that sample web service and write a web service client that will call the Magic 8-Ball demo service. Again we will use Spring Web Services to implement this web service client.

For Spring Web Services clients Spring continues to leverage its use of the Template pattern and provide “helper methods to perform common operations, and for more sophisticated usage, delegate to user implemented callback interfaces…various convenience methods for the sending and receiving of XML messages, marshalling objects to XML before sending, and allows for multiple transport options.” See Spring Web Service Client. As usual Spring provides the application infrastructure allowing you to focus on the core application logic: in our case calling the Magic 8-Ball web services and getting back the response.

We will also reuse some of the artifacts we used to build the Magic 8-Ball demo service; specifically the JAXB marshalling and unmarshalling class generated from the eightball.xsd which defined the data contract for the Magic 8-Ball demo service.

Assumptions

  • You have an instance of the 8-Ball Web service running in Java container (i.e., Tomcat) and is accessible by URL:
  • http://localhost:8080/eightball/

Tools User
We are using an updated tool set for this sample:

Project

In STS use File/New/Project…/Maven Project

  1. Select Default workspace
  2. Select spring-ws-archtype
  3. Enter client8ball for Group Id
  4. Enter client8ball for Artifact Id
  5. Select Finish
  6. Selecting the POM.XML under the dependencies tab add dependencies in the Tools Used section above
    • Add spring-oxm-tiger dependency
    • Add spring-ws-core-tiger dependency
POM Dependencies

POM Dependencies

Leveraging the Contract

Using the JAXB Artifacts

Spring Web Services implement the Contract First design pattern. As part of the previous Magic 8-Ball example we used JAXB to generate the Java classes to support the marshalling and unmarshalling of our XML requests and response documents as specified in our XSD which defined our contract. In this example we are going to leverage the same JAXB artifacts in support of the Spring Web Service client’s marshalling and unmarshalling.

  1. Create the package jaxb.eightball under the resource folder src/main/java
  2. Import the JAXB Java files under the jaxb.eightball package.
  3. JAXB Artifacts

Application Context

Using Springs Inversion of Control (IoC) we are going to wire up our JAXB artifacts and soon to be written Web Service Client.

  1. In the resource folder src/main/resources/ edit the file application-context.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-2.0.xsd">

    <bean id="eightBallClient" class="client8ball.client8ball.EightBallClient">
<property name="defaultUri" value="http://localhost:8080/eightball"/>
<property name="marshaller" ref="marshaller"/>
<property name="unmarshaller" ref="marshaller"/>
    </bean>

     <bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">
         <constructor-arg ref="marshaller" />
     </bean>     

     <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
	<list>
                <value>jaxb.eightball.EightBallRequest</value>
                <value>jaxb.eightball.EightBallResponse</value>
             </list>
         </property>
     </bean>
</beans>

  • In the application-context.xml file we define our Magic 8-Ball client bean. eightballclient. We inject the:
    • default uri, marshaller, unmarshaller
  • We define our end-point marshaller using the Spring provided class org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter
  • We define our marshaller and the specific JAXB beans to be used:
    • jaxb.eightball.EightBallRequest
    • jaxb.eightball.EightBallResponse

Magic 8-Ball Client Bean

  1. In the resource folder src/main/java create a new package client8ball.client8ball
  2. In this package create a new class EightBallClient which extends WebServiceGatewaySupport
  3. Define the Request resource.
  4. Define our method AskQuestion which will invoke our Magic 8-Ball Web Service and return its response.
    • Using a the webservicegateway method
      response =  (EightBallResponse)getWebServiceTemplate().marshalSendAndReceive(request);
      

      we invoke the Magic 8-Ball service and return the response

package client8ball.client8ball;

import java.io.IOException;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.core.io.Resource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import jaxb.eightball.EightBallRequest;
import jaxb.eightball.EightBallResponse;

public class EightBallClient extends WebServiceGatewaySupport {

	private Resource request;
	public void setRequest(Resource request){
		this.request = request;
	}
	public String AskQuestion(String question) throws IOException{
		String responseString = null;

		EightBallRequest request = new EightBallRequest();
		request.setQuestion(question);

		EightBallResponse response = new EightBallResponse();

		response =  (EightBallResponse)getWebServiceTemplate().marshalSendAndReceive(request);
		responseString = response.getAnswer().toString();
		return responseString;
	}
}

Testing

Now to test our Web Service Client. We could have created our EightBallClient.java with a main and written code to exercise our web service client. Instead we’ll write a Unit Test using Springs built-in support of JUnit.

JUnit Test

  1. In the resource folder src/test/java in the package client8ball.client8ball create a unit test by selecting the package and then pressing the right mouse button and selecting New/JUnit Test Case
  2. Fill in the wizard specifying:
    1. The Name of TestClient8Ball
    2. Selecting constructor
    3. Specifying the Class under test: as client8ball.client8ball.EightBallClient
    4. JUnit Test Case for Client8Ball

    5. After selecting the Next>> button :
      1. Select the method AskQuestion and then select the Finish button
  3. To implement our testAskQuestion method we will:
    1. Load up the application context from the application-context.xml and EightBallClient.class
    2. We create an instance of the EightBallClient
    3. Now we invoke the client and Ask our Question
    4. Lastly we assess the response to our question

package client8ball.client8ball;

import java.io.IOException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import junit.framework.TestCase;

public class TestClient8Ball extends TestCase {

public TestClient8Ball(String name) {
super(name);
}

public void testAskQuestion() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("../../applicationContext.xml", EightBallClient.class);
EightBallClient client8Ball = (EightBallClient) applicationContext.getBean("eightBallClient");
try {
String answer = client8Ball.AskQuestion("Will This Work");
assertNotNull(answer);
System.out.println("The Answer is: " + answer);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
}

}

BE SURE YOUR Magic 8-Ball Web Service is up and running in you container (i.e., http://localhost:8080/eightball)

  • Test and have fun.

Project Code

You can download Client8Ball Source

Spring Web Service’s with JAXB, Maven & Eclipse

April 14, 2009

Acknowledgements

Technorati Profile

Before I get started I wish to acknowledge the work of others that greatly assisted me in my understanding of Spring Web Services. I encourage readers to reach out to these sources as well.

Contract Last vs Contract First

There are two development styles for developing web services using Java. With contract-last you start with your Java code and from that you generate the web service contract (WSDL – web service definition language). When using the contract first you start with the WSDL or contract and use Java to implement a service to meet this contract.

Spring-WS only supports contract-first development style.
For more information on contract-first ; much of the information paraphrased here is explored in greater detail.

Problems with Contract Last

From experience and for me the most important difficulties with Contract Last are:

  • Language specific (proprietary) types can become exposed in a XSD and are not portable to other languages.
    • Example Java TreeMap type would not be understood correctly by .NET or Python and would result in a different data type instantiated with differing semantics.
  • Code == Contract. Increased Fragility since the WSDL contract is directly generated from the Java code thereby resulting in a change in WSDL contract with any change in the Java code. This is not desirable.
    • Contracts should be as stable as long as possible
  • Performance resulting from XML generated from Java code.
  • XSD reuse is difficult if not impossible.

Benefits of Contract-First

  • By focusing on the contract and in particular the XSD that defines the contract you implement a more robust WSDL contract that can support changes in the Java code that implements the contract. That is the WSDL contract and Java contract are loosely coupled.
    • The contract is stable over a longer period of time
  • By focusing on what is needed in the XML to support the WSDL contract a much better performing XML message is implemented.
  • XSD components are reusable across other WSDL contracts therefore increasing the re-usability of the SOA artifacts.
    • This of course is dependent upon the XML design pattern chosen to implement the XSD. For an extensive and well thought exploration of this topic refer to Roger L. Costello’s discussion of Schemas

Tools Used

For our example a number of tools are used. Briefly I mention them here.

Spring Web Services

  • The contract is defined by the XML schema (XSD) of the services’ messages
  • The Service contract (i.e., WSDL) will be generated from the XSD
  • Each Spring-WS has an end point which handles the incoming XML documents and manages the outgoing XML response documents
  • Each end point will require a business service to operate
    • This business service is defined as an interface
    • The business service interface_ is implemented by a business service class
  • These dependencies are injected by Springs IoC with metadata defined in the spring-ws-servlet.xml
    • All the components are wired together by the configurations specified in spring-ws-servlet.xml context.

Sample: Magic 8 Ball

The following example is based on the old toy Magic 8-ball which allows as question to be asked and magically 1 of 20 possible answers return as a response to the query. Our sample web service using Spring WS with JAXB will do just this.

The Contract

We focus on the data contract between our client and service and define this with in an XML Schema; our XSD.   Using a simple Russian Doll design pattern we have two elements; a request and a response.  The request involves a question and the reponse an answer.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://acompany.com/it/enterprise/DEPT/EightBall/v1" xmlns:tns="http://acompany.com/it/enterprise/DEPT/EightBall/v1" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified" attributeFormDefault="unqualified">
	<xs:element name="eightBallRequest">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Question" type="xs:string"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:element name="eightBallResponse">
		<xs:complexType>
			<xs:sequence>
				<xs:element name="Answer" type="xs:string"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

Marshalling/Unmarshalling:JAXB

Not only does our XSD define our data contract between the client and service it is used by JAXB to generate the marshalling and unmarshalling code that our service uses to handle the XML messages.

  1. With your XSD in the bin directory of you JAXB installation run the xjc tool to generate the JAVA class for marshalling and unmarshalling.
  2. You can us the -p switch and specify a simple package name for your JAXB JAVA code. In our example jaxb.eightball. The default package name is the XSD target namespace

C:\jaxb-ri-20070122\bin>xjc.bat -p jaxb.eightball eightball.xsd
parsing a schema…
compiling a schema…
jaxb\eightball\EightBallRequest.java
jaxb\eightball\EightBallResponse.java
jaxb\eightball\ObjectFactory.java
jaxb\eightball\package-info.java

Eclipse Project using Maven 2

  1. In Eclispe use File/New/Project…/Maven Project
  2. Select Default workspace
  3. Select spring-ws-archtype
  4. Enter eightballdemo for Group Id
  5. Enter eightballdemo for Artifact Id
  6. Select Finish
  7. Selecting the POM.XML under the dependencies tab add the log4j POM dependencies in the Tools Used section above
    • Add spring-oxm-tiger dependency
    • Add spring-ws-core-tiger dependency
  8. POM Dependencies

Exposing the Contract

  • Import eightball.xsd in src/main/webapp/WEB-INF
  • Edit spring-ws-servlet.xml and add the following for Spring to generate the WSDL at runtime from the XSD file:
  •    <!-- Add automatic WSDL generation support -->
        <bean id="eightball" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
    <property name="schema" ref="schema" />
    <property name="portTypeName" value="eightball" />
    <property name="locationUri" value="http://localhost:8080/eightball/" />
    <property name="targetNamespace" value="http://acompany.com/it/enterprise/DEPT/EightBall/v1" />
        </bean>  
    
        <bean id="schema" class="org.springframework.xml.xsd.SimpleXsdSchema">
    <property name="xsd" value="/WEB-INF/eightball.xsd" />
        </bean>
    

Preparing for Code

  1. Add a Source Folder to your project: src/main/java
  2. Add the following packages to this Source Folder
    • ws – web service end point
    • jaxb.eightballJAXB marshalling and unmarshalling classes
    • service – interface for class that contains service logic
    • service.impl – class that implements service logic
  3. Import the JAXB Java files generated under the jaxb.eightball package.
  4. JAXB for Eightball

EndPoint

First Part

  • In spring-ws-servlet.xml define the web service endpoint using annotations along with the service interface and implementation.
  • <!-- Register PayloadRootAnnotationMethodEndpointMapping -->  
        <bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" />  
      
        <!-- Register Endpoint -->  
        <bean id="eightBallEndpoint" class="ws.EightBallEndpoint">
        <description>
                This endpoint handles requests.
            </description>
            <property name="eightBallService" ref="eightBallService"/>
        </bean>  
        
         <bean id="eightBallService" class="service.impl.EightBallServiceImpl">
            <description>
                This bean is our "business" service.
            </description>
        </bean>
        
    

  • Now create the end point class EightBallEndPoint in the ws package
  • package ws;
    import service.EightBallService;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.ws.server.endpoint.annotation.Endpoint;
    import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
    
    import jaxb.eightball.EightBallRequest;
    import jaxb.eightball.EightBallResponse;
    
    @Endpoint
    public class EightBallEndpoint {
    	
    	private EightBallService eightBallService;
    	protected final Log logger = LogFactory.getLog(getClass());
    	
    	/**
    	 * Sets the "business service" to delegate to.
    	 */
    	public void setEightBallService(EightBallService eightBallService) {
    		this.eightBallService = eightBallService;
    	}....
    

Service: EightBallService

  • Define the interface EightBallService in the package service
  • package service;
    
    public interface EightBallService {
    
    	String question (String s);
    }
    

Wire In the JAXB

  • In spring-ws-servlet.xml add the following wiring for the JAXB marshalling and unmarshalling.
  •      <!-- Configure XML Marshaller -->  
        <bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">  
            <constructor-arg ref="marshaller" />  
        </bean>  
      
        <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">  
            <property name="classesToBeBound">  
                <list>  
                    <value>jaxb.eightball.EightBallRequest</value>  
                    <value>jaxb.eightball.EightBallResponse</value> 
                </list>  
            </property>  
        </bean> 
    

  • In EightBallEndPoint add the following annotation based section for marshalling and unmarshalling.
  • 
    	@PayloadRoot(localPart= "eightBallRequest", namespace="http://acompany.com/it/enterprise/DEPT/EightBall/v1")
    	public EightBallResponse doit(EightBallRequest request){
    
    		String question = request.getQuestion();
    		System.out.println("The question is " + question);
    		logger.info("The question is " + question);
    		String answer = eightBallService.question(question);
    		logger.info("The answer is " + answer);
    		EightBallResponse response = new EightBallResponse();
    		response.setAnswer(answer);
    		return response;
    	}
    }
    

EightBallServiceImpl

  • Create the Class EightBallServiceImpl implementing the interface EightBallService
  • package service.impl;
    
    import java.util.ArrayList;
    import java.util.Random;
    
    import service.EightBallService;
    
    public class EightBallServiceImpl implements EightBallService {
    
    	public String question (String s) {
    		Random rand = new Random();
    		ArrayList<String> answers = new ArrayList<String>(20);
    		answers.add(0, "As I see it, yes");
    		answers.add(1, "It is certain");
    		answers.add(2,"It is decidedly so" );
    		answers.add(3,"Most likely");
    		answers.add(4,"Outlook good");
    		answers.add(5, "Signs point to yes");
    		answers.add(6, "Without a doubt");
    		answers.add(7, "Yes");
    		answers.add(8, "Yes - definitely");
    		answers.add(9, "You may rely on it");
    		answers.add(10,"Reply hazy, try again");
    		answers.add(11,"Better not tell you now");
    		answers.add(12,"Cannot predict now");
    		answers.add(13,"Concentrate and ask again");
    		answers.add(14,"Don't count on it");
    		answers.add(15,"My reply is no");
    		answers.add(16,"My sources say no");
    		answers.add(17,"Outlook not so good");
    		answers.add(18,"Very doubtful");
    		answers.add(19, "Ask again later");
    
    		int iNum = rand.nextInt(20);
    		return answers.get(iNum).toString();
    	}
    }
    
    
    

Package and Test

We are now done should be ready to compile, package and test our service. I strongly recommended using SoapUI for testing your web service.

  • On the project eightballdemo right mouse-button
    • Select Run As
    • Select Maven package
  • You can deploy your eightball.war to your Tomcat servlet container
  • From SoapUI you can create a project and import the WSDL from your Tomcat Instance
  • http://localhost:8080/eightball/eightball.wsdl

  • Test and have fun

Project Code

You can download Eclipse Project Zip file


Follow

Get every new post delivered to your Inbox.