编组时JAXB和继承有效;但不是解组

时间:2013-12-19 15:37:31

标签: java inheritance jaxb

我想编组/解组继承另一个类的类的对象。

我从课程Thing开始:

import java.util.List;

public class Thing {
  private List<String> strings;

  public List<String> getStrings() {
    return strings;
  }

  public void setStrings(List<String> strings) {
    this.strings = strings;
  }
}

我扩展了这个类并使用JAXB注释对其进行注释。

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class JaxbThing extends Thing {

  // @XmlElementWrapper(name = "list")
  @XmlElementWrapper(name = "strings")
  @XmlElement(name = "string")
  public List<String> getStrings() {
    return super.getStrings();
  }

  public void setStrings(List<String> string) {
    super.setStrings(string);
  }
}

然后我运行以下编组/解组程序:

import java.io.File;
import java.util.Arrays;
import javax.xml.bind.*;

public class Main {
  public static void main(String[] args) {
    JaxbThing t = new JaxbThing();
    t.setStrings(Arrays.asList("a", "b", "c"));
    try {
      File f = new File("jaxb-file.xml");

      JAXBContext context = JAXBContext.newInstance(JaxbThing.class);

      Marshaller m = context.createMarshaller();
      m.marshal(t, f);

      Unmarshaller um = context.createUnmarshaller();
      JaxbThing t2 = (JaxbThing) um.unmarshal(f);

      System.out.println(t2.getStrings());  // I expect to see [a, b, c]

    } catch (JAXBException e) {
      e.printStackTrace();
    }
  }
}

XML文件的内容是:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxbThing>
    <strings>
        <string>a</string>
        <string>b</string>
        <string>c</string>
    </strings>
</jaxbThing>

一切似乎都是正确的。但解密的结果让我感到惊讶,因为控制台显示:

[
    ]

当我希望看到[a, b, c]

如果我以这种方式注释strings属性:

  @XmlElementWrapper(name = "list")
  // @XmlElementWrapper(name = "strings")
  @XmlElement(name = "string")
  public List<String> getStrings() {
    return super.getStrings();
  }

然后控制台显示预期的[a, b, c]

我想JAXB unmarshaler正在使用类Thing而不是JaxbThing来解组XML文件内容。事实上,如果我用Thing注释班级@XmlTransient,我会得到预期的结果。

但是我不明白JAXB的这种行为。

有人可以解释一下吗?提前谢谢。

2 个答案:

答案 0 :(得分:2)

问题是您正在覆盖父类的属性。 JAXB认为JAXBThing有“

  1. 一个名为strings的属性(继承自String)映射到元素strings
  2. 一个名为strings的属性(在JAXBThing上定义,映射到元素string下的元素strings
  3. 如果你在setStrings上的JAXBThing方法中设置了一个断点,你会看到它首先使用正确的数据调用,然后第二次调用它,其中包含覆盖初始值的错误数据set(因为它认为它们是共享setter的不同属性)。

    您始终可以通过Thing对其进行注释来删除@XmlTransient课程。

    import java.util.List;
    import javax.xml.bind.annotation.XmlTransient;
    
    @XmlTransient
    public class Thing {
      private List<String> strings;
    
      public List<String> getStrings() {
        return strings;
      }
    
      public void setStrings(List<String> strings) {
          System.out.println("Thing" + strings);
        this.strings = strings;
      }
    
    }
    

    了解更多信息

答案 1 :(得分:0)

非常感谢您的回答。我做了你建议我的事。你是对的,setStrings方法被调用两次。但是,至少在我的实验中,它永远不会被调用正确的值。

Bellow我提供修改后的示例代码。我添加了几行来跟踪执行情况。我还激活了marshaller格式化输出,以便更好地了解解组过程中会发生什么。

基类Thing

import java.util.List;

public class Thing {
  private List<String> strings;

  public List<String> getStrings() {
    return strings;
  }

  public void setStrings(List<String> strings) {
    /*new*/ System.out.printf("Thing.setStrings called. Prev. this.strings: %s (size %s). Received strings param: %s", this.strings, (this.strings!=null ? this.strings.size():"null"),strings);
    this.strings = strings;
    /*new*/ System.out.printf(". New this.strings: %s (size %s).%n%n", this.strings, (this.strings!=null ? this.strings.size():"null"));
  }
}

扩展班级JaxbThing

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class JaxbThing extends Thing {

  // @XmlElementWrapper(name = "list")
  @XmlElementWrapper(name = "strings")
  @XmlElement(name = "string")
  public List<String> getStrings() {
    return super.getStrings();
  }

  public void setStrings(List<String> string) {
    /*new*/ System.out.printf("JaxbThing.setStrings called. Received strings param: %s (size %s)%n",string,(string !=null?string.size():"null"));
    super.setStrings(string);
  }
}

测试程序:

import java.io.File;
import java.util.Arrays;
import javax.xml.bind.*;

public class Main {
  public static void main(String[] args) {    
    System.out.println("---- Initiallizing");
    JaxbThing t = new JaxbThing();
    t.setStrings(Arrays.asList("a", "b", "c"));
    try {
      File f = new File("jaxb-file.xml");

      JAXBContext context = JAXBContext.newInstance(JaxbThing.class);

      System.out.println("---- Marshalling");
      Marshaller m = context.createMarshaller();
      m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);   /*new*/
      m.marshal(t, f);

      System.out.println("---- UnMarshalling");
      Unmarshaller um = context.createUnmarshaller();
      JaxbThing t2 = (JaxbThing) um.unmarshal(f);

      System.out.println("---- Showing results");
      System.out.println(t2.getStrings());  // I expect to see [a, b, c]

    } catch (JAXBException e) {
      e.printStackTrace();
    }
  }
}

结果如下(我已对行编号):

1  ---- Initiallizing
2  JaxbThing.setStrings called. Received strings param: [a, b, c] (size 3)
3  Thing.setStrings called. Prev. this.strings: null (size null). Received strings param: [a, b, c]. New this.strings: [a, b, c] (size 3).
4  
5  ---- Marshalling
6  ---- UnMarshalling
7  JaxbThing.setStrings called. Received strings param: [] (size 0)
8  Thing.setStrings called. Prev. this.strings: null (size null). Received strings param: []. New this.strings: [] (size 0).
9  
10 JaxbThing.setStrings called. Received strings param: [
       ] (size 1)
11 Thing.setStrings called. Prev. this.strings: [
       ] (size 1). Received strings param: [
       ]. New this.strings: [
       ] (size 1).
12 
13 ---- Showing results
14 [
         ]

在解组时,会构建一个新的JaxbThing,首先使用0长度的字符串列表调用其JaxbThing.setStrings(第7行)。因此,调用Thing.setStrings(第8行)。对象的字符串字段(this.strings)的先前值为null。然后,再次调用JaxbThing.setStrings(第10行),但现在有一个字符串列表,其中包含一个带有'\ n'字符和4个空格的字符串(我猜这对应于XML文件的缩进) )。两句话:

  1. 永远不会使用正确的值调用JaxbThing.setStrings(除非我没有看到它)。
  2. 第二次调用JaxbThing.setStrings(第10行)会导致第二次调用Thing.setStrings(第11行)。但是现在this.strings的先前值不是在第8行中对Thing.setStrings的上一次调用中设置的0长度字符串列表。它已经是'\ n'字符加上4个空格,即作为参数传递。
  3. 解释这种行为的任何线索?