Package de.ailis.pherialize

Source Code of de.ailis.pherialize.Serializer

/*
* $Id$
* Copyright (C) 2009 Klaus Reimer <k@ailis.de>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

package de.ailis.pherialize;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import de.ailis.pherialize.exceptions.SerializeException;


/**
* Serializes Java objects in a PHP serializer format string.
*
* @author Klaus Reimer (k.reimer@iplabs.de)
* @version $Revision$
*/

public class Serializer
{
    /** The object history for resolving references */
    private final List<Object> history;


    /**
     * Constructor
     */

    public Serializer()
    {
        super();
        this.history = new ArrayList<Object>();
    }


    /**
     * Serializes the specified object.
     *
     * @param object
     *            The object
     * @return The serialized data
     */

    public String serialize(final Object object)
    {
        StringBuffer buffer;

        buffer = new StringBuffer();
        serializeObject(object, buffer);
        return buffer.toString();
    }

   
    /**
     * This method is used internally for recursively scanning the object while
     * serializing. It just calls the other serializeObject method defaulting
     * to allowing references.
     *
     * @param object
     *            The object to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeObject(final Object object, final StringBuffer buffer)
    {
        serializeObject(object, buffer, true);
    }
   
   
    /**
     * This method is used internally for recursively scanning the object while
     * serializing. If references are allowed or not can be specified with the
     * last parameter. For example Array/Map-Keys are not allowed to be a
     * reference.
     *
     * @param object
     *            The object to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     * @param allowReference
     *            If reference is allowed for this object
     */

    private void serializeObject(final Object object, final StringBuffer buffer,
        final boolean allowReference)
    {
        if (object == null)
        {
            serializeNull(buffer);
        }
        else if (allowReference && serializeReference(object, buffer))
        {
            return;
        }
        else if (object instanceof String)
        {
            serializeString((String) object, buffer);
        }
        else if (object instanceof Character)
        {
            serializeCharacter((Character) object, buffer);
        }
        else if (object instanceof Integer)
        {
            serializeInteger(((Integer) object).intValue(), buffer);
        }
        else if (object instanceof Short)
        {
            serializeInteger(((Short) object).intValue(), buffer);
        }
        else if (object instanceof Byte)
        {
            serializeInteger(((Byte) object).intValue(), buffer);
        }
        else if (object instanceof Long)
        {
            serializeLong(((Long) object).longValue(), buffer);
        }
        else if (object instanceof Double)
        {
            serializeDouble(((Double) object).doubleValue(), buffer);
        }
        else if (object instanceof Float)
        {
            serializeDouble(((Float) object).doubleValue(), buffer);
        }
        else if (object instanceof Boolean)
        {
            serializeBoolean((Boolean) object, buffer);
        }
        else if (object instanceof Mixed)
        {
            serializeMixed((Mixed) object, buffer);
            return;
        }
        else if (object instanceof Object[])
        {
            serializeArray((Object[]) object, buffer);
            return;
        }
        else if (object instanceof Collection<?>)
        {
            serializeCollection((Collection<?>) object, buffer);
            return;
        }
        else if (object instanceof Map<?, ?>)
        {
            serializeMap((Map<?, ?>) object, buffer);
            return;
        }
        else if (object instanceof Serializable)
        {
            serializeSerializable((Serializable) object, buffer);
            return;
        }
        else
        {
            throw new SerializeException("Unable to serialize "
                + object.getClass().getName());
        }

        this.history.add(object);
    }


    /**
     * Tries to serialize a reference if the specified object was already
     * serialized. It returns true in this case. If the object was not
     * serialized before then false is returned.
     *
     * @param object
     *            The object to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     * @return If a reference was serialized or not
     */

    private boolean serializeReference(final Object object, final StringBuffer buffer)
    {
        Iterator<?> iterator;
        int index;
        boolean isReference;
       
        // Don't allow references for simple types because here PHP and
        // Java are VERY different and the best way it to simply disallow
        // References for these types
        if (object instanceof Number || object instanceof Boolean ||
            object instanceof String)
        {
            return false;
        }

        iterator = this.history.iterator();
        index = 0;
        isReference = false;
        while (iterator.hasNext())
        {
            if (iterator.next() == object)
            {
                buffer.append("R:");
                buffer.append(index + 1);
                buffer.append(';');
                isReference = true;
                break;
            }
            index++;
        }
        return isReference;
    }


    /**
     * Serializes the specified mixed object and appends it to the serialization
     * buffer.
     *
     * @param mixed
     *            The object to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeMixed(final Mixed mixed, final StringBuffer buffer)
    {
        serializeObject(mixed.getValue(), buffer);
    }


    /**
     * Serializes the specified string and appends it to the serialization
     * buffer.
     *
     * @param string
     *            The string to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeString(final String string, final StringBuffer buffer)
    {
        buffer.append("s:");
        buffer.append(string.length());
        buffer.append(":\"");
        buffer.append(string);
        buffer.append("\";");
    }


    /**
     * Serializes the specified character and appends it to the serialization
     * buffer.
     *
     * @param value
     *            The value to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeCharacter(final Character value, final StringBuffer buffer)
    {
        buffer.append("s:1:\"");
        buffer.append(value);
        buffer.append("\";");
    }


    /**
     * Adds a serialized NULL to the serialization buffer.
     *
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeNull(final StringBuffer buffer)
    {
        buffer.append("N;");
    }


    /**
     * Serializes the specified integer number and appends it to the
     * serialization buffer.
     *
     * @param number
     *            The integer number to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeInteger(final int number, final StringBuffer buffer)
    {
        buffer.append("i:");
        buffer.append(number);
        buffer.append(';');
    }


    /**
     * Serializes the specified lonf number and appends it to the serialization
     * buffer.
     *
     * @param number
     *            The lonf number to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeLong(final long number, final StringBuffer buffer)
    {
        if ((number >= Integer.MIN_VALUE) && (number <= Integer.MAX_VALUE))
        {
            buffer.append("i:");
        }
        else
        {
            buffer.append("d:");
        }
        buffer.append(number);
        buffer.append(';');
    }


    /**
     * Serializes the specfied double number and appends it to the serialization
     * buffer.
     *
     * @param number
     *            The number to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeDouble(final double number, final StringBuffer buffer)
    {
        buffer.append("d:");
        buffer.append(number);
        buffer.append(';');
    }


    /**
     * Serializes the specfied boolean and appends it to the serialization
     * buffer.
     *
     * @param value
     *            The value to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeBoolean(final Boolean value, final StringBuffer buffer)
    {
        buffer.append("b:");
        buffer.append(value.booleanValue() ? 1 : 0);
        buffer.append(';');
    }


    /**
     * Serializes the specfied collection and appends it to the serialization
     * buffer.
     *
     * @param collection
     *            The collection to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeCollection(final Collection<?> collection, final StringBuffer buffer)
    {
        Iterator<?> iterator;
        int index;

        this.history.add(collection);
        buffer.append("a:");
        buffer.append(collection.size());
        buffer.append(":{");
        iterator = collection.iterator();
        index = 0;
        while (iterator.hasNext())
        {
            serializeObject(Integer.valueOf(index), buffer, false);
            this.history.remove(this.history.size() - 1);
            serializeObject(iterator.next(), buffer);
            index++;
        }
        buffer.append('}');
    }


    /**
     * Serializes the specfied array and appends it to the serialization
     * buffer.
     *
     * @param array
     *            The array to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeArray(final Object[] array, final StringBuffer buffer)
    {
        int max;

        this.history.add(array);
        buffer.append("a:");
        max = array.length;
        buffer.append(max);
        buffer.append(":{");
        for (int i = 0; i < max; i++)
        {
            serializeObject(Integer.valueOf(i), buffer, false);
            this.history.remove(this.history.size() - 1);
            serializeObject(array[i], buffer);
        }
        buffer.append('}');
    }

   
    /**
     * Serializes the specfied map and appends it to the serialization buffer.
     *
     * @param map
     *            The map to serialize
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeMap(final Map<?, ?> map, final StringBuffer buffer)
    {
        Iterator<?> iterator;
        Object key;

        this.history.add(map);
        buffer.append("a:");
        buffer.append(map.size());
        buffer.append(":{");
        iterator = map.keySet().iterator();
        while (iterator.hasNext())
        {
            key = iterator.next();
            serializeObject(key, buffer, false);
            this.history.remove(this.history.size() - 1);
            serializeObject(map.get(key), buffer);
        }
        buffer.append('}');
    }


    /**
     * Serializes a serializable object
     *
     * @param object
     *            The serializable object
     * @param buffer
     *            The string buffer to append serialized data to
     */

    private void serializeSerializable(final Serializable object, final StringBuffer buffer)
    {
        String className;
        Class<?> c;
        Field[] fields;
        int i, max;
        Field field;
        String key;
        Object value;
        StringBuffer fieldBuffer;
        int fieldCount;

        this.history.add(object);
        c = object.getClass();
        className = c.getSimpleName();
        buffer.append("O:");
        buffer.append(className.length());
        buffer.append(":\"");
        buffer.append(className);
        buffer.append("\":");

        fieldBuffer = new StringBuffer();
        fieldCount = 0;
        while (c != null)
        {
            fields = c.getDeclaredFields();
            for (i = 0, max = fields.length; i < max; i++)
            {
                field = fields[i];
                if (Modifier.isStatic(field.getModifiers())) continue;
                if (Modifier.isVolatile(field.getModifiers())) continue;

                try
                {
                    field.setAccessible(true);
                    key = field.getName();
                    value = field.get(object);
                    serializeObject(key, fieldBuffer);
                    this.history.remove(this.history.size() - 1);
                    serializeObject(value, fieldBuffer);
                    fieldCount++;
                }
                catch (final SecurityException e)
                {
                    // Field is just ignored when this exception is thrown
                }
                catch (final IllegalArgumentException e)
                {
                    // Field is just ignored when this exception is thrown
                }
                catch (final IllegalAccessException e)
                {
                    // Field is just ignored when this exception is thrown
                }
            }
            c = c.getSuperclass();
        }
        buffer.append(fieldCount);
        buffer.append(":{");
        buffer.append(fieldBuffer);
        buffer.append("}");
    }
}
TOP

Related Classes of de.ailis.pherialize.Serializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.