【问题标题】:Apache Camel JAXB unmarshalling returns null properties after upgrade from Camel from 2.20.4 to 2.21.2 or 2.22.1从 Camel 从 2.20.4 升级到 2.21.2 或 2.22.1 后,Apache Camel JAXB 解组返回空属性
【发布时间】:2018-10-09 08:44:30
【问题描述】:

在将 Apache Camel 从 2.20.4 升级到 2.21.2 甚至 2.22.1 之后,我的单元测试失败了,我不明白为什么。

我有一个接收 XML 响应的路由,我想将它解组到一个数据类中。自 Apache Camel 2.21.2 以来,这失败了。

JAXB 上下文知道给定包中的所有数据类并选择正确的类。创建了正确的对象本身,但属性保持为空。通过调试 SAX 解析器,似乎标记之间的文本被 SAX 解析器故意忽略了。

我在 Camel 网站上看到 Camel 2.21.0“升级到 JAXB 2.3.0”。我不知道这对我意味着什么。

我的路线是这样的:

@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
    }
}

数据类是这样的

@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*/}
}

使用 Apache Camel 2.20.4,我的单元测试有效。对于 2.21.2 和 2.22.1,它会中断。问题是,解组器不会填充属性。

单元测试只是向返回 XML 的 Mockito 发送一个有效请求。

<?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>

有什么想法吗? camel-jaxb 中的错误?

【问题讨论】:

    标签: java jaxb apache-camel unmarshalling


    【解决方案1】:

    我创建了自定义 DataFormat 和更严格的 MarshallerUnmarhaller 来捕获此类错误。它可以帮助您找到真正的原因。

    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
            }
        }
    }
    

    将您的JaxbDataFormat 替换为StrictJaxbDataFormat

    final StrictJaxbDataFormat unmarshalFormat = new StrictJaxbDataFormat();
    

    我已尝试模拟您的代码,它的行为与您描述的完全一样(idtitle 为空)。当我添加StrictJaxbDataFormat 时,它会抛出javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.w3.org/2005/Atom", local:"id"). Expected elements are &lt;{}id&gt;,&lt;{}title&gt;,所以这可能是这个问题JAXB unmarshalling error: Expected elements are <{ } Root>,您应该使用JAXB 类将package-info.java 添加到您的包中。

    @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;
    

    【讨论】:

    • 嗨..这绝对有帮助。我对 package-info.java 的问题是,我的两个可能的响应具有不同的命名空间,而 package-info.java 在一个 XmlSchema 注释中只采用一个或不同的命名空间需要不同的前缀。我的解决方法是使用 XmlElement(namespace = "...") 注释每个属性。这是做的工作,但似乎不正确。发生的另一个问题是响应有额外的标签,我是这样解决的:stackoverflow.com/a/25621852/3066152 这是真的吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-24
    • 2020-07-01
    相关资源
    最近更新 更多