当前位置: 首页 > 知识库问答 >
问题:

使用xstream生成子类从xml解组

通奕
2023-03-14

我正在尝试使用XStream将XML转换为对象树。我希望基于属性创建一个特定的子类。

我该怎么做呢?

<items>
    <item>
        <event type="aaa">
            <timestamp>2014-04-10 15:58:08 UTC</timestamp>
        </event>
        <event type="bbb">
            <timestamp>2014-04-03 11:58:08 UTC</timestamp>
        </event>
    </item>
</items>

当我简单地使用带有别名和一个事件类的XStream时,它工作得很好。

    xstream.alias("items", Items.class);
    xstream.alias("event", Event.class);

但是,我希望XStream为每个Event类型创建不同的类。我有从抽象Event扩展的类EventAAA和EventBBB。如何告诉XStream在解组时考虑到这一点?XStream目前总是尝试实例化Event并失败,因为它是抽象的。

干杯

共有1个答案

司空劲
2023-03-14

执行所需操作(及更多操作)的示例代码:

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * http://stackoverflow.com/posts/23792750
 */
public class App {

    public static class Items {

        private ArrayList<Item> e;

        public Items(ArrayList<Item> e) {
            this.e = e;
        }

    }

    public static class Item {

        private ArrayList<Event> e;

        public Item(ArrayList<Event> e) {
            this.e = e;
        }

    }

    public static void main(String[] args) {
        Items items = new Items(
                new ArrayList<Item>(
                        Arrays.asList(
                                new Item(
                                        new ArrayList(
                                                Arrays.<Event>asList(new EventAAA(), new EventBBB())
                                        )
                                )
                        )
                )
        );

        XStream xs = new XStream();

        xs.registerConverter(new EventConverter());
        xs.registerConverter(new ItemConverter());
        xs.alias("item", Item.class);
        xs.addImplicitArray(Item.class, "e");
        xs.alias("items", Items.class);
        xs.addImplicitArray(Items.class, "e");

        System.out.println("Serialize individual event objects:");
        System.out.println(xs.toXML(new EventAAA()));
        System.out.println(xs.toXML(new EventBBB()));
        System.out.println("De-serialize individual event objects:");
        System.out.println(xs.fromXML(xs.toXML(new EventAAA())).toString());
        System.out.println(xs.fromXML(xs.toXML(new EventAAA())).getClass().getName());
        System.out.println(xs.fromXML(xs.toXML(new EventBBB())).toString());
        System.out.println(xs.fromXML(xs.toXML(new EventBBB())).getClass().getName());

        System.out.println("Show serialization of ArrayList<Item> items:");
        System.out.println(xs.toXML(items));

        System.out.println("Show de-serialization of ArrayList<Item> items:");
        System.out.println(xs.fromXML(xs.toXML(items)));

        System.out.println("Show correct type information in de-serialization for elements in e:");
        Items items2 = (Items) xs.fromXML(xs.toXML(items));
        for (Item i : items2.e) {
            for (Event e : i.e) {
                System.out.println(e.getClass().getName());
            }
        }
    }

    public static class Timestamp {

        public Timestamp(String timestamp) {

        }
    }

    public static abstract class Event {

        public abstract String getTypeName();

        private Timestamp timestamp = new Timestamp("");

        public void setTimestamp(Timestamp t) {
            this.timestamp = t;
        }

        public Timestamp getTimestamp() {
            return timestamp;
        }
    }

    public static class EventAAA extends Event {

        @Override
        public String getTypeName() {
            return "aaa";
        }

    }

    public static class EventBBB extends Event {

        @Override
        public String getTypeName() {
            return "bbb";
        }

    }

    public static class ItemConverter implements Converter {

        @Override
        public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext mc) {
            Item i = (Item) o;
            for (Event e : i.e) {
                writer.startNode("event");
                mc.convertAnother(e);
                writer.endNode();
            }
        }

        @Override
        public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext uc) {
            Item i = new Item(new ArrayList<>());
            while (reader.hasMoreChildren()) {
                i.e.add((Event) uc.convertAnother(i, Event.class));
            }
            return i;
        }

        @Override
        public boolean canConvert(Class type) {
            return (type.equals(Item.class));
        }

    }

    public static class EventConverter implements Converter {

        public boolean canConvert(Class clazz) {
            return Event.class.isAssignableFrom(clazz);
        }

        public void marshal(Object value, HierarchicalStreamWriter writer,
                MarshallingContext context) {
            Event e = (Event) value;
            writer.addAttribute("type", e.getTypeName());
            writer.startNode("timestamp");
            writer.setValue(e.getTimestamp().toString());
            writer.endNode();
        }

        public Object unmarshal(HierarchicalStreamReader reader,
                UnmarshallingContext context) {
            String type = reader.getAttribute("type");
            Event e;
            if (type.equals("aaa")) {
                e = new EventAAA();
            } else if (type.equals("bbb")) {
                e = new EventBBB();
            } else {
                throw new IllegalArgumentException("Encountered illegal type of event: " + type);
            }
            reader.moveDown();
            e.setTimestamp(new Timestamp(reader.getValue()));
            reader.moveUp();
            return e;
        }

    }

}

示例代码的输出:

Serialize individual event objects:
<App_-EventAAA type="aaa">
  <timestamp>App$Timestamp@184cf7cf</timestamp>
</App_-EventAAA>
<App_-EventBBB type="bbb">
  <timestamp>App$Timestamp@5bfa9431</timestamp>
</App_-EventBBB>
De-serialize individual event objects:
App$EventAAA@48fa0f47
App$EventAAA
App$EventBBB@161479c6
App$EventBBB
Show serialization of ArrayList<Item> items:
<items>
  <item>
    <event type="aaa">
      <timestamp>App$Timestamp@5c909414</timestamp>
    </event>
    <event type="bbb">
      <timestamp>App$Timestamp@65466a6a</timestamp>
    </event>
  </item>
</items>
Show de-serialization of ArrayList<Item> items:
App$Items@3eb7fc54
Show correct type information in de-serialization for elements in e:
App$EventAAA
App$EventBBB

如您所见,EventAAA和EventBBB被序列化为

您应该能够像对待代码一样使用它;您需要用真实的类替换存根类。

 类似资料:
  • 我定义了一个类来存储我的应用程序的配置数据。我想将其实例保存到xml并为此使用XStream。但是当我尝试编写实例时,我总是遇到内存错误。 这是我的类定义: ...等所有标准getter和setter 下面是我将单个对象导出为xml的处理程序 每次我抛出“线程中的异常”JavaFX应用程序线程“java.lang.OutOfMemoryError:java堆空间”。我不明白为什么这么简单的类会抛出

  • 如何编写java类来读取此XMl文件 我试过这样 但我得到了这个错误 请帮我解决这个问题。。。 非常感谢。

  • 我为基本上是Bèzier路径的创建了一些。为此,我转换了类型为和的路径元素,为此我还有转换器: 我有一个测试代码: 混搭路径时创建的文件如下所示,这是我基本上想要的: 但是,在解组XML时,我遇到了这个异常: PathConverter中的第52行指向该行(在for循环中的第一次调用): 我的猜测是,这个问题与方法上的和方法有关,这样读者仍然处于它期望的结束节点的状态。对于其他两个转换器,我也有测

  • 这里有两个xsd定义,它们几乎90%相似。下面是第一个xsd的框架: 第二个xsd是: 现在,这两个XSD在两个不同的包中生成两组类。我正在使用JAXB来解组收到的XML。XML是从这两个XSD生成的。 在创建JAXB上下文时,它给我带来了错误,因为我相信大多数类都会导致冲突。 下面是错误跟踪: 如果有人能给我提出任何解决方案,那就太好了。 谢谢

  • 在通过RabbitMQ发送数据时,我使用XStream1.4.8对XML进行序列化。在某些情况下,会将类名添加到生成的XML中,从而中断反序列化。我最难解释的问题是,在生产中,某个XML值不会生成异常,而在dev中,我会得到一个异常。 在开发中,我从来没有看到额外的类提到。我可以通过删除字符串“”和关闭标记来“修复”这一点,但我想要理解。 实际上我并不关心在线交换的数据格式是什么。类名是否存在对我

  • 然后我调用子类中的方法。 我希望有一个对象创建的基础上,子类已经被调用,如果这是有意义的?