📄 serializableconverter.java
字号:
package com.thoughtworks.xstream.converters.reflection;import com.thoughtworks.xstream.converters.ConversionException;import com.thoughtworks.xstream.converters.Converter;import com.thoughtworks.xstream.converters.MarshallingContext;import com.thoughtworks.xstream.converters.UnmarshallingContext;import com.thoughtworks.xstream.core.util.CustomObjectInputStream;import com.thoughtworks.xstream.core.util.CustomObjectOutputStream;import com.thoughtworks.xstream.io.HierarchicalStreamReader;import com.thoughtworks.xstream.io.HierarchicalStreamWriter;import com.thoughtworks.xstream.mapper.Mapper;import java.io.IOException;import java.io.InvalidObjectException;import java.io.ObjectInputStream;import java.io.ObjectInputValidation;import java.io.ObjectOutputStream;import java.io.ObjectStreamClass;import java.io.ObjectStreamField;import java.io.Serializable;import java.lang.reflect.Field;import java.util.ArrayList;import java.util.Collections;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;/** * Emulates the mechanism used by standard Java Serialization for classes that implement java.io.Serializable AND * implement a custom readObject()/writeObject() method. * * <h3>Supported features of serialization</h3> * <ul> * <li>readObject(), writeObject()</li> * <li>class inheritance</li> * <li>readResolve(), writeReplace()</li> * </ul> * * <h3>Currently unsupported features</h3> * <ul> * <li>putFields(), writeFields(), readFields()</li> * <li>ObjectStreamField[] serialPersistentFields</li> * <li>ObjectInputValidation</li> * </ul> * * @author Joe Walnes */public class SerializableConverter implements Converter { private final SerializationMethodInvoker serializationMethodInvoker = new SerializationMethodInvoker(); private final Mapper mapper; private final ReflectionProvider reflectionProvider; private static final String ELEMENT_NULL = "null"; private static final String ELEMENT_DEFAULT = "default"; private static final String ATTRIBUTE_CLASS = "class"; private static final String ATTRIBUTE_SERIALIZATION = "serialization"; private static final String ATTRIBUTE_VALUE_CUSTOM = "custom"; private static final String ELEMENT_FIELDS = "fields"; private static final String ELEMENT_FIELD = "field"; private static final String ATTRIBUTE_NAME = "name"; public SerializableConverter(Mapper mapper, ReflectionProvider reflectionProvider) { this.mapper = mapper; this.reflectionProvider = reflectionProvider; } public boolean canConvert(Class type) { return Serializable.class.isAssignableFrom(type) && ( serializationMethodInvoker.supportsReadObject(type, true) || serializationMethodInvoker.supportsWriteObject(type, true) ); } public void marshal(Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { final Object replacedSource = serializationMethodInvoker.callWriteReplace(source); if (replacedSource.getClass() != source.getClass()) { writer.addAttribute(mapper.attributeForReadResolveField(), mapper.serializedClass(replacedSource.getClass())); } writer.addAttribute(ATTRIBUTE_SERIALIZATION, ATTRIBUTE_VALUE_CUSTOM); // this is an array as it's a non final value that's accessed from an anonymous inner class. final Class[] currentType = new Class[1]; final boolean[] writtenClassWrapper = {false}; CustomObjectOutputStream.StreamCallback callback = new CustomObjectOutputStream.StreamCallback() { public void writeToStream(Object object) { if (object == null) { writer.startNode(ELEMENT_NULL); writer.endNode(); } else { writer.startNode(mapper.serializedClass(object.getClass())); context.convertAnother(object); writer.endNode(); } } public void writeFieldsToStream(Map fields) { ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType[0]); writer.startNode(ELEMENT_DEFAULT); for (Iterator iterator = fields.keySet().iterator(); iterator.hasNext();) { String name = (String) iterator.next(); ObjectStreamField field = objectStreamClass.getField(name); Object value = fields.get(name); if (field == null) { throw new ObjectAccessException("Class " + value.getClass().getName() + " may not write a field named '" + name + "'"); } if (value != null) { writer.startNode(mapper.serializedMember(currentType[0], name)); if (field.getType() != value.getClass() && !field.getType().isPrimitive()) { writer.addAttribute(ATTRIBUTE_CLASS, mapper.serializedClass(value.getClass())); } context.convertAnother(value); writer.endNode(); } } writer.endNode(); } public void defaultWriteObject() { boolean writtenDefaultFields = false; ObjectStreamClass objectStreamClass = ObjectStreamClass.lookup(currentType[0]); if (objectStreamClass == null) { return; } ObjectStreamField[] fields = objectStreamClass.getFields(); for (int i = 0; i < fields.length; i++) { ObjectStreamField field = fields[i]; Object value = readField(field, currentType[0], replacedSource); if (value != null) { if (!writtenClassWrapper[0]) { writer.startNode(mapper.serializedClass(currentType[0])); writtenClassWrapper[0] = true; } if (!writtenDefaultFields) { writer.startNode(ELEMENT_DEFAULT); writtenDefaultFields = true; } writer.startNode(mapper.serializedMember(currentType[0], field.getName())); Class actualType = value.getClass(); Class defaultType = mapper.defaultImplementationOf(field.getType()); if (!actualType.equals(defaultType)) { writer.addAttribute(ATTRIBUTE_CLASS, mapper.serializedClass(actualType)); } context.convertAnother(value); writer.endNode(); } } if (writtenClassWrapper[0] && !writtenDefaultFields) { writer.startNode(ELEMENT_DEFAULT); writer.endNode(); } else if (writtenDefaultFields) { writer.endNode(); } } public void flush() { writer.flush(); } public void close() { throw new UnsupportedOperationException("Objects are not allowed to call ObjectOutputStream.close() from writeObject()"); } }; try { Iterator classHieararchy = hierarchyFor(replacedSource.getClass()); while (classHieararchy.hasNext()) { currentType[0] = (Class) classHieararchy.next(); if (serializationMethodInvoker.supportsWriteObject(currentType[0], false)) { writtenClassWrapper[0] = true; writer.startNode(mapper.serializedClass(currentType[0])); ObjectOutputStream objectOutputStream = CustomObjectOutputStream.getInstance(context, callback); serializationMethodInvoker.callWriteObject(currentType[0], replacedSource, objectOutputStream); writer.endNode(); } else if (serializationMethodInvoker.supportsReadObject(currentType[0], false)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -