001: /*
002: * Copyright (C) 2004, 2005, 2006 Joe Walnes.
003: * Copyright (C) 2006, 2007 XStream Committers.
004: * All rights reserved.
005: *
006: * The software in this package is published under the terms of the BSD
007: * style license a copy of which has been included with this distribution in
008: * the LICENSE.txt file.
009: *
010: * Created on 24. August 2004 by Joe Walnes
011: */
012: package com.thoughtworks.xstream.converters.reflection;
013:
014: import com.thoughtworks.xstream.converters.ConversionException;
015: import com.thoughtworks.xstream.converters.Converter;
016: import com.thoughtworks.xstream.converters.MarshallingContext;
017: import com.thoughtworks.xstream.converters.UnmarshallingContext;
018: import com.thoughtworks.xstream.core.util.CustomObjectInputStream;
019: import com.thoughtworks.xstream.core.util.CustomObjectOutputStream;
020: import com.thoughtworks.xstream.io.HierarchicalStreamReader;
021: import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
022: import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
023: import com.thoughtworks.xstream.mapper.Mapper;
024:
025: import java.io.Externalizable;
026: import java.io.IOException;
027: import java.io.NotActiveException;
028: import java.io.ObjectInputValidation;
029: import java.util.Map;
030:
031: /**
032: * Converts any object that implements the java.io.Externalizable interface, allowing compatability with native Java
033: * serialization.
034: *
035: * @author Joe Walnes
036: */
037: public class ExternalizableConverter implements Converter {
038:
039: private Mapper mapper;
040:
041: public ExternalizableConverter(Mapper mapper) {
042: this .mapper = mapper;
043: }
044:
045: public boolean canConvert(Class type) {
046: return Externalizable.class.isAssignableFrom(type);
047: }
048:
049: public void marshal(Object source,
050: final HierarchicalStreamWriter writer,
051: final MarshallingContext context) {
052: try {
053: Externalizable externalizable = (Externalizable) source;
054: CustomObjectOutputStream.StreamCallback callback = new CustomObjectOutputStream.StreamCallback() {
055: public void writeToStream(Object object) {
056: if (object == null) {
057: writer.startNode("null");
058: writer.endNode();
059: } else {
060: ExtendedHierarchicalStreamWriterHelper
061: .startNode(writer, mapper
062: .serializedClass(object
063: .getClass()), object
064: .getClass());
065: context.convertAnother(object);
066: writer.endNode();
067: }
068: }
069:
070: public void writeFieldsToStream(Map fields) {
071: throw new UnsupportedOperationException();
072: }
073:
074: public void defaultWriteObject() {
075: throw new UnsupportedOperationException();
076: }
077:
078: public void flush() {
079: writer.flush();
080: }
081:
082: public void close() {
083: throw new UnsupportedOperationException(
084: "Objects are not allowed to call ObjecOutput.close() from writeExternal()");
085: }
086: };
087: CustomObjectOutputStream objectOutput = CustomObjectOutputStream
088: .getInstance(context, callback);
089: externalizable.writeExternal(objectOutput);
090: objectOutput.popCallback();
091: } catch (IOException e) {
092: throw new ConversionException("Cannot serialize "
093: + source.getClass().getName()
094: + " using Externalization", e);
095: }
096: }
097:
098: public Object unmarshal(final HierarchicalStreamReader reader,
099: final UnmarshallingContext context) {
100: final Class type = context.getRequiredType();
101: try {
102: final Externalizable externalizable = (Externalizable) type
103: .newInstance();
104: CustomObjectInputStream.StreamCallback callback = new CustomObjectInputStream.StreamCallback() {
105: public Object readFromStream() {
106: reader.moveDown();
107: Object streamItem = context.convertAnother(
108: externalizable, mapper.realClass(reader
109: .getNodeName()));
110: reader.moveUp();
111: return streamItem;
112: }
113:
114: public Map readFieldsFromStream() {
115: throw new UnsupportedOperationException();
116: }
117:
118: public void defaultReadObject() {
119: throw new UnsupportedOperationException();
120: }
121:
122: public void registerValidation(
123: ObjectInputValidation validation, int priority)
124: throws NotActiveException {
125: throw new NotActiveException("stream inactive");
126: }
127:
128: public void close() {
129: throw new UnsupportedOperationException(
130: "Objects are not allowed to call ObjectInput.close() from readExternal()");
131: }
132: };
133: CustomObjectInputStream objectInput = CustomObjectInputStream
134: .getInstance(context, callback);
135: externalizable.readExternal(objectInput);
136: objectInput.popCallback();
137: return externalizable;
138: } catch (InstantiationException e) {
139: throw new ConversionException("Cannot construct "
140: + type.getClass(), e);
141: } catch (IllegalAccessException e) {
142: throw new ConversionException("Cannot construct "
143: + type.getClass(), e);
144: } catch (IOException e) {
145: throw new ConversionException("Cannot externalize "
146: + type.getClass(), e);
147: } catch (ClassNotFoundException e) {
148: throw new ConversionException("Cannot externalize "
149: + type.getClass(), e);
150: }
151: }
152: }
|