尝试使用 JBoss编组API 将 org.dom4j.Document 作为属性序列化Java对象时,我遇到了一个问题。
我正在使用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 + "]";
}
}
主类:
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:
地图:{霍比特人=电影[标题=霍比特人:意想不到的旅程, 导演=彼得杰克逊,年= 2012年, docXml=org.dom4j.tree.DefaultDocument@570c16b7 [文件:名称无效]]} 编组失败:java.io.NotActiveException:writeFields()可能只是 在尚未编写字段时调用 org.jboss.marshalling.river.RiverObjectOutputStream.defaultWriteObject(RiverObjectOutputStream.java:162) 在org.dom4j.QName.writeObject(QName.java:239)处 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在java.lang.reflect.Method.invoke(Method.java:606)at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:569) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:569) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:569) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) 在 org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65) 在 org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56) 在 org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50) 在 org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179) 在 java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:343) 在java.util.HashMap.writeObject(HashMap.java:1129)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在java.lang.reflect.Method.invoke(Method.java:606)at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976) 在 org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854) 在 org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:58) 在 org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:111) at test.t4.WriteExample.goMarshall(WriteExample.java:119)at test.t4.WriteExample.main(WriteExample.java:43)引起:an 发生的异常:在字段qname中的字段属性中 对象中字段docXml中的字段内容中的字段内容 java.util.HashMap@9ffb6306
在 org.dom4j.QName 对象中精确检测到该问题。
答案 0 :(得分:1)
Java序列化规范中解释了发生这种情况的原因:
该类的writeObject方法(如果实现)负责 保存班级的状态。 ObjectOutputStream的 defaultWriteObject或writeFields方法必须调用一次(并且只能调用 在写入任何可能需要的数据之前 相应的readObject方法恢复对象的状态; 即使没有写入可选数据,defaultWriteObject或writeFields 必须仍然被调用一次。如果是defaultWriteObject或writeFields 然后,在写入可选数据(如果有)之前不会调用一次 在以下情况下,实例反序列化的行为是不确定的 ObjectInputStream无法解析定义的类 有问题的writeObject方法。
注意句子“... defaultWriteObject或writeFields方法必须一次(只有一次)之前编写任何可选数据......”(强调添加) 。
QName类在编写可选数据后调用writeFields ,因此违反了规范。 也就是说,我一直在考虑试图找到一种方法来对这种限制更加宽容,但是现在还没有一个简单的修复,没有在两端添加一个类替换来换掉一个类。这是以兼容的方式正确序列化的。
感谢David Lloyd(https://issues.jboss.org/browse/JBMAR-174)
<强>更新强>
问题:谢谢David,我现在明白了。但是我还有一个问题,当使用本机Java Serialization API时,没有遇到问题并且序列化工作(dom4j中的规范违规似乎并没有打扰受质疑的Java API)。 JBoss编组有什么区别吗? (我更新了上面的例子。)
答案:是的,因为Oracle序列化实现比规范更宽松。
Java序列化规范以获取更多详细信息:http://docs.oracle.com/javase/7/docs/platform/serialization/spec/output.html#861
答案 1 :(得分:0)
无答案;请不要upvote 有一些双重结束;尝试使用资源可以简化事情。 虽然错误信息对我来说仍然没有意义。
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();
}