users@wadl.java.net

Re: Re: wadl2java: exception when marshalling generated JavaBeans to XML in request bodies

From: <michaelw_at_articulatedesign.us.com>
Date: Wed, 14 May 2014 20:09:14 +0000 (UTC)

> On 13 May 2014, at 21:13, michaelw@... wrote:
>
> > I ran wadl2java 1.1.6 to generate JavaBeans from WADL and used the
> > beans in my Jersey 2.7 client. There are no problems unmarshalling
an
> > XML response using the generated beans. However, if a request body
> > content is XML, marshalling fails with an exception:
> >
> >
org.glassfish.jersey.message.internal.WriterInterceptorExecutor$Termina
> > lWriterInterceptor aroundWriteTo
> > SEVERE: MessageBodyWriter not found for media type=application/xml,

> > type=class com.ltree.airportweather.AirportInfo,
> > genericType=class com.ltree.airportweather.AirportInfo.
> >
> > If I manually add @XmlRootElement to the generated bean, the
request
> > succeeds.
>
> Can you show me the code snippet you use to invoke the service using
the
> client
> as you did below? And also the body of the client method it is
calling.

Here's my code:

    String driverPostString =
        AirportWeatherRestClient.weather()
                                .postXmlAsTextPlain(airportInfoBean,
String.class);

And here's the method generated by wadl2java:

    public<T >T postXmlAsTextPlain(Object input, GenericType<T>
returnType) {
       UriBuilder localUriBuilder = _uriBuilder.clone();
       WebTarget resource =
_client.target(localUriBuilder.buildFromMap(
                                          
_templateAndMatrixParameterValues));
       javax.ws.rs.client.Invocation.Builder resourceBuilder =
resource.request("text/plain");
       Response response;
       response = resourceBuilder.build("POST", Entity.entity(input,
"application/xml")).invoke();
       if (response.getStatus()>= 400) {
          throw new
AirportWeatherRestClient.WebApplicationExceptionMessage(response);
       }
       return response.readEntity(returnType);
    }


> > I get the same result when sending requests from the generated
custom
> > class (i.e., the generated JAX-RS client with methods for all the
> > requests in the WADL).
> >
> > Here's my code:
> >
> > AirportInfo airportInfoBean = new AirportInfo(); // generated by
> > wadl2java
> > ...
> > Client client = ClientBuilder.newClient();
> > String responseFromPost =
> > client.target(BASE_URL)
> > .request(MediaType.TEXT_PLAIN)
>
> > .post(Entity.xml(airportInfoBean), String.class);
>
> This is an odd formulation, why are you using Entity.xml,

I'm following examples in the Java EE 7 tutorial, e.g. section
30.1.1.4:

    TrackingNumber trackingNumber =
        myResource.request(MediaType.APPLICATION_XML)
                  .post(Entity.xml(order), TrackingNumber.class);
                  
I checked the source, and Entity.xml(obj) is a wrapper for new
Entity.entity(obj, MediaType.APPLICATION_XML_TYPE). Is there a better
way? I'm new to JAX-RS, so any suggestions for good practices are
welcome.

> I suspect that give your model you will need to use:
>
> .post(new JAXBElment(new QName(….), AirportInfoBean.class,
> airportInfoBean),String.class);
>
> The problem here is that the AirportInfo object in a @XmlType and you
need to
> provide the specific name in order to map this to a xml element / or
just
> just the XmlRootElement annotation on it as you did above if the
names match.

Ok, I added a JAXBElement to the call, and the marshalling to XML
succeeds:

    JAXBElement<AirportInfo> airportInfoElement =
        new JAXBElement<>(new QName("airportInfo"), AirportInfo.class,
airportInfoBean);
    String responseFromXml =
        webTarget.request(MediaType.TEXT_PLAIN)
                 .post(Entity.xml(airportInfoElement), String.class);

However, if I replace Entity.xml() with Entity.json(), the client
throws this exception:

SEVERE: MessageBodyWriter not found for media type=application/json,
type=class javax.xml.bind.JAXBElement,
genericType=class javax.xml.bind.JAXBElement.

If I add @XmlRootElement to the generated bean, the JSON request
succeeds (without the JAXBElement).

Here's the relevant portion of the schema generated by wadl2java:

  <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  
    <xs:element name="airportInfo" type="airportInfo"/>

    <xs:complexType name="airportInfo">
      <xs:sequence>
        <xs:element name="airportCode" type="xs:string" minOccurs="0"/>
        <xs:element name="associatedCity" type="xs:string"
minOccurs="0"/>
        <xs:element name="elevation" type="xs:double" minOccurs="0"/>
        <xs:element name="latitude" type="xs:decimal" minOccurs="0"/>
        <xs:element name="longitude" type="xs:decimal" minOccurs="0"/>
        <xs:element name="name" type="xs:string" minOccurs="0"/>
      </xs:sequence>
    </xs:complexType>