【问题标题】:Marshalling null values with a custom type used with an xml adapter使用与 xml 适配器一起使用的自定义类型编组空值
【发布时间】:2012-05-02 13:47:00
【问题描述】:

我正在使用带有 XmlType 的 POJO 对象作为我为编组字符串映射而构建的自定义 XML 适配器。但是,我遇到了问题,让我可以正确使用空值。我能够让它工作,但我对它生成的 XML 不满意。

这是我目前正在使用的我想要工作的东西,但正如您在示例 XML 结果中看到的那样,它不包括正确的 xmlns:xsi="http://www.w3.org/ 2001/XMLSchema-instance" xsi:nil="true" 值

@XmlType(name="element")
public class RestMapElements {

  @XmlAttribute(name="name")
  public String key;
  @XmlValue
  public String value;

  public RestMapElements(String key, String value) {
    this.key = key;
    this.value = value;
  }
}

生成的 XML(精简为相关数据)。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
...
    <element-list>
        <item name="activated_date">2012-03-29 11:34:14.323</item>
        <item name="some_null_value"/>
    </element-list>
...

但是,我能够让它与它一起工作,我只是不满意 XML 必须在 item 标记内添加一个额外的“值”标记以使其工作。 (旁注,为什么将它命名为 item 而不是我试图在 XmlType 名称声明中指定的元素?)

@XmlType(name="element")
public class RestMapElements {

  @XmlAttribute(name="name")
  public String key;
  @XmlElement(nillable = true)
  public String value;

  public RestMapElements(String key, String value) {
    this.key = key;
    this.value = value;
  }
}

同样,生成的 XML(精简为相关数据)。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
...
<element-list>
    <item name="activated_date"><value>2012-03-29 11:34:14.323</value></item>
    <item name="some_null_value"><value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/></item>
</element-list>
...

真的,我可以使用第二个,因为它可以解决我的问题。我只是想将其用作学习经验,以查看使用注释的 JAXB 是否允许将其弯曲到我正在寻找的内容,而不必在项目标签下添加额外的值标签,这样我就可以支持空值.现在,当它在第一个示例中解组时,我最终得到的是空字符串而不是 null。在第二个示例中,我得到了预期的 null 值。

仅供参考:我目前正在使用 Jersey 1.11

【问题讨论】:

    标签: java jaxb jersey


    【解决方案1】:

    注意:我是EclipseLink JAXB (MOXy) 领导,也是JAXB 2 (JSR-222) 专家组的成员。

    您可以使用 MOXy 的 @XmlNullPolicy 扩展来映射此用例:

    RestMapElements

    package forum10415075;
    
    import javax.xml.bind.annotation.*;
    import org.eclipse.persistence.oxm.annotations.*;
    
    @XmlType(name="element")
    public class RestMapElements {
    
      @XmlAttribute(name="name")
      public String key;
    
      @XmlValue
      @XmlNullPolicy(nullRepresentationForXml=XmlMarshalNullRepresentation.XSI_NIL)
      public String value;
    
    }
    

    package forum10415075;
    
    import java.util.*;
    import javax.xml.bind.annotation.*;
    
    @XmlRootElement
    public class Root {
    
        @XmlElementWrapper(name="element-list")
        @XmlElement(name="item")
        public List<RestMapElements> items = new ArrayList<RestMapElements>();
    
    }
    

    jaxb.properties

    要将 MOXy 用作您的 JAXB (JSR-222) 提供程序,您需要在与域模型相同的包中添加一个名为 jaxb.properties 的文件,其内容如下:

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

    演示

    package forum10415075;
    
    import java.io.File;
    import javax.xml.bind.*;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Root.class);
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            File xml = new File("src/forum10415075/input.xml");
            Root root = (Root) unmarshaller.unmarshal(xml);
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(root, System.out);
        }
    
    }
    

    input.xml/Output

    <?xml version="1.0" encoding="UTF-8"?>
    <root>
       <element-list>
          <item name="activated_date">2012-03-29 11:34:14.323</item>
          <item name="some_null_value" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
       </element-list>
    </root>
    

    注意

    如果您在 GlassFish 3.1.2 MOXy 或 WebLogic 12.1.1 中使用 Jersey:

    【讨论】:

    • 感谢您的详细解答。我已经看到您关于 MOXy 解决的其他 JAXB 问题的其他帖子 - 但是,我们正试图坚持参考实现。如果我们要使用 MOXy,您的解决方案会奏效!
    • 亲爱的@BlaiseDoughan 有没有机会在未来的 JAXB 中将 nillable 元素放在 @XmlValue 上?
    • 亲爱的@BlaiseDoughan Oh nillable @XmlRootElement 会更好。 :)
    【解决方案2】:

    我看到了你的问题。只有通过将ArrayList(或其他)中相应的RestMapElements 条目设置为null,才能生成带有xsi:nil="true"item 元素,从而丢失属性。我认为没有太多的解决方案。

    一种选择是从帖子的开头使用您的编组,然后使用以下内容解组:

    如果你正在做这样的事情:

    @XmlElementWrapper(name="element-list")
    @XmlElement(name="item")
    public ArrayList<RestMapElements> list;
    

    您可以使用XmlAdapter 来检查value 是否为空String,如果是则将其设置为null

    @XmlElementWrapper(name="element-list")
    @XmlElement(name="item")
    @XmlJavaTypeAdapter(ItemAdapter.class)
    public ArrayList<RestMapElements> list;
    

    还有ItemAdapter:

    public class ItemAdapter extends XmlAdapter<RestMapElements, RestMapElements> {
    
        @Override
        public RestMapElements unmarshal(RestMapElements v) throws Exception {
            if (v.value.equals("")) v.value = null;
            return v;
        }
    }
    

    虽然这仍然是不雅的恕我直言。 如果你想生成正确的 xsi:nil="true" item 元素,这显然不是你想要的。

    祝你好运。

    【讨论】:

    • 是的,我正试图远离那个解决方案。我也想到了这一点,只是在 XmlAdapter 上修复它,但我希望该服务是正确的,以便其他人在我们的 Web 服务上构建库时,它们都作为相同的实现运行。我试图让我们的包装库成为 REST 服务的直接翻译器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-05
    • 1970-01-01
    • 2014-06-29
    • 1970-01-01
    相关资源
    最近更新 更多