MrGorilla
MrGorilla

Reputation: 31

Apache Camel JAXB unmarshalling returns null properties after upgrade from Camel from 2.20.4 to 2.21.2 or 2.22.1

After upgrading Apache Camel from 2.20.4 to 2.21.2 or even 2.22.1 a unit test of my fails and I can't see why.

I have a route which receives an XML response, which I want to unmarshal in to a data class. This fails since Apache Camel 2.21.2.

The JAXB context knows all data classes in the given package and picks the right class. The right object itself is created, but the properties stay null. With debugging the SAX parser, it seemed as if the text between the tags is deliberately ignored by the SAX parser.

I have seen on the Camel website that Camel 2.21.0 "Upgraded to JAXB 2.3.0". I don't know what that means for me.

My route looks like this:

@Component
public class NewsletterRoute extends RouteBuilder {

8<-------------------------------------------------

@Override
public void configure() {
    final DataFormat marshalFormat =
        new JacksonDataFormat(HybrisRequest.class);
    final JaxbDataFormat unmarshalFormat = new JaxbDataFormat();
    unmarshalFormat.setContextPath(
       SuccessResponse.class.getPackage().getName());

    from(URI)
        .routeId("subscribeRoute")
        // Fetch the auth token to send it as 'x-csrf-token' header.
        .setHeader(Exchange.HTTP_URI,
            method(this.backendUrlProvider, "getUrl"))
        .setHeader(Exchange.HTTP_PATH,
             constant(this.subscribeUnsubscribePath))
        .setHeader(Exchange.HTTP_METHOD, HttpMethods.POST)
        .setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
        // Marshal body to JSON
        .marshal(marshalFormat)
        .to(String.format("https4:backend" +
                "?sslContextParameters=hybrisSslContextParams" +
                "&x509HostnameVerifier=hybrisHostnameVerifier" +
                // don't throw on 3XX/4XX/5XX since
                // we need the response body 
                "&throwExceptionOnFailure=false" +
                "&cookieStore=#hybrisCookieStore" +
                "&authUsername=%s" +
                "&authPassword=%s" +
                "&authenticationPreemptive=true" +
                "&httpClient.redirectsEnabled=true" +
                "&httpClient.maxRedirects=3" +
                "&httpClient.connectTimeout=%d" +
                "&httpClient.socketTimeout=%d",
            "RAW(" + username + ")",
            "RAW(" + password + ")",
            backendTimeoutMillis,
            backendTimeoutMillis))
        .convertBodyTo(String.class)
        // Store the received response as property before
        // trying to unmarshal it
        .setProperty(PROPERTY_RESPONSE_RAW, body())
        .unmarshal(unmarshalFormat);
    // @formatter:on
    }
}

The data class looks like this

@XmlRootElement(name = "entry", namespace = "http://www.w3.org/2005/Atom")
public class SuccessResponse {
    private String id;
    private String title;
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    public String toString() { /*code cut out*/}
}

With Apache Camel 2.20.4 my unit test worked. With 2.21.2 and 2.22.1 it breaks. The problem is, that the unmarshaler won't fill the properties.

The unit test just sends a valid request to Mockito which returns the XML.

<?xml version="1.0" encoding="utf-8"?>
<entry xml:base="https://xxx.xxx.xxx.xxx:44380/sap/opu/odata/sap/CUAN_IMPORT_SRV/"
    xmlns="http://www.w3.org/2005/Atom"
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices">  
<!-- 8<---------- Code cut out here ----------------------------------- --> 
    <id>bla</id>
    <title type="text">blub</title>
</entry>

Any ideas? Bug in camel-jaxb?

Upvotes: 3

Views: 1988

Answers (1)

Bedla
Bedla

Reputation: 4919

I have created custom DataFormat with more strict Marshaller and Unmarhaller to catch this type of errors. It can help you to find real cause.

import org.apache.camel.converter.jaxb.JaxbDataFormat;

import javax.xml.bind.*;

public class StrictJaxbDataFormat extends JaxbDataFormat {

    @Override
    protected Unmarshaller createUnmarshaller() throws JAXBException {
        Unmarshaller unmarshaller = super.createUnmarshaller();
        unmarshaller.setEventHandler(new StrictValidationEventHandler());
        return unmarshaller;
    }

    @Override
    protected Marshaller createMarshaller() throws JAXBException {
        Marshaller marshaller = super.createMarshaller();
        marshaller.setEventHandler(new StrictValidationEventHandler());
        return marshaller;
    }

    private static class StrictValidationEventHandler implements ValidationEventHandler {
        @Override
        public boolean handleEvent(ValidationEvent event) {
            return false; // all validation events should throw exception
        }
    }
}

Replace your JaxbDataFormat with StrictJaxbDataFormat

final StrictJaxbDataFormat unmarshalFormat = new StrictJaxbDataFormat();

I have tried to simulate your code and it behaves exactly as you described (id and title is null). When I have added StrictJaxbDataFormat, it throws javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.w3.org/2005/Atom", local:"id"). Expected elements are <{}id>,<{}title> so it is probably this issue JAXB unmarshalling error: Expected elements are <{ } Root> and you should add package-info.java to your package with JAXB classes.

@XmlSchema(namespace = "http://www.w3.org/2005/Atom", elementFormDefault = XmlNsForm.QUALIFIED)
package your.package;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

Upvotes: 1

Related Questions