About Blaise Doughan

Team lead for the TopLink/EclipseLink JAXB & SDO implementations, and the Oracle representative on those specifications.

Leveraging MOXy in your Web Service via JAX-WS Provider

In previous articles I demonstrated how EclipseLink JAXB (MOXy) is directly integrated into the JAX-WS implementations in WebLogic (as of 12.1.1) and in GlassFish (as of 3.1.2). In this post I’ll demonstrate how to leverage MOXy in any application server by using the JAX-WS Provider class.

Web Service

The Provider mechanism in JAX-WS provides you a way to create a Web Service with direct access to the XML. Through the @ServiceMode annotation you can specify whether you want all of the XML from the message or just the payload.
 

FindCustomerService

All the magic happens in the invoke method. Since we specified PAYLOAD as the service mode the input will be an instance of Source that represents the body of the message. All JAXB (JSR-222) implementations can unmarshal from a Source so we will do that to realize the request. After we perform our business logic we need to return the body of the response as an instance of Source. To achieve this we will wrap our response objects in an instance of JAXBSource.

package blog.jaxws.provider;

import javax.xml.bind.*;
import javax.xml.bind.util.JAXBSource;
import javax.xml.transform.Source;
import javax.xml.ws.*;

@ServiceMode(Service.Mode.PAYLOAD)
@WebServiceProvider(
    portName = 'FindCustomerPort', 
    serviceName = 'FindCustomerService', 
    targetNamespace = 'http://service.jaxws.blog/', 
    wsdlLocation = 'WEB-INF/wsdl/FindCustomerService.wsdl')
public class FindCustomerService implements Provider<Source> {

    private JAXBContext jaxbContext;

    public FindCustomerService() {
        try {
            jaxbContext = JAXBContext.newInstance(FindCustomerResponse.class,
                    FindCustomerRequest.class);
        } catch (JAXBException e) {
            throw new WebServiceException(e);
        }
    }

    @Override
    public Source invoke(Source request) throws WebServiceException {
        try {
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            FindCustomerRequest fcRequest = (FindCustomerRequest) unmarshaller
                    .unmarshal(request);

            Customer customer = new Customer();
            customer.setId(fcRequest.getArg0());
            customer.setFirstName('Jane');
            customer.setLastName('Doe');

            FindCustomerResponse response = new FindCustomerResponse();
            response.setValue(customer);

            return new JAXBSource(jaxbContext, response);
        } catch (JAXBException e) {
            throw new WebServiceException(e);
        }
    }

}

MOXy as the JAXB Provider

To specify that MOXy should be used as the JAXB provider we need to include a file called jaxb.properties that is located in the same package as our domain model with the following entry (see: Specifying EclipseLink MOXy as your JAXB Provider).

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

WSDL

Below is the WSDL that corresponds to our Web Service. One draw back to using the Provider approach is that the JAX-WS implementation can’t automatically generate one for us (see: GlassFish 3.1.2 is full of MOXy (EclipseLink JAXB)). A WSDL is necessary as it defines a contract for the client. It can even be used to generate a client.

<?xml version='1.0' encoding='UTF-8'?>
<definitions 
    xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd' 
    xmlns:wsp='http://www.w3.org/ns/ws-policy' 
    xmlns:wsp1_2='http://schemas.xmlsoap.org/ws/2004/09/policy' 
    xmlns:wsam='http://www.w3.org/2007/05/addressing/metadata' 
    xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/' 
    xmlns:tns='http://service.jaxws.blog/' 
    xmlns:xsd='http://www.w3.org/2001/XMLSchema' 
    xmlns='http://schemas.xmlsoap.org/wsdl/' 
    targetNamespace='http://service.jaxws.blog/' 
    name='FindCustomerService'>
    <types>
        <xsd:schema>
            <xsd:import 
                namespace='http://service.jaxws.blog/' 
                schemaLocation='FindCustomerService.xsd'/>
        </xsd:schema>
    </types>
    <message name='findCustomer'>
        <part name='parameters' element='tns:findCustomer'/>
    </message>
    <message name='findCustomerResponse'>
        <part name='parameters' element='tns:findCustomerResponse'/>
    </message>
    <portType name='FindCustomer'>
        <operation name='findCustomer'>
            <input 
                wsam:Action='http://service.jaxws.blog/FindCustomer/findCustomerRequest' 
                message='tns:findCustomer'/>
            <output 
                wsam:Action='http://service.jaxws.blog/FindCustomer/findCustomerResponse' 
                message='tns:findCustomerResponse'/>
        </operation>
    </portType>
    <binding name='FindCustomerPortBinding' type='tns:FindCustomer'>
        <soap:binding 
            transport='http://schemas.xmlsoap.org/soap/http' 
            style='document'/>
            <operation name='findCustomer'>
                <soap:operation soapAction=''/>
                <input>
                    <soap:body use='literal'/>
                </input>
                <output>
                    <soap:body use='literal'/>
                </output>
        </operation>
    </binding>
    <service name='FindCustomerService'>
        <port name='FindCustomerPort' binding='tns:FindCustomerPortBinding'>
            <soap:address location='http://localhost:8080/Blog-JAXWS/FindCustomerService'/>
        </port>
    </service>
</definitions>

XML Schema

Below is the XML schema that corresponds to the payload of our message. One draw back to using the Provider approach is that the JAX-WS implementation can’t leverage JAXB directly to automatically generate the XML schema directly, so we need to supply one.

<?xml version='1.0' encoding='UTF-8'?>
<xsd:schema 
    xmlns:ns0='http://service.jaxws.blog/' 
    xmlns:xsd='http://www.w3.org/2001/XMLSchema'
    targetNamespace='http://service.jaxws.blog/'>
    <xsd:element name='findCustomerResponse' 
        type='ns0:findCustomerResponse' />
    <xsd:complexType name='findCustomerResponse'>
        <xsd:sequence>
            <xsd:element name='return' type='ns0:customer'
                minOccurs='0' />
        </xsd:sequence>
    </xsd:complexType>
    <xsd:element name='findCustomer' 
        type='ns0:findCustomer' />
    <xsd:complexType name='findCustomer'>
        <xsd:sequence>
            <xsd:element name='arg0' type='xsd:int' />
        </xsd:sequence>
    </xsd:complexType>
    <xsd:complexType name='customer'>
        <xsd:sequence>
            <xsd:element name='personal-info' minOccurs='0'>
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element name='first-name' 
                            type='xsd:string'
                            minOccurs='0' />
                        <xsd:element name='last-name'
                            type='xsd:string'
                            minOccurs='0' />
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
        </xsd:sequence>
        <xsd:attribute name='id' type='xsd:int' use='required' />
    </xsd:complexType>
</xsd:schema>

Request Objects

The highlighted portion of the XML message below is what we are going to receive in our Provider as in instance of Source. We will create a JAXB model to map to this section.

<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S='http://schemas.xmlsoap.org/soap/envelope/'>
    <S:Header/>
    <S:Body>
        <ns2:findCustomer xmlns:ns2='http://service.jaxws.blog/'>
            <arg0>123</arg0>
        </ns2:findCustomer>
    </S:Body>
</S:Envelope>

FindCustomerRequest

The root element is in a different XML namespace than the rest of the body. We will leverage the @XmlRootElement annotation to specify the namespace (see: JAXB & Namespaces ).

package blog.jaxws.provider;

import javax.xml.bind.annotation.*;

@XmlRootElement(
    namespace='http://service.jaxws.blog/', 
    name='findCustomer')
public class FindCustomerRequest {

    private int arg0;

    public int getArg0() {
        return arg0;
    }

    public void setArg0(int arg0) {
        this.arg0 = arg0;
    }

}

Response Objects

The highlighted portion of the XML message below is what we are going to return from our Provider as in instance of Source. We will create a JAXB model to map to this section.

<S:Envelope xmlns:S='http://schemas.xmlsoap.org/soap/envelope/'>
    <S:Header />
    <S:Body>
        <ns0:findCustomerResponse 
            xmlns:ns0='http://service.jaxws.blog/'>
            <return id='123'>
                <personal-info>
                    <first-name>Jane</first-name>
                    <last-name>Doe</last-name>
                </personal-info>
            </return>
        </ns0:findCustomerResponse>
    </S:Body>
</S:Envelope>

FindCustomerResponse

package blog.jaxws.provider;

import javax.xml.bind.annotation.*;

@XmlRootElement(namespace='http://service.jaxws.blog/')
public class FindCustomerResponse {

    private Customer value;

    @XmlElement(name='return')
    public Customer getValue() {
        return value;
    }

    public void setValue(Customer value) {
        this.value = value;
    }

}

Customer

One of the many reasons to use MOXy is its path based mapping (see: XPath Based Mapping). Below is an example of how it is specified using the @XmlPath annotation.

package blog.jaxws.provider;

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlType(propOrder = { 'firstName', 'lastName' })
public class Customer {

    private int id;
    private String firstName;
    private String lastName;

    @XmlAttribute
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @XmlPath('personal-info/first-name/text()')
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    @XmlPath('personal-info/last-name/text()')
    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

}

 

Reference: Leveraging MOXy in your Web Service via JAX-WS Provider from our JCG partner Blaise Doughan at the Java XML & JSON Binding blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

One Response to "Leveraging MOXy in your Web Service via JAX-WS Provider"

  1. Tirupati says:

    Dear Blaise,

    Thanks for all your posts, which are very helpful.

    Currently I am working on a mobility project consuming the webservices. I am using the approach of generating the stubs by using wsimport and JAX Context generating classes by using XJC.

    I am able to Invoke Webservice Operation With the simple type, There are two more Webservices with the ComplexTypes where I need to Pass Parameters(Attribute and ComplexType Object). Bu=y using AnnotationIntrospector I am able to see the Newly Created Object Instance(with all the Setted Values) but while passing this Object instance to the WebService opration, It looks like passing Null values. Please guide me to achive this.

    Sharing the Invoking class and other details. Please let me know if you need anymore details.

    Invoking Class :

    package custom.com.concept.evlution.main;

    import java.io.IOException;
    import javax.xml.bind.JAXBElement;
    import javax.xml.bind.JAXBException;
    import org.codehaus.jackson.JsonGenerationException;
    import org.codehaus.jackson.map.AnnotationIntrospector;
    import org.codehaus.jackson.map.JsonMappingException;
    import org.codehaus.jackson.map.ObjectMapper;
    import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;
    import org.datacontract.schemas._2004._07.musanada_concept_events_contracts.FEVENTSDto;
    import com.microsoft.schemas._2003._10.serialization.ObjectFactory;
    import uk.co.fsi.services.evolution._04._09.ITaskEventsService;
    import uk.co.fsi.services.evolution._04._09.TaskEventsService;

    public class CreateEventServiceTest {

    public static void main(String[] args) throws JAXBException, JsonGenerationException, JsonMappingException, IOException, InstantiationException {
    if (args.length != 2) {
    System.out.println(“You Need to Pass UserID and Password”);
    } else {
    String userID = args[0];
    String sessionID = args[1];

    System.out.println(“::: INSIDE the UPDATE EVENT Service ::::”+userID);
    System.out.println(“::: INSIDE the UPDATE EVENT Service ::::”+sessionID);

    ObjectFactory objectFactory = new ObjectFactory();
    JAXBElement evEvent = objectFactory.createString((String) “[E] Re-assigned to Contractor”);
    Integer taskSeq = 56932;

    ObjectMapper mapper = new ObjectMapper();
    AnnotationIntrospector intro = new JaxbAnnotationIntrospector();
    mapper.setAnnotationIntrospector(intro);

    FEVENTSDto eventObject = new FEVENTSDto();
    eventObject.setEVFKEYTASEQ(taskSeq);
    eventObject.setEVEVENT(evEvent);

    /**
    * Getters, Setters and JAXB Context converter.
    **/

    String result = mapper.writeValueAsString(eventObject);

    System.out.println(“:::: PRINTING EVENT OBJECT ::::”+result);
    TaskEventsService varEventService = new TaskEventsService();
    ITaskEventsService varTaskPort = varEventService.getTaskEventsService();
    varTaskPort.createEvent(sessionID, eventObject);
    }
    }
    }

    Thanks..

    Regards,

    Tirupati

Leave a Reply


nine + = 11



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close