All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jfirer.fse.serializer.ObjectSerializer Maven / Gradle / Ivy

The newest version!
package com.jfirer.fse.serializer;

import com.jfirer.baseutil.reflect.UNSAFE;
import com.jfirer.baseutil.reflect.ValueAccessor;
import com.jfirer.fse.*;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ObjectSerializer extends CycleFlagSerializer implements FseSerializer
{
    Entry[] entries;
    private Class type;

    @Override
    public void init(Class type, SerializerFactory serializerFactory)
    {
        this.type = type;
        List list = getAllFields(type);
        entries = new Entry[list.size()];
        for (int i = 0; i < list.size(); i++)
        {
            Entry entry = buildEntry(serializerFactory, list.get(i));
            entries[i] = entry;
        }
    }

    private Entry buildEntry(SerializerFactory serializerFactory, Field field)
    {
        Entry entry = new Entry();
        entry.field = field;
        entry.fieldType = field.getType();
        entry.accessor = new ValueAccessor(field);
        Class fieldType = field.getType();
        if (fieldType.isArray())
        {
            entry.array = true;
            entry.finalType = true;
            entry.serializer = serializerFactory.getSerializer(fieldType);
        }
        else
        {
            entry.type = getType(fieldType);
            if (entry.type == BuildInType.OBJECT && (entry.fieldType.isInterface() == false && Modifier.isAbstract(entry.fieldType.getModifiers()) == false))
            {
                if (Modifier.isFinal(fieldType.getModifiers()))
                {
                    entry.finalType = true;
                }
                FseSerializer serializer = serializerFactory.getSerializer(fieldType);
                entry.serializer = serializer;
            }
        }
        return entry;
    }

    private List getAllFields(Class type)
    {
        List list = new ArrayList();
        while (type != Object.class)
        {
            for (Field each : type.getDeclaredFields())
            {
                if (each.isAnnotationPresent(FseIgnore.class))
                {
                    continue;
                }
                int modifiers = each.getModifiers();
                if (Modifier.isStatic(modifiers))
                {
                    continue;
                }
                list.add(each);
            }
            type = type.getSuperclass();
        }
        Collections.sort(list, new Comparator()
        {
            @Override
            public int compare(Field o1, Field o2)
            {
                return o1.toString().compareTo(o2.toString());
            }
        });
        return list;
    }

    private BuildInType getType(Class fieldType)
    {
        if (fieldType.isPrimitive() == false)
        {
            return BuildInType.OBJECT;
        }
        if (fieldType == int.class)
        {
            return BuildInType.INT;
        }
        else if (fieldType == byte.class)
        {
            return BuildInType.BYTE;
        }
        else if (fieldType == char.class)
        {
            return BuildInType.CHAR;
        }
        else if (fieldType == boolean.class)
        {
            return BuildInType.BOOLEAN;
        }
        else if (fieldType == float.class)
        {
            return BuildInType.FLOAT;
        }
        else if (fieldType == long.class)
        {
            return BuildInType.LONG;
        }
        else if (fieldType == short.class)
        {
            return BuildInType.SHORT;
        }
        else if (fieldType == double.class)
        {
            return BuildInType.DOUBLE;
        }
        else
        {
            throw new IllegalArgumentException();
        }
    }

    @Override
    public void doWriteToBytes(Object o, InternalByteArray byteArray, FseContext fseContext, int depth)
    {
        for (Entry entry : entries)
        {
            if (entry.array == false)
            {
                serializeProperty(o, byteArray, fseContext, entry, depth);
            }
            else
            {
                Object property = entry.accessor.get(o);
                if (property == null)
                {
                    byteArray.put(Fse.NULL);
                    continue;
                }
                entry.serializer.writeToBytes(entry.accessor.get(o), Fse.USE_FIELD_TYPE, byteArray, fseContext, depth);
            }
        }
    }

    @Override
    public Object readBytes(InternalByteArray byteArray, FseContext fseContext)
    {
        Object instance = UNSAFE.allocateInstance(type);
        fseContext.collectObject(instance);
        for (Entry entry : entries)
        {
            if (entry.array == false)
            {
                deSerializeProperty(byteArray, fseContext, instance, entry);
            }
            else
            {
                int    flag = byteArray.readVarInt();
                Object result;
                if (flag == Fse.NULL)
                {
                    result = null;
                }
                else if (flag == Fse.USE_FIELD_TYPE)
                {
                    result = entry.serializer.readBytes(byteArray, fseContext);
                }
                else if (flag < 0)
                {
                    result = fseContext.getObjectByIndex(0 - flag);
                }
                else
                {
                    result = fseContext.getClassRegistry(flag).getSerializer().readBytes(byteArray, fseContext);
                }
                entry.accessor.setObject(instance, result);
            }
        }
        return instance;
    }

    private void deSerializeProperty(InternalByteArray byteArray, FseContext fseContext, Object instance, Entry entry)
    {
        switch (entry.type)
        {
            case INT:
                entry.accessor.set(instance, byteArray.readVarInt());
                break;
            case BYTE:
                entry.accessor.set(instance, byteArray.get());
                break;
            case CHAR:
                entry.accessor.set(instance, byteArray.readVarChar());
                break;
            case LONG:
                entry.accessor.set(instance, byteArray.readVarLong());
                break;
            case FLOAT:
                entry.accessor.set(instance, byteArray.readFloat());
                break;
            case SHORT:
                entry.accessor.set(instance, byteArray.readShort());
                break;
            case DOUBLE:
                entry.accessor.set(instance, byteArray.readDouble());
                break;
            case BOOLEAN:
                if (byteArray.get() == 0)
                {
                    entry.accessor.set(instance, true);
                }
                else
                {
                    entry.accessor.set(instance, false);
                }
                break;
            case OBJECT:
                int flag = byteArray.readVarInt();
                Object result;
                if (flag == Fse.NULL)
                {
                    result = null;
                }
                else if (flag == Fse.USE_FIELD_TYPE)
                {
                    result = entry.serializer.readBytes(byteArray, fseContext);
                }
                else if (flag < 0)
                {
                    result = fseContext.getObjectByIndex(0 - flag);
                }
                else
                {
                    result = fseContext.getClassRegistry(flag).getSerializer().readBytes(byteArray, fseContext);
                }
                entry.accessor.setObject(instance, result);
                break;
        }
    }

    private void serializeProperty(Object o, InternalByteArray byteArray, FseContext fseContext, Entry entry, int depth)
    {
        switch (entry.type)
        {
            case INT:
                byteArray.writeVarInt(entry.accessor.getInt(o));
                break;
            case BYTE:
                byteArray.put(entry.accessor.getByte(o));
                break;
            case CHAR:
                byteArray.writeVarChar(entry.accessor.getChar(o));
                break;
            case LONG:
                byteArray.writeVarLong(entry.accessor.getLong(o));
                break;
            case FLOAT:
                byteArray.writeFloat(entry.accessor.getFloat(o));
                break;
            case SHORT:
                byteArray.writeShort(entry.accessor.getShort(o));
                break;
            case DOUBLE:
                byteArray.writeDouble(entry.accessor.getDouble(o));
                break;
            case BOOLEAN:
                if (entry.accessor.getBoolean(o))
                {
                    byteArray.put((byte) 0);
                }
                else
                {
                    byteArray.put((byte) 1);
                }
                break;
            case OBJECT:
                Object property = entry.accessor.get(o);
                if (property == null)
                {
                    byteArray.put(Fse.NULL);
                    break;
                }
                if (entry.finalType || property.getClass() == entry.fieldType)
                {
                    entry.serializer.writeToBytes(property, Fse.USE_FIELD_TYPE, byteArray, fseContext, depth);
                }
                else
                {
                    fseContext.serialize(property, byteArray, depth);
                }
                break;
        }
    }

    enum BuildInType
    {
        INT, BYTE, CHAR, BOOLEAN, FLOAT, LONG, SHORT, DOUBLE,//
        OBJECT
    }

    class Entry
    {
        Field         field;
        Class         fieldType;
        boolean       array     = false;
        boolean       finalType = false;
        BuildInType   type;
        ValueAccessor accessor;
        FseSerializer serializer;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy