Java 如何使CXF生成的代码解组为JAX-B并忽略未映射字段?

Java 如何使CXF生成的代码解组为JAX-B并忽略未映射字段?,java,jaxb,cxf,unmarshalling,cxf-codegen-plugin,Java,Jaxb,Cxf,Unmarshalling,Cxf Codegen Plugin,我调用一个web服务,它可以定期在它们的契约中添加一些元素 示例:SOAP响应主体包含: <picture> <active>true</active> <code>172</code> <label>Nikon D3200 Black</label> <downloadEnabled>true</downloadEnabled> </picture>

我调用一个web服务,它可以定期在它们的契约中添加一些元素

示例:SOAP响应主体包含:

<picture>
   <active>true</active>
   <code>172</code>
   <label>Nikon D3200 Black</label>
   <downloadEnabled>true</downloadEnabled>
</picture>
<picture>
   <active>false</active>
   <code>177</code>
   <label>Nikon D5200 Red</label>
   <downloadEnabled>true</downloadEnabled>
   <extraField>none</extraField>
</picture>
我的CXF生成的JAXB Bean如下所示:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "pictureListJAXB", propOrder = {
    "active",
    "code",
    "label",
    "downloadEnabled",
    "extraField"
})
public class PictureListJAXB {

    protected boolean active;
    protected String code;
    protected String label;
    protected boolean downloadEnabled;
    @XmlElement(nillable = true)
    protected String extraField

    // And Getters / Setters comes here after      

}
jaxbbean是使用maven插件
cxfcodegen插件
version2.6.2(来自apache.cxf)生成的

现在我想知道,如果SOAP响应中出现新元素,是否有一种解决方案可以使我的Bean具有容错性:

<picture>
    <active>true</active>
    <code>172</code>
    <label>Nikon D3200 Black</label>
    <downloadEnabled>true</downloadEnabled>
    <newUnmappedElement>anything irrelevant</newUnmappedElement>
</picture>
现在,当我收到这样的响应时,我得到了一个
解组错误
,因为这个新元素

我的JAXB包含我想要管理的最小字段,但我希望bean能够处理新元素,而忽略它们

有没有办法在不重新生成jaxbbean的情况下做到这一点? (现在我必须重新生成bean并发布我的项目)

我检查了CXF选项(和xjc),但在文档(和google)中没有找到任何内容。解组操作在同样由CXF生成的
ReferentialService
中自动完成,那么修改此部件的生成的选项就足够了

下面是使用CXF生成的类调用web服务的代码:

public ReferentialService getReferentialService(String resource, String auth) throws RuntimeException {

    // These two classes are generated by CXF
    Referential referential;
    ReferentialService referentialService;


    // Get the resource URL in form http://myserver:port/remote-backend/resource?wsdl
    referential = new Referential(new URL(MyConfigUtil.getWSDL(resource)));

    referentialService = referential.getReferentialServicePort();
    BindingProvider bp = (BindingProvider) referentialService;

    // Get the endpoint URL in form http://myserver:port/remote-backend/resource
    bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, MyConfigUtil.getWebServiceEndPoint(resource));

    // Add SOAP credentials
    String username = HttpBasicAuthHelper.getUsername(auth);
    String password = HttpBasicAuthHelper.getPassword(auth);

    bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, username);
    bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password);

    return referentialService;
}
电话:

// Throws Exception just for the sample code
public InputStream listPictures(QueryDTO request, String resource, String auth) throws Exception {

    InputStream is = null;
    if (request != null) {

        // This is the WS Call which failed with unmarshal error
        List<PictureListJAXB> result = getReferentialService(resource, auth).getPictures(request);

        // Some code to convert JAXB into a  XML stream
        is = convertObjectToXmlStream(result);
    }
    return is;
}
//仅针对示例代码引发异常
公共InputStream listPictures(queryTo请求、字符串资源、字符串身份验证)引发异常{
InputStream=null;
if(请求!=null){
//这是由于解组错误而失败的WS调用
列表结果=getReferentialService(资源,身份验证).getPictures(请求);
//一些将JAXB转换为XML流的代码
is=convertObjectToXmlStream(结果);
}
回报是;
}
更新:
我看到了,我的感觉是一样的:如果单独使用而不使用CXF,JAXB将忽略未映射的元素。通过使用cxf codegen插件,情况并非如此。

解决此问题的一种方法是使用Jaxb annotation@xmlanyement(lax=true)。这意味着,对于该字段,如果元素通过@XmlRootElement或@XmlElementDecl与类关联,则相应类的实例将用于填充该字段,如果不是,则元素将设置为org.w3c.dom.element的实例。示例代码

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Root {
    ..
    ....
    @XmlAnyElement(lax = true)
    protected List<Object> any;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
公共类根{
..
....
@xmlanyement(lax=true)
任何受保护的清单;

输入中与类的显式属性不对应的任何元素都将被扫到此列表中。签出更多我通过查找最终找到了答案,但由于我没有像在文章中那样使用声明性方式,因此我猜测我应该能够在绑定提供程序上添加一些属性

我对代码的修改是在
BindingProvider
中添加这些属性,就像在
getReferentialService
方法中那样:

bp.getRequestContext().put("schema-validation-enabled", "true");
bp.getRequestContext().put("jaxb-validation-event-handler", new ValidatorHandler());
对于测试,我刚刚创建了一个内部类
ValidatorHandler

private class ValidatorHandler extends DefaultValidationEventHandler {
    @Override
    public boolean handleEvent(ValidationEvent event) {
        if (event.getSeverity() == ValidationEvent.WARNING) {
            return super.handleEvent(event);
        } else if (event.getSeverity() == ValidationEvent.ERROR
                && event.getMessage().startsWith("unexpected element")) {
            return true;
        } else {
            throw new RuntimeException(event.getMessage()
                    + " [line:" + event.getLocator().getLineNumber() + "]");
        }
    }
}

通过这样做,我不需要修改生成的bean(JAX-B)并使用默认生成的bean。

您的回答对我的研究很有帮助。谢谢。 我在SOAP响应中遇到了同样的未知元素问题

ValidationEvent.FATAL_错误“cvc复杂类型.2.4.a:无效内容”

我可以补充以下内容

bp.getRequestContext().put("set-jaxb-validation-event-handler", false);

这将关闭Danial Kulp CXF Committer的just JAXB验证和引用“在大多数情况下,这只是未知元素或错误名称空间中的元素之类的事情。”

您是否尝试删除Propoder属性(可能只是为了测试而手动删除)?我尝试在没有Proporter的情况下创建自己的Jaxb,但结果仍然相同。仍然需要附加字段。我看到我可以传递自己的binding.xjb文件,但我不知道在那里配置什么(缺少详细文档)…我做了一个简单的单元测试,Proporter对解组没有任何影响:JAXB仍然可以从带有额外字段的XML实例化。然后我的问题可能集中在CXF的解组上,但似乎我无法控制这一部分(自动生成的代码)(我猜你的意思是说,“…仍然无法实例化…”这是一个遗憾。到目前为止,我只使用了EclipseLink/MOXy JAXB实现,它在解组过程中忽略了任何未映射的元素。不,单元测试工作正常,但它不使用CXF或WSDL(只需使用javax.xml.bind.Unmarshaller和JaxbContext对JAX-B进行简单的解组)好的,但如何使CXF生成此注释?我不想修改自动生成的代码。@ruffp不确定如何使用CXF codegen插件进行解组,需要对其进行研究。我建议问另一个问题,如如何生成@XmlAnyElement(lax=true)使用cxf codegen插件感谢您的建议,但最后我通过添加一个特定的验证器就成功了。