无法使用 JBoss 编组 API 序列化 org.dom4j.Document

Can't serialize org.dom4j.Document using JBoss Marshalling API

我在尝试使用 org.dom4j.Document 序列化 Java 对象作为属性时遇到问题 JBoss 编组 API.

我正在使用 JDK 1.7

与 dom4j 1.5.2 相同的问题。

Java 对象:

package test.t4;
import org.dom4j.Document;
public class Movie implements java.io.Serializable {

    private static final long serialVersionUID = 1L;

    private String title;
    private String director;
    private transient int code;
    private int year;
    private Document docXml;

    public Movie() {
        super();
    }

    public Movie(String title, String director, int code, int year) {
        super();
        this.title = title;
        this.director = director;
        this.code = code;
        this.year = year;
    }

    //Getters and Setters

    @Override
    public String toString() {
        return "Movie [title=" + title + ", director=" + director + ", year="
                + year + ", docXml=" + docXml + "]";
    }

}

主要Class:

package test.t4;

import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.jboss.marshalling.Marshaller;
import org.jboss.marshalling.MarshallerFactory;
import org.jboss.marshalling.Marshalling;
import org.jboss.marshalling.MarshallingConfiguration;
import org.jboss.marshalling.river.RiverMarshallerFactory;

public final class WriteExample {

    final static String file = "D:/TEST/serialization/jboss40.ser";

    public static void main(String[] args) {

        Document docXml = null;
        Movie mov0 = new Movie("The Hobbit: An Unexpected Journey",
                "Peter Jackson", 123456780, 2012);
        docXml = createDocument();
        mov0.setDocXml(docXml);

        Map<String, Movie> maps = new HashMap<String, Movie>();
        maps.put("Hobbit", mov0);

        System.out.println("maps : " + maps);

        goMarshall(maps);
      //serialize(maps);//When using the native Serialization Java API, the serialization works.
    }

public static void serialize(Map<String, Movie> maps) {
    try {
        FileOutputStream fileOut = new FileOutputStream(fileJDKSerialize);
        ObjectOutputStream out = new ObjectOutputStream(fileOut);
        out.writeObject(maps);
        out.close();
        fileOut.close();
        System.out
                .printf("Serialized data is saved in " + fileJDKSerialize);
    } catch (IOException i) {
        i.printStackTrace();
    }
}

    public static Document createDocument() {
        Document document = DocumentHelper.createDocument();
        Element starring = document.addElement("Starring");

        Element actor1 = starring.addElement("actor")
                .addAttribute("name", "Martin Freeman")
                .addAttribute("character", "Bilbo").addText("Good morning.");
        Element actor2 = starring
                .addElement("actor")
                .addAttribute("name", "Ian McKellen")
                .addAttribute("character", "Gandalf")
                .addText(
                        "What do you mean? Do you mean to wish me a good morning or do you mean that it is a good morning whether I want it or not? Or perhaps you mean to say that you feel good on this particular morning. Or are you simply stating that this is a morning to be good on? ");

        return document;
    }

public static void goMarshall(Object obj) {
    // Get the factory for the "river" marshalling protocol
    final MarshallerFactory marshallerFactory = new RiverMarshallerFactory();// Marshalling.getProvidedMarshallerFactory("river");

    // Create a configuration
    final MarshallingConfiguration configuration = new MarshallingConfiguration();
    // Use version 3
    configuration.setVersion(3);
    FileOutputStream os = null;
    try {

        final Marshaller marshaller = marshallerFactory
                .createMarshaller(configuration);
        os = new FileOutputStream(file);
        marshaller.start(Marshalling.createByteOutput(os));
        marshaller.writeObject(obj);
        marshaller.finish();
        os.close();

    } catch (IOException e) {
        System.err.print("Marshalling failed: ");
        e.printStackTrace();
    }
}
}

错误 StackTrace:

maps : {Hobbit=Movie [title=The Hobbit: An Unexpected Journey, director=Peter Jackson, year=2012, docXml=org.dom4j.tree.DefaultDocument@570c16b7 [Document: name null]]} Marshalling failed: java.io.NotActiveException: writeFields() may only be called when the fields have not yet been written at org.jboss.marshalling.river.RiverObjectOutputStream.defaultWriteObject(RiverObjectOutputStream.java:162) at org.dom4j.QName.writeObject(QName.java:239) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271) at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976) at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032) at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988) at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967) at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:569) at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032) at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988) at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:569) at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032) at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988) at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:569) at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032) at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988) at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032) at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988) at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65) at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56) at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50) at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:343) at java.util.HashMap.writeObject(HashMap.java:1129) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271) at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976) at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) at org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:58) at org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:111) at test.t4.WriteExample.goMarshall(WriteExample.java:119) at test.t4.WriteExample.main(WriteExample.java:43) Caused by: an exception which occurred: in field qname in field attributes in field content in field content in field docXml in object java.util.HashMap@9ffb6306

在对象 org.dom4j.QName.

中准确检测到问题

没有答案;请不要投票 有一些双重关闭; try-with-resources 可能会简化事情。 尽管错误消息对我来说仍然没有意义。

    try (Marshaller marshaller = marshallerFactory
                .createMarshaller(configuration)) {
        try (FileOutputStream os = new FileOutputStream(file) {

            marshaller.start(Marshalling.createByteOutput(os));
            marshaller.writeObject(obj);
            marshaller.finish();
        }
    } catch (IOException e) {
        System.err.print("Marshalling failed: ");
        e.printStackTrace();
    }

Java 序列化规范中解释了发生这种情况的原因:

The class's writeObject method, if implemented, is responsible for saving the state of the class. Either ObjectOutputStream's defaultWriteObject or writeFields method must be called once (and only once) before writing any optional data that will be needed by the corresponding readObject method to restore the state of the object; even if no optional data is written, defaultWriteObject or writeFields must still be invoked once. If defaultWriteObject or writeFields is not invoked once prior to the writing of optional data (if any), then the behavior of instance deserialization is undefined in cases where the ObjectInputStream cannot resolve the class which defined the writeObject method in question.

注意句子“...defaultWriteObject 或 writeFields 方法 必须 调用一次(并且仅调用一次) 写入任何可选数据之前...”(强调)。

QName class 在 写入可选数据后调用 writeFields ,因此它违反了规范。 也就是说,我一直在考虑尝试找到一种对这个限制更宽松的方法,但目前还没有一个简单的解决办法,除了在两端添加一个 class 替换来换出class 对于以兼容方式正确序列化的那个。

感谢David Lloyd (https://issues.jboss.org/browse/JBMAR-174)

更新:

问题: 谢谢大卫,我现在明白了。但我仍然有一个问题,当使用本机 Java 序列化 API 时没有遇到问题并且序列化有效(dom4j 中的规范违规似乎没有打扰被质疑的人 Java API)。 JBoss 编组有什么区别吗? (我更新了上面的例子)。

回答:是的,因为 Oracle 序列化实现比规范更宽松。

Java 序列化规范的更多详细信息:http://docs.oracle.com/javase/7/docs/platform/serialization/spec/output.html#861