首页 文章

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

提问于
浏览
4

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

我从类 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文件内容 . 事实上,如果我使用 @XmlTransient 注释类 Thing ,我会得到预期的结果 .

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

有人可以解释一下吗,拜托?先感谢您 .

2 回答

  • 0

    问题是您要从父类重写属性 . JAXB认为 JAXBThing 有“

    • 一个名为 strings (继承自 String )的属性映射到元素 strings .

    • 一个名为 strings 的属性(在 JAXBThing 上定义,映射到元素 strings 下的元素 string .

    如果在 JAXBThing 上的 setStrings 方法中设置断点,您将看到它首先使用正确的数据进行调用,然后第二次使用不正确的数据来覆盖初始集(因为它认为它们是共享的不同属性一个二传手 .

    您始终可以通过使用 @XmlTransient 注释来删除 Thing 类 .

    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;
      }
    
    }
    

    For More Information

  • 2

    非常感谢您的回答 . 我做了你建议我的事 . 你是对的, 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长度的字符串列表(第7行)调用 JaxbThing.setStrings . 因此, Thing.setStrings 被调用(第8行) . 对象的字符串字段( this.strings )的先前值为null . 然后,再次调用 JaxbThing.setStrings (第10行),但现在有一个字符串列表,其中包含一个带有'\n'字符的字符串加上4个空格(我猜这对应于XML文件的缩进) . 两个评论:

    • 永远不会使用正确的值调用 JaxbThing.setStrings (除非我没有看到它) .

    • 第二次调用 JaxbThing.setStrings (第10行)导致第二次调用 Thing.setStrings (第11行) . 但是现在 this.strings 的前一个值不是在第8行的前一次调用 Thing.setStrings 中设置的0长度字符串列表 . 它已经是'\n'字符加上4个作为参数传递的空格 .

    解释这种行为的任何线索?

相关问题