有没有办法将@XmlElement List <string> fieldName编组为<fieldname xsi:nil =“true”... =“”>而不是缺少节点?</fieldname> </string>

时间:2014-02-03 13:18:28

标签: java jaxb eclipselink moxy

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

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

用例是:

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

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

我尝试了MOXy并使用了@XmlNullPolicy注释,但它似乎对集合属性没有影响。还有另一种方法可以为emtpty集合制作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);

  }
}

我感谢任何帮助。

感谢您的关注!

祝你好运, 基督教

1 个答案:

答案 0 :(得分:0)

为什么难以映射

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

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

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

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

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

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

你能做什么

我会调整您的数据以获得您想要的XML表示。您可以通过在编组事件之前和之后利用来实现此目的。如果before事件将任何null值转换为包含List值的大小为1的null。然后在after unmarshal事件中将包含List值的null大小设置回null

可以使用Marshal.Listener

完成此操作

或者在类的回调方法中: