java - 有什么方法可以将 @XmlElement List<String> fieldName 编码(marshal)至 <fieldName xsi :nil ="true". ../> 而不是缺失的节点?

标签 java jaxb eclipselink moxy

我正在尝试让 MOXy 或 JAXB RI 将 null 集合编码到 xsi:nil 元素,如下所示:

<element xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>

用例是:

  • 我无法控制 Axis2 SOAP 端点
  • 我在客户端
  • Endpoint 需要 null 集合的 xsi:nil 元素,但不允许对它们进行包装(使用 @XmlElementWrapper),这将为包装元素生成所需的 xsi:nil 元素。
  • 我只能使用从 JDK 6 r4+ 开始的 JAX-WS RI 或最新的 Metro 实现。
  • 我可以使用 JAXB RI 或 MOXy 实现。
  • 我使用的是 EclipseLink 2.5.1
  • 绑定(bind)类型是在构建时通过 wsimport 从服务 WSDL 生成的。因此,任何不需要对生成的源进行后处理以进行注释修改的解决方案都是更可取的。

我知道从 2.2.6 开始,JAXB RI 可能无法做到这一点,但也许我错过了一些东西。我检查了来源,它基本上说,非参数化:“如果它是一个列表并且如果它为空,则仅在字段上存在@XmlElementWrapper时才输出任何内容”。但不幸的是,这不是这种情况的解决方案。

我尝试了 MOXy 及其 @XmlNullPolicy 注释的使用,但它似乎对集合属性没有影响。还有另一种方法可以使 MOXy 为空集合输出 xsi:nil 元素吗?

我创建了一个测试用例来举例说明所发生的情况。第一个和第二个是实际结果和我需要的结果。第三个是为第四个代码块中的实际用例启用 MOXy 所需的 jaxb.properties 文件。

这是我在底部执行测试用例时得到的结果:

<?xml version="1.0" encoding="UTF-8"?>
<model>
   <nonCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
   <nonCollectionEmptyNode/>
   <wrappedNullCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</model>

这就是我需要的:

<?xml version="1.0" encoding="UTF-8"?>
<model>
   <nonCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
   <nonCollectionEmptyNode/>
   <nullCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
   <wrappedNullCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</model>

jaxb.properties 该文件需要与下面的测试用例位于同一包中,否则 MOXy 将无法使用。

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

测试用例:

package test;

import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlMarshalNullRepresentation;
import org.eclipse.persistence.oxm.annotations.XmlNullPolicy;

/**
 * jaxb.properties containing string:
 * "javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory"
 * needs to be in the same package as this class to enable MOXy.
 */
public class XmlNullPolicyTest
{

  @XmlAccessorType(XmlAccessType.FIELD)
  @XmlRootElement
  private static class Model
  {

    /**
     * Outputs xsi:nil elements when using JAXB RI or MOXy.
     */
    @XmlElement(required = true, nillable = true)
    protected String nonCollection;


    /**
     * This is here to test if the EclipseLink implementation is actually used.
     * To enable MOXy JAXB impl put jaxb.properties containing text
     * "javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory"
     * in the same package as this class.
     *
     * Using the RI it outputs:
     * <nonCollectionEmptyNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
     *
     * And with MOXy, because it processes @XmlNullPolicy:
     * <nonCollectionEmptyNode/>
     */
    @XmlElement(required = true, nillable = true)
    @XmlNullPolicy(
      nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE
    )
    protected String nonCollectionEmptyNode;

    /**
     * Need this one to work. Should marshal to:
     * <nullCollection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
     * ...if possible.
     */
    @XmlElement(required = true, nillable = true)
    @XmlNullPolicy(
      nullRepresentationForXml = XmlMarshalNullRepresentation.XSI_NIL,
      xsiNilRepresentsNull = true
    )
    private List<String> nullCollection = null;

    /**
     * Cannot use this one, since it the service expects elements unwrapped.
     * Works though as long as the list is actually null.
     */
    @XmlElement(required = true, nillable = true)
    @XmlElementWrapper(nillable = true)
    private List<String> wrappedNullCollection = null;
  }

  public static void main(String[] args)
    throws JAXBException
  {

    final JAXBContext jaxbContext =
      JAXBContext.newInstance(Model.class);

    final Marshaller marshaller =
      jaxbContext.createMarshaller();

    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

    marshaller.marshal(new Model(), System.out);

  }
}

我很感激任何帮助。

感谢您的关注!

最诚挚的问候, 克里斯蒂安

最佳答案

为什么很难绘制 map

具有以下内容表示集合属性为 null。

<fieldName xsi:nil=“true”…/> 

当以下内容代表填充集合时:

<fieldName>foo</fieldName>
<fieldName>bar</fieldName>

有点奇怪,因为 <fieldName xsi:nil=“true”…/>将被解释为包含一个空条目的集合。

正如您通常在 JAXB 中提到的那样,您将利用 @XmlElementWrapper并使包装元素指示集合为空。

你可以做什么

我会调整您的数据以获得您想要的 XML 表示形式。您可以通过利用编码事件之前和之后来做到这一点。如果之前的事件转换任何 null值到 List尺寸为 1,包含 null值(value)。然后在解码后事件中设置 List大小包含 null值返回null .

这可以通过 Marshal.Listener 来完成:

或者在类的回调方法中:

关于java - 有什么方法可以将 @XmlElement List<String> fieldName 编码(marshal)至 <fieldName xsi :nil ="true". ../> 而不是缺失的节点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21528449/

相关文章:

java - 如何使用 API 将数据插入条形图

jaxb - javassist 不在现有字段中注入(inject)注释

java - 如何告诉 JAXB 在运行时序列化哪些字段?

java - 使用 JAXB 解码通用列表

java - JPQL 加入多个连接的实体

java - Eclipselink Mysql 表名大写

java - 如何从 xsd 生成 xpath?

java - 无法使用 VBO 渲染四边形

java - 如何识别 Java(JDK) 和 Apache Tomcat 的最新稳定版本?

jpa - querydsl 将多个查询合二为一