Table of Contents

JAXB / JAX-WS / JAX-RS

Questions answered

JAX-RS

How to implement dynamic content negotiation?

From Runtime content negotiation:

Controller.java

import java.util.List;
 
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.Variant;
 
import org.springframework.stereotype.Controller;
 
@Controller
public class Controller {
 
    private static final List<Variant> SUPPORTED_MEDIA_TYPES = Variant
                .mediaTypes(MediaType.APPLICATION_XML_TYPE, MediaType.APPLICATION_JSON_TYPE, MediaType.TEXT_PLAIN_TYPE)
                .build();
 
    @GET
    @Path("/process")
    public Response process(@Context Request request) {
        Variant variant = request.selectVariant(SUPPORTED_MEDIA_TYPES);
 
        if (variant == null) {
            return Response.notAcceptable(SUPPORTED_MEDIA_TYPES).build();
        }
 
        Object bean = ...; // some POJO, e.g. JAXB-annotated
        // XML or JSON are marshalled by the container, but plain text is evaluated somehow differently:
        return Response.ok(variant.getMediaType() == MediaType.TEXT_PLAIN_TYPE ? bean.toString() : bean, variant.getMediaType().withCharset("UTF-8")).
            build();
    }
}

JAX-WS

The sources are generated OK, but I get the compilation problem.

The error reported might look like:
DocumentInquiryService.java:[68,20] cannot find symbol
symbol  : method getPort(javax.xml.namespace.QName,java.lang.Class<DocumentInquiryPortType>,javax.xml.ws.WebServiceFeature[])
location: class javax.xml.ws.Service

JAX-WS v2.1 refers some new classes and annotations, which are not part of JDK prior to v1.6.0_04. You need to put jaxb-api.jar and jaxws-api-2.1.jar to $JAVA_HOME/lib/endorsed (e.g. for Windows it might be C:\Program Files\JAVA\jdk1.6.0_03\jre\lib\endorsed\). Make sure maven is using this very Java installation.

What JDK versions include what JAX-WS API version?

  • JDK 1.6.0 includes JAX-WS 2.0 API.
  • JDK 1.6.0_04 includes JAXB and JAX-WS 2.1 API. It is back-compatible with JAX-WS 2.0. You can use v2.1.x XJC generator and with minor efforts port it to JAXB 2.0 API (@XmlElementRef was added an extra attribute, javax.xml.ws.Service implementations have more extended interface, …).
    • JDK 1.6.0_14 includes JAXB 2.1.10 and JAX-WS 2.1.6 runtime.
  • JDK 7 includes JAXP 1.4.5, JAXB 2.2.4, JAX-WS 2.2.4.
  • JDK 8 includes JAXB 2.2.8.

More information:

Sun SAAJ implementation is not compatible with IBM JDK

It is known problem, as Sun SAAJ implementation depends on reallocated Xerces classes. See Ref Impl does not work with IBM JDK, SAAJ test cases no longer work with IBM's SDK.

Alternative SOAP implementations are listed in Alternative to Sun SAAJ SOAP implementation.

How to use catalogs with JAX-WS?

When I use wsimport I got the error message “src-resolve: Cannot resolve the name 'soapenc:Array' to a(n) 'type definition' component”.

Why JAX-WS generates faultInfo?

From Faults and exceptions in JAX-WS:

JAX-WS generator generates the exception, and the JAXB generator generates the Java bean containing the exception's data.

How to use proxy with jaxws-maven-plugin?

Due to issue#57 httpproxy configuration option is not correctly passed to wsimport. Workarounds are:
  • To use args configuration option to pass the setting correctly:
    <configuration>
        ...
        <args>
            <arg>-httpproxy:proxy:8080</arg>
        </args>
    </configuration>
  • To define JVM-wide proxy at maven execution or define system property MAVEN_OPTS="-Dhttp.proxyHost=proxy -Dhttp.proxyPort=8080"

How to define connection and request timeouts for the client?

In fact, the proxy returned by any getPort() function is an instance of com.sun.xml.ws.client.sei.SEIStub and implements javax.xml.ws.BindingProvider:
import javax.xml.ws.BindingProvider;
import com.sun.xml.ws.developer.JAXWSProperties;
 
// 3 seconds (in milliseconds) to open a connection:
private static final Integer CONNECT_TIMEOUT = Integer.valueOf(3000);
// 10 seconds (in milliseconds) to retrieve the data from connection:
private static final Integer REQUEST_TIMEOUT = Integer.valueOf(10000);
...
 
MyPortType myPort = new MyService().getMyPort();
 
Map<String, Object> context = ((BindingProvider) myPort).getResponseContext();
 
context.put(JAXWSProperties.CONNECT_TIMEOUT, CONNECT_TIMEOUT);
context.put(JAXWSProperties.REQUEST_TIMEOUT, REQUEST_TIMEOUT);


How to get attachments for the received response?

In fact, the proxy returned by any getPort() function is an instance of com.sun.xml.ws.client.sei.SEIStub and implements javax.xml.ws.BindingProvider:
import javax.activation.DataHandler;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.MessageContext;
 
MyPortType myPort = new MyService().getMyPort();
 
Map<String, DataHandler> attachments = (Map<String, DataHandler>) ((BindingProvider) myPort).getResponseContext().get(MessageContext.INBOUND_MESSAGE_ATTACHMENTS);
 
DataHandler dataHandler = attachments.values().iterator().next();
... = dataHandler.getInputStream();

How to deal with large MIME attachments in SOAP messages?

Starting from SAAJ RI 1.3.4 it is possible to enable MimePull parser via System.setProperty("saaj.use.mimepull", "true"). See Creating SOAPMessages with Very Large XML Payload and SAAJ-31.

How can I see the SOAP messages send between client and server? Is there any way to dump them?

For client part enable system property -Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true, for server part -Dcom.sun.xml.ws.transport.http.HttpAdapter.dump=true

How can I intersect SOAP messages send between client and server and pipe them to another client?

Are JAX-WS client proxies thread safe?

Generally not (check here as well). Pooling client proxies is far from perfect workaround, as JAX-WS runtime model is not shared among client proxies (which means you will loose memory not even per WSDL, but per WS operation).

How can I test the newly developed WebService?

  • You can use Spring SimpleJaxWsServiceExporter helper bean to export your WebService endpoints for example:
    <?xml version="1.0"?>
    <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.5.xsd">
     
        <!-- Instantiate the bean manually or you can use @Service annotation + <context:component-scan /> -->
        <bean name="providerWS" class="org.mycompany.ws.MyProviderImpl" />
     
        <!-- This utility bean will scan all context beans for @WebService annotation and publish them on the given port: -->
        <bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter">
            <property name="baseAddress" value="http://localhost:8999/" />
        </bean>
     
        <!--
            The helper bean that is a factory of WS client instances that implement the given interface.
            Check WSDL file for concrete values for "serviceName" and "portName".
        -->
        <bean name="providerWSClient" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
            <property name="serviceInterface" value="org.mycompany.ws.api.MyProviderAPI" />
            <property name="wsdlDocumentUrl" value="http://localhost:8999/" />
            <property name="namespaceUri" value="http://myservice.mycompany.org/" />
            <property name="serviceName" value="MyProviderImplService" />
            <property name="portName" value="MyProviderPort" />
        </bean>
    </beans>

    Internally above approach uses build-in HttpServer. You can benefit from it, if you have developed you WebServers using e.g. Axis.

    Starting from Spring 3.0.4, the default values are inherited from @WebService annotation on MyProviderAPI interface. But due to 890, the annotation meta-information should be manually enhanced to make everything working.

  • You can use Jetty to deploy the backed WAR file + Spring for the client.

JAXB

What is “XPath evaluation of … results in empty target node”?

This happens when XPath expression in your customization has not matched any node (the expression is incorrect or you are trying to match in the wrong schema file) (see here some more information)

How to customize package names / class prefix or suffix?

You can define the package name per XSD (e.g. per namespace). From 6214576:
<jaxb:bindings
    schemaLocation="../wsdl/address.xsd"
    node="//xsd:schema[@targetNamespace='http://mycompany.com/service']">
    <jaxb:schemaBindings>
        <jaxb:package name="com.mycompany.project" />
        <jaxb:nameXmlTransform>
            <jaxb:typeName prefix="Foo" suffix="Type" />
            <jaxb:anonymousTypeName prefix="Foo" suffix="Type" />
            <jaxb:elementName prefix="Foo" suffix="Element" />
        </jaxb:nameXmlTransform>
    </jaxb:schemaBindings>
</jaxb:bindings>

How to refer the XSD from JAR in JAXB customization?

Suppose the schema is taken from JAR dependency as shown in this example:

pom.xml

<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb2-plugin</artifactId>
    <version>0.8.1</version>
    <executions>...</executions>
    <configuration>
        <schemas>
            <schema>
                <dependencyResource>
                    <groupId>com.test</groupId>
                    <artifactId>schemas</artifactId>
                    <version>1.10-SNAPSHOT</version>
                    <resource>schemas/schema.xsd</resource>
                </dependencyResource>
            </schema>
        </schemas>
        ...
    </configuration>
</plugin>

How to refer a specific schema from customization file?

From JAXB Bindings to schemas in a JAR and Using SCD for customizations the solution is to use SCD to point the schema by target namespace:

pom.xml

<jaxb:bindings scd="x-schema::tns" xmlns:tns="http://my.schema.target.namespace/">
    <jaxb:schemaBindings>
        <jaxb:package name="org.jvnet.jaxb2.maven2.tests.po"/>
    </jaxb:schemaBindings>
</jaxb:bindings>

How to automatically make collection properties plural (e.g. countrycountries)?

Have a look at simple binding mode:
<jaxb:globalBindings>
    <xjc:simple />
</jaxb:globalBindings>

How to define custom interface / class that specific JAXB bean should implement / extend?

Where can I find the DTD/XSD describing JAXB customizations file?

Check this: jaxb-xjc.jar/com\sun\tools\xjc\reader\xmlschema\bindinfo\binding.xsd


How to unmarshal part of XML?

From Suppress outer tag for nested objects: Use StreamFilter to suppress XML nodes which should not be fed to JAXB .

From Can JAXB parse large XML files in chunks: Use custom XMLStreamReader or some logic around it to skip uninteresting elements.

How to marshal JAXB fragment without default namespaces generated for each fragment?

From JAXB fragment marshal w/o namespace: Use XMLStreamWriter or NS-aware DOM.

How to create immutable objects?

From JAXB and Immutable Objects: Use XmlAdapter<AdaptedCustomer, Customer>.

How to make the property unmarshalled, but ignored during the marshalling?

From Annotation @XmlElement write only:

Mark your property using @XmlReadOnly.

How to tell JAXB to ignore the properties from the parent class?

There are two solutions for this (from here):
  • Mark you parent class with @XmlTransient. In this case all class properties will be populated to parent classes, but class itself will be excluded from domain model (so you cannot marshall/unmarshall it).
  • Mark you parent class with @XmlAccessorType(XmlAccessType.NONE). You will have to duplicate both property setters and getters in your child class:

    ChildDocument.java

    public String getComment() {
        return super.getComment();
    }
    public void setComment(String comment) {
        super.setComment(comment);
    }

    or one can create package-info.java with the following content:

    package-info.java

    @XmlAccessorType(XmlAccessType.NONE)
    package test.sub;
     
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;

How to split JAXB model compilation into several parts?

In JAXB these parts are called episodes. See:

How to workaround com.sun.istack.SAXException2: unable to marshal type “…” as an element because it is missing an @XmlRootElement annotation problem?

This happens when the given object represents XSD type (not a concrete element). As in this example you need to wrap the given object into JAXBElement. ObjectFactory should have at least one factory method to do so.

programming/java/jax.txt · Last modified: 2012/04/21 12:43 by dmitry
 
 
Recent changes RSS feed Driven by DokuWiki