【问题标题】:Marshalling a List of objects implementing a common interface, with JaxB使用 JaxB 编组实现公共接口的对象列表
【发布时间】:2011-05-07 20:31:57
【问题描述】:

我正在尝试编组实现公共接口的对象列表。 涉及3个类和1个接口:

Community 类(有一个方法:List getPeople();

Person 接口(只有一种方法:String getName();

Girl 类(实现 Person)

Boy 类(实现 Person)

参见下面的代码。

我想要一个看起来像这样的 XML:

<community>
  <people>
    <girl>
      <name>Jane</name>
    </girl>
    <boy>
      <name>John</name>
    </boy>
    <girl>
      <name>Jane</name>
    </girl>
    <boy>
      <name>John</name>
    </boy>
  </people>
</community>

或者可能:

<community>
  <people>
   <person>
      <girl>
        <name>Jane</name>
      </girl>
    </person>
    <person>
      <boy>
        <name>John</name>
      </boy>
    </person>
  </people>
</community>

到目前为止,我得到的是这样的:

<community>
    <people>
        <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="girl">
            <name>Jane</name>
        </person>
        <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="boy">
            <name>John</name>
        </person>
        <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="girl">
            <name>Jane</name>
        </person>
        <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="boy">
            <name>John</name>
        </person>
    </people>
</community>

我意识到我可以将元素更改为其他内容,但我希望元素名称是在 Girl 或 Boy 类中指定的名称。

这可以吗?谢谢。

@XmlRootElement(name = "community")
public class Community {

 private List<Person> people;

 @XmlElementWrapper
 @XmlElement(name="person")
 public List<Person> getPeople() {
  return people;
 }

 public Community() {
  people = new ArrayList<Person>();
  people.add(new Girl());
  people.add(new Boy());
  people.add(new Girl());
  people.add(new Boy());
 }
}







@XmlRootElement(name = "girl")
public class Girl implements Person {

 @XmlElement
 public String getName() {
  return "Jane";
 }
}


@XmlRootElement(name = "boy")
public class Boy implements Person {

 @XmlElement
 public String getName() {
  return "John";
 }
}



@XmlJavaTypeAdapter(AnyTypeAdapter.class)
public interface Person {
 public String getName();
}



public class AnyTypeAdapter extends XmlAdapter<Object, Object> {

 @Override
   public Object marshal(Object v) throws Exception {
    return v;
   }

 @Override
   public Object unmarshal(Object v) throws Exception {
    return v;
   }

}

【问题讨论】:

    标签: java xml jaxb


    【解决方案1】:

    对于这种情况,我建议使用@XmlElements。 @XmlElements 用于表示选择的 XML 模式概念:

    这是您的示例的外观:

    @XmlElements({ 
        @XmlElement(name="girl", type=Girl.class),
        @XmlElement(name="boy", type=Boy.class)
    })
    @XmlElementWrapper
    public List<Person> getPeople() {
        return people;
    }
    

    @XmlElementRef 对应于 XML 模式中的替换组的概念。这就是为什么前面的答案要求将 Person 从接口更改为类的原因。

    【讨论】:

      【解决方案2】:

      好的,如果您准备将 Person 从接口更改为抽象基类,那么您就成功了。代码如下:

      public class Main {
      
      
        public static void main(String[] args) throws Exception {
      
          Community community = new Community();
      
          JAXBContext context = JAXBContext.newInstance(Community.class);
          Marshaller marshaller = context.createMarshaller();
          marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
          marshaller.marshal(community, System.out);
      
        }
      }
      
      @XmlRootElement(name = "community")
      @XmlSeeAlso({Person.class})
      public class Community {
      
       private List<Person> people;
      
       @XmlElementWrapper(name="people")
       @XmlElementRef()
       public List<Person> getPeople() {
        return people;
       }
      
       public Community() {
        people = new ArrayList<Person>();
        people.add(new Girl());
        people.add(new Boy());
        people.add(new Girl());
        people.add(new Boy());
       }
      }
      
      @XmlRootElement(name="boy")
      public class Boy extends Person {
      
       public String getName() {
        return "John";
       }
      }
      
      @XmlRootElement(name="girl")
      public class Girl extends Person {
      
       public String getName() {
        return "Jane";
       }
      }
      
      @XmlRootElement(name = "person")
      @XmlSeeAlso({Girl.class,Boy.class})
      public abstract class Person {
      
        @XmlElement(name="name")
       public abstract String getName();
      }
      

      主要技巧是在社区列表中使用@XmlElementRef。这通过它的@XmlRootElement 标识类的类型。您可能还对有助于组织上下文声明的@XmlSeeAlso 感兴趣。

      输出是

      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <community>
          <people>
              <girl>
                  <name>Jane</name>
              </girl>
              <boy>
                  <name>John</name>
              </boy>
              <girl>
                  <name>Jane</name>
              </girl>
              <boy>
                  <name>John</name>
              </boy>
          </people>
      </community>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-03
        • 1970-01-01
        • 2011-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-25
        • 1970-01-01
        相关资源
        最近更新 更多