/* * Copyright (C) 2004, 2005 Joe Walnes. * Copyright (C) 2006, 2007 XStream Committers. * All rights reserved. * * The software in this package is published under the terms of the BSD * style license a copy of which has been included with this distribution in * the LICENSE.txt file. * * Created on 23. August 2004 by Joe Walnes */ package com.thoughtworks.xstream.core.util; import java.io.IOException; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.util.Map; import com.thoughtworks.xstream.converters.ConversionException; import com.thoughtworks.xstream.converters.DataHolder; public class CustomObjectOutputStream extends ObjectOutputStream { private FastStack callbacks = new FastStack(1); private FastStack customFields = new FastStack(1); private static final String DATA_HOLDER_KEY = CustomObjectOutputStream.class.getName(); public static synchronized CustomObjectOutputStream getInstance(DataHolder whereFrom, StreamCallback callback) { try { CustomObjectOutputStream result = (CustomObjectOutputStream) whereFrom.get(DATA_HOLDER_KEY); if (result == null) { result = new CustomObjectOutputStream(callback); whereFrom.put(DATA_HOLDER_KEY, result); } else { result.pushCallback(callback); } return result; } catch (IOException e) { throw new ConversionException("Cannot create CustomObjectStream", e); } } public static interface StreamCallback { void writeToStream(Object object) throws IOException; void writeFieldsToStream(Map fields) throws IOException; void defaultWriteObject() throws IOException; void flush() throws IOException; void close() throws IOException; } /** * Warning, this object is expensive to create (due to functionality inherited from superclass). * Use the static fetch() method instead, wherever possible. * * @see #getInstance(com.thoughtworks.xstream.converters.DataHolder, com.thoughtworks.xstream.core.util.CustomObjectOutputStream.StreamCallback) */ public CustomObjectOutputStream(StreamCallback callback) throws IOException, SecurityException { this.callbacks.push(callback); } /** * Allows the CustomObjectOutputStream (which is expensive to create) to be reused. */ public void pushCallback(StreamCallback callback) { this.callbacks.push(callback); } public StreamCallback popCallback(){ return (StreamCallback) this.callbacks.pop(); } public StreamCallback peekCallback(){ return (StreamCallback) this.callbacks.peek(); } /*** Methods to delegate to callback ***/ public void defaultWriteObject() throws IOException { peekCallback().defaultWriteObject(); } protected void writeObjectOverride(Object obj) throws IOException { peekCallback().writeToStream(obj); } public void writeBoolean(boolean val) throws IOException { peekCallback().writeToStream(val ? Boolean.TRUE : Boolean.FALSE); // JDK 1.3 friendly } public void writeByte(int val) throws IOException { peekCallback().writeToStream(new Byte((byte) val)); } public void writeInt(int val) throws IOException { peekCallback().writeToStream(new Integer(val)); } public void writeChar(int val) throws IOException { peekCallback().writeToStream(new Character((char)val)); } public void writeDouble(double val) throws IOException { peekCallback().writeToStream(new Double(val)); } public void writeFloat(float val) throws IOException { peekCallback().writeToStream(new Float(val)); } public void writeLong(long val) throws IOException { peekCallback().writeToStream(new Long(val)); } public void writeShort(int val) throws IOException { peekCallback().writeToStream(new Short((short) val)); } public void write(byte[] buf) throws IOException { peekCallback().writeToStream(buf); } public void writeChars(String str) throws IOException { peekCallback().writeToStream(str.toCharArray()); } public void writeUTF(String str) throws IOException { peekCallback().writeToStream(str); } public void write(int val) throws IOException { peekCallback().writeToStream(new Byte((byte) val)); } public void write(byte[] buf, int off, int len) throws IOException { byte[] b = new byte[len]; System.arraycopy(buf, off, b, 0, len); peekCallback().writeToStream(b); } public void flush() throws IOException { peekCallback().flush(); } public void close() throws IOException { peekCallback().close(); } public PutField putFields() { CustomPutField result = new CustomPutField(); customFields.push(result); return result; } public void writeFields() throws IOException { CustomPutField customPutField = (CustomPutField) customFields.pop(); peekCallback().writeFieldsToStream(customPutField.asMap()); } private class CustomPutField extends PutField { private final Map fields = new OrderRetainingMap(); public Map asMap() { return fields; } public void write(ObjectOutput out) throws IOException { peekCallback().writeToStream(asMap()); } public void put(String name, Object val) { fields.put(name, val); } public void put(String name, byte val) { put(name, new Byte(val)); } public void put(String name, char val) { put(name, new Character(val)); } public void put(String name, double val) { put(name, new Double(val)); } public void put(String name, float val) { put(name, new Float(val)); } public void put(String name, int val) { put(name, new Integer(val)); } public void put(String name, long val) { put(name, new Long(val)); } public void put(String name, short val) { put(name, new Short(val)); } public void put(String name, boolean val) { put(name, val ? Boolean.TRUE : Boolean.FALSE); // JDK 1.3 friendly } } /****** Unsupported methods ******/ public void reset() { throw new UnsupportedOperationException(); } public void useProtocolVersion(int version) { throw new UnsupportedOperationException(); } public void writeBytes(String str) { throw new UnsupportedOperationException(); } public void writeUnshared(Object obj) { throw new UnsupportedOperationException(); } }