/** * Copyright 2005-2012 Akiban Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.persistit.encoding; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import com.persistit.DefaultValueCoder; import com.persistit.Value; import com.persistit.exception.ConversionException; /** * <p> * A {@link ValueCoder} that uses standard Java serialization to store and * retrieve object values. This class is related to {@link DefaultValueCoder}. * When Persistit serializes or deserializes an object for which there is no * registered <code>ValueCoder</code>, it implicitly constructs either a * <code>DefaultValueCoder</code> or a <code>SerialValueCoder</code>, depending * on the value of the <code>serialOverride</code> property. See <a * href="../../../Object_Serialization_Notes.html"> Persistit Object * Serialization</a> for details. * </p> * <p> * This class creates a new <code>java.io.ObjectInputStream</code> each time it * is called upon to deserialize an instance of its client class, or a * <code>java.io.ObjectOutputStream</code> to serialize an instance. The format * of the stored data is specified by the <a href= * "http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/serialTOC.html" * > Java Object Serialization Specification</a> with one exception: the class * descriptor is replaced by a handle; an association between handles and class * descriptors is maintained in a separate metadata tree. This avoids * redundantly storing class descriptors for multiple instance of the same * class. * </p> * * @since 1.1 * @version 1.1 */ public final class SerialValueCoder implements ValueCoder { private final ObjectStreamClass _classDescriptor; public SerialValueCoder(final Class<?> clazz) { _classDescriptor = ObjectStreamClass.lookup(clazz); if (_classDescriptor == null) { throw new ConversionException("Not Serializable: " + clazz.getName()); } } /** * <p> * Creates an instance of the supplied class, populates its state by * decoding the supplied <code>Value</code> using standard Java * serialization, and returns it. This method will be called only if this * <code>ValueCoder</code> has been registered with the current * {@link CoderManager} to encode objects having supplied <code>Class</code> * value. Persistit will never call this method to decode a value that was * <code>null</code> when written because null values are handled by * built-in encoding logic. * </p> * * @param value * The <code>Value</code> from which interior fields of the * object are to be retrieved * * @param clazz * The class of the object to be returned. * * @param context * An arbitrary object that can optionally be supplied by the * application to convey an application-specific context for the * operation. (See {@link CoderContext}.) The default value is * <code>null</code>. For <code>SerialValueCoder</code> this * parameter is always ignored. * * @return An <code>Object</code> having the same class as the suppled * <code>clazz</code> parameter. * * @throws ConversionException */ @Override public Object get(final Value value, final Class<?> clazz, final CoderContext context) { try { final ObjectInputStream stream = value.oldValueInputStream(_classDescriptor); final Object object = stream.readObject(); stream.close(); return object; } catch (final Exception e) { throw new ConversionException(e); } } /** * <p> * Encodes the supplied <code>Object</code> into the supplied * <code>Value</code> using standard Java serialization. This method will be * called only if this <code>ValueCoder</code> has been registered with the * current {@link CoderManager} to encode objects having the class of the * supplied object. * </p> * <p> * Upon completion of this method, the backing byte array of the * <code>Value</code> and its size should be updated to reflect the appended * key segment. Use the methods {@link Value#getEncodedBytes}, * {@link Value#getEncodedSize} and {@link Value#setEncodedSize} to * manipulate the byte array directly. More commonly, the implementation of * this method will simply call the appropriate <code>put</code> methods to * write the interior field values into the <code>Value</code> object. * </p> * * @param value * The <code>Value</code> to which the interior data of the * supplied <code>Object</code> should be encoded * * @param object * The object value to encode. This parameter will never be * <code>null</code> because Persistit encodes nulls with a * built-in encoding. * * @param context * An arbitrary object that can optionally be supplied by the * application to convey an application-specific context for the * operation. (See {@link CoderContext}.) The default value is * <code>null</code>. For <code>SerialValueCoder</code> this * parameter is always ignored. */ @Override public void put(final Value value, final Object object, final CoderContext context) { try { final ObjectOutputStream stream = value.oldValueOutputStream(_classDescriptor); stream.writeObject(object); stream.close(); } catch (final Exception e) { throw new ConversionException(e); } } }