Статьи

Использование MOXy в вашем веб-сервисе через JAX-WS Provider

В предыдущих статьях я демонстрировал, как EclipseLink JAXB (MOXy) напрямую интегрируется в реализации JAX-WS в WebLogic (по состоянию на 12.1.1) и в GlassFish (по состоянию на 3.1.2) . В этой статье я продемонстрирую, как использовать MOXy на любом сервере приложений с помощью класса провайдера JAX-WS.

Веб-сервис

Механизм Provider в JAX-WS предоставляет вам способ создания веб-службы с прямым доступом к XML. С помощью аннотации @ServiceMode вы можете указать, хотите ли вы весь XML из сообщения или только полезную нагрузку.

FindCustomerService

Вся магия происходит в методе invoke . Так как мы указали PAYLOAD в качестве сервисного режима, входные данные будут экземпляром Source, который представляет тело сообщения. Все реализации JAXB (JSR-222) могут демонтироваться из источника, поэтому мы сделаем это для реализации запроса. После того, как мы выполним нашу бизнес-логику, нам нужно вернуть тело ответа как экземпляр Source . Чтобы достичь этого, мы обернем наши объекты ответа в экземпляр JAXBSource .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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);
        }
    }
 
}

МОКСИ как провайдер JAXB

Чтобы указать, что MOXy должен использоваться в качестве провайдера JAXB, нам нужно включить файл с именем jaxb.properties, который находится в том же пакете, что и наша модель домена, со следующей записью (см. Определение EclipseLink MOXy в качестве вашего провайдера JAXB ).

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

WSDL

Ниже приведен WSDL, соответствующий нашему веб-сервису. Одним из недостатков использования подхода Provider является то, что реализация JAX-WS не может автоматически сгенерировать его для нас (см. GlassFish 3.1.2 полон MOXy (EclipseLink JAXB) ). WSDL необходим, поскольку он определяет контракт для клиента. Он даже может быть использован для генерации клиента.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?xml version='1.0' encoding='UTF-8'?>
<definitions
    xmlns:wsp='http://www.w3.org/ns/ws-policy'
    xmlns:tns='http://service.jaxws.blog/'
    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-схема

Ниже приведена схема XML, которая соответствует полезной нагрузке нашего сообщения. Одним из недостатков использования подхода Provider является то, что реализация JAX-WS не может напрямую использовать JAXB для автоматической генерации XML-схемы, поэтому нам необходимо предоставить ее.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?xml version='1.0' encoding='UTF-8'?>
<xsd:schema
    xmlns:ns0='http://service.jaxws.blog/'
    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>

Объекты запроса

Выделенная часть XML-сообщения ниже — это то, что мы собираемся получить в нашем провайдере, как в случае с источником . Мы создадим модель JAXB для сопоставления с этим разделом.

1
2
3
4
5
6
7
8
9
<?xml version='1.0' encoding='UTF-8'?>
    <S:Header/>
    <S:Body>
        <ns2:findCustomer xmlns:ns2='http://service.jaxws.blog/'>
            <arg0>123</arg0>
        </ns2:findCustomer>
    </S:Body>
</S:Envelope>

FindCustomerRequest

Корневой элемент находится в другом пространстве имен XML, чем остальная часть тела. Мы будем использовать аннотацию @XmlRootElement для указания пространства имен (см .: JAXB & Namespaces ).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
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;
    }
 
}

Объекты ответа

Выделенная часть XML-сообщения ниже — это то, что мы собираемся вернуть нашему провайдеру, как в случае с источником . Мы создадим модель JAXB для сопоставления с этим разделом.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
    <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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
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;
    }
 
}

Клиент

Одной из многих причин использования MOXy является его отображение на основе пути (см .: XPath Based Mapping ). Ниже приведен пример того, как это указано с помощью аннотации @XmlPath .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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;
    }
 
}

Ссылка: Использование MOXy в вашем веб-сервисе через провайдера JAX-WS от нашего партнера по JCG Блэза Дафана из блога Java XML & JSON Binding .