Package com.dyuproject.protostuff.runtime

Source Code of com.dyuproject.protostuff.runtime.PolymorphicMapSchema

//================================================================================
//Copyright (c) 2012, David Yu
//All rights reserved.
//--------------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
// 3. Neither the name of protostuff nor the names of its contributors may be used
//    to endorse or promote products derived from this software without
//    specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//================================================================================


package com.dyuproject.protostuff.runtime;

import static com.dyuproject.protostuff.runtime.RuntimeFieldFactory.ID_ENUM_MAP;
import static com.dyuproject.protostuff.runtime.RuntimeFieldFactory.ID_MAP;
import static com.dyuproject.protostuff.runtime.RuntimeFieldFactory.STR_ENUM_MAP;
import static com.dyuproject.protostuff.runtime.RuntimeFieldFactory.STR_MAP;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.IdentityHashMap;
import java.util.Map;

import com.dyuproject.protostuff.GraphInput;
import com.dyuproject.protostuff.Input;
import com.dyuproject.protostuff.Output;
import com.dyuproject.protostuff.Pipe;
import com.dyuproject.protostuff.ProtostuffException;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.StatefulOutput;
import com.dyuproject.protostuff.runtime.IdStrategy.Wrapper;
import com.dyuproject.protostuff.runtime.RuntimeEnv.Instantiator;

/**
* Used when the type is an interface (Map/SortedMap).
*
* @author David Yu
* @created Apr 24, 2012
*/
public abstract class PolymorphicMapSchema extends PolymorphicSchema
{
   
    static final int ID_EMPTY_MAP = 1,
            ID_SINGLETON_MAP = 2,
            ID_UNMODIFIABLE_MAP = 3,
            ID_UNMODIFIABLE_SORTED_MAP = 4,
            ID_SYNCHRONIZED_MAP = 5,
            ID_SYNCHRONIZED_SORTED_MAP = 6,
            ID_CHECKED_MAP = 7,
            ID_CHECKED_SORTED_MAP = 8;
   
    static final String STR_EMPTY_MAP = "a",
            STR_SINGLETON_MAP = "b",
            STR_UNMODIFIABLE_MAP = "c",
            STR_UNMODIFIABLE_SORTED_MAP = "d",
            STR_SYNCHRONIZED_MAP = "e",
            STR_SYNCHRONIZED_SORTED_MAP = "f",
            STR_CHECKED_MAP = "g",
            STR_CHECKED_SORTED_MAP = "h";
   
    static final IdentityHashMap<Class<?>,Integer> __nonPublicMaps =
            new IdentityHashMap<Class<?>, Integer>();
   
    static final Field fSingletonMap_k,
            fSingletonMap_v,
           
            fUnmodifiableMap_m,
           
            fUnmodifiableSortedMap_sm,
           
            fSynchronizedMap_m,
           
            fSynchronizedSortedMap_sm,
           
            fSynchronizedMap_mutex,
           
            fCheckedMap_m,
            fCheckedSortedMap_sm,
            fCheckedMap_keyType,
            fCheckedMap_valueType;
           
    static final Instantiator<?> iSingletonMap,
           
            iUnmodifiableMap,
            iUnmodifiableSortedMap,
           
            iSynchronizedMap,
            iSynchronizedSortedMap,
           
            iCheckedMap,
            iCheckedSortedMap;
   
   
    static
    {
        map("java.util.Collections$EmptyMap", ID_EMPTY_MAP);
       
        Class<?> cSingletonMap =
                map("java.util.Collections$SingletonMap", ID_SINGLETON_MAP);
       
        Class<?> cUnmodifiableMap =
                map("java.util.Collections$UnmodifiableMap", ID_UNMODIFIABLE_MAP);
       
        Class<?> cUnmodifiableSortedMap =
                map("java.util.Collections$UnmodifiableSortedMap", ID_UNMODIFIABLE_SORTED_MAP);
       
        Class<?> cSynchronizedMap =
                map("java.util.Collections$SynchronizedMap", ID_SYNCHRONIZED_MAP);
       
        Class<?> cSynchronizedSortedMap =
                map("java.util.Collections$SynchronizedSortedMap", ID_SYNCHRONIZED_SORTED_MAP);
       
        Class<?> cCheckedMap =
                map("java.util.Collections$CheckedMap", ID_CHECKED_MAP);
       
        Class<?> cCheckedSortedMap =
                map("java.util.Collections$CheckedSortedMap", ID_CHECKED_SORTED_MAP);
       
        try
        {
            fSingletonMap_k = cSingletonMap.getDeclaredField("k");
            fSingletonMap_v = cSingletonMap.getDeclaredField("v");
           
            fUnmodifiableMap_m = cUnmodifiableMap.getDeclaredField("m");
            fUnmodifiableSortedMap_sm = cUnmodifiableSortedMap.getDeclaredField("sm");
           
            fSynchronizedMap_m = cSynchronizedMap.getDeclaredField("m");
            fSynchronizedSortedMap_sm = cSynchronizedSortedMap.getDeclaredField("sm");
            fSynchronizedMap_mutex = cSynchronizedMap.getDeclaredField("mutex");
           
            fCheckedMap_m = cCheckedMap.getDeclaredField("m");
            fCheckedSortedMap_sm = cCheckedSortedMap.getDeclaredField("sm");
            fCheckedMap_keyType = cCheckedMap.getDeclaredField("keyType");
            fCheckedMap_valueType = cCheckedMap.getDeclaredField("valueType");
           
            iSingletonMap = RuntimeEnv.newInstantiator(cSingletonMap);
           
            iUnmodifiableMap = RuntimeEnv.newInstantiator(cUnmodifiableMap);
            iUnmodifiableSortedMap = RuntimeEnv.newInstantiator(cUnmodifiableSortedMap);
           
            iSynchronizedMap = RuntimeEnv.newInstantiator(cSynchronizedMap);
            iSynchronizedSortedMap = RuntimeEnv.newInstantiator(cSynchronizedSortedMap);
           
            iCheckedMap = RuntimeEnv.newInstantiator(cCheckedMap);
            iCheckedSortedMap = RuntimeEnv.newInstantiator(cCheckedSortedMap);
        }
        catch(Exception e)
        {
            throw new RuntimeException(e);
        }
       
        fSingletonMap_k.setAccessible(true);
        fSingletonMap_v.setAccessible(true);
       
        fUnmodifiableMap_m.setAccessible(true);
        fUnmodifiableSortedMap_sm.setAccessible(true);
       
        fSynchronizedMap_m.setAccessible(true);
        fSynchronizedSortedMap_sm.setAccessible(true);
        fSynchronizedMap_mutex.setAccessible(true);
       
        fCheckedMap_m.setAccessible(true);
        fCheckedSortedMap_sm.setAccessible(true);
        fCheckedMap_keyType.setAccessible(true);
        fCheckedMap_valueType.setAccessible(true);
    }
   
    private static Class<?> map(String className, int id)
    {
        Class<?> clazz = RuntimeEnv.loadClass(className);
        __nonPublicMaps.put(clazz, id);
        return clazz;
    }
   
    static String name(int number)
    {
        switch(number)
        {
            case ID_EMPTY_MAP: return STR_EMPTY_MAP;
            case ID_SINGLETON_MAP: return STR_SINGLETON_MAP;
            case ID_UNMODIFIABLE_MAP: return STR_UNMODIFIABLE_MAP;
            case ID_UNMODIFIABLE_SORTED_MAP: return STR_UNMODIFIABLE_SORTED_MAP;
            case ID_SYNCHRONIZED_MAP: return STR_SYNCHRONIZED_MAP;
            case ID_SYNCHRONIZED_SORTED_MAP: return STR_SYNCHRONIZED_SORTED_MAP;
            case ID_CHECKED_MAP: return STR_CHECKED_MAP;
            case ID_CHECKED_SORTED_MAP: return STR_CHECKED_SORTED_MAP;
            case ID_ENUM_MAP: return STR_ENUM_MAP;
            case ID_MAP: return STR_MAP;
            default: return null;
        }
    }
   
    static int number(String name)
    {
        if(name.length() != 1)
            return 0;
       
        switch(name.charAt(0))
        {
            case 'a': return 1;
            case 'b': return 2;
            case 'c': return 3;
            case 'd': return 4;
            case 'e': return 5;
            case 'f': return 6;
            case 'g': return 7;
            case 'h': return 8;
            case 'w': return ID_ENUM_MAP;
            case 'z': return ID_MAP;
            default: return 0;
        }
    }
   
    protected final Pipe.Schema<Object> pipeSchema = new Pipe.Schema<Object>(this)
    {
        protected void transfer(Pipe pipe, Input input, Output output) throws IOException
        {
            transferObject(this, pipe, input, output, strategy);
        }
    };
   
    public PolymorphicMapSchema(IdStrategy strategy)
    {
        super(strategy);
    }
   
    public Pipe.Schema<Object> getPipeSchema()
    {
        return pipeSchema;
    }
   
    public String getFieldName(int number)
    {
        return name(number);
    }

    public int getFieldNumber(String name)
    {
        return number(name);
    }

    public String messageFullName()
    {
        return Collection.class.getName();
    }

    public String messageName()
    {
        return Collection.class.getSimpleName();
    }

    public void mergeFrom(Input input, Object owner) throws IOException
    {
        setValue(readObjectFrom(input, this, owner, strategy), owner);
    }

    public void writeTo(Output output, Object value) throws IOException
    {
        writeObjectTo(output, value, this, strategy);
    }
   
    static int idFrom(Class<?> clazz)
    {
        final Integer id = __nonPublicMaps.get(clazz);
        if(id == null)
            throw new RuntimeException("Unknown map: " + clazz);
       
        return id.intValue();
    }
   
    static Object instanceFrom(final int id)
    {
        switch(id)
        {
            case ID_EMPTY_MAP:
                return Collections.EMPTY_MAP;
               
            case ID_SINGLETON_MAP:
                return iSingletonMap.newInstance();
               
            case ID_UNMODIFIABLE_MAP:
                return iUnmodifiableMap.newInstance();
            case ID_UNMODIFIABLE_SORTED_MAP:
                return iUnmodifiableSortedMap.newInstance();
               
            case ID_SYNCHRONIZED_MAP:
                return iSynchronizedMap.newInstance();
            case ID_SYNCHRONIZED_SORTED_MAP:
                return iSynchronizedSortedMap.newInstance();
               
            case ID_CHECKED_MAP:
                return iCheckedMap.newInstance();
            case ID_CHECKED_SORTED_MAP:
                return iCheckedSortedMap.newInstance();
               
            default:
                throw new RuntimeException("Unknown id: " + id);
        }
    }
   
    @SuppressWarnings("unchecked")
    static void writeObjectTo(Output output, Object value, Schema<?> currentSchema,
            IdStrategy strategy) throws IOException
    {
        if(Collections.class == value.getClass().getDeclaringClass())
        {
            writeNonPublicMapTo(output, value, currentSchema, strategy);
            return;
        }
       
        Class<Object> clazz = (Class<Object>)value.getClass();
        if(EnumMap.class.isAssignableFrom(clazz))
        {
            strategy.writeEnumIdTo(output, ID_ENUM_MAP,
                    EnumIO.getKeyTypeFromEnumMap(value));
           
            // TODO use enum schema
        }
        else
        {
            strategy.writeMapIdTo(output, ID_MAP, clazz);
        }
       
        if(output instanceof StatefulOutput)
        {
            // update using the derived schema.
            ((StatefulOutput)output).updateLast(strategy.MAP_SCHEMA, currentSchema);
        }
       
        strategy.MAP_SCHEMA.writeTo(output, (Map<Object,Object>)value);
    }
   
    static void writeNonPublicMapTo(Output output, Object value, Schema<?> currentSchema,
            IdStrategy strategy) throws IOException
    {
        final Integer n = __nonPublicMaps.get(value.getClass());
        if(n == null)
            throw new RuntimeException("Unknown collection: " + value.getClass());
        final int id = n.intValue();
        switch(id)
        {
            case ID_EMPTY_MAP:
                output.writeUInt32(id, 0, false);
                break;
               
            case ID_SINGLETON_MAP:
            {
                final Object k, v;
                try
                {
                    k = fSingletonMap_k.get(value);
                    v = fSingletonMap_v.get(value);
                }
                catch (IllegalArgumentException e)
                {
                    throw new RuntimeException(e);
                }
                catch (IllegalAccessException e)
                {
                    throw new RuntimeException(e);
                }
               
                output.writeUInt32(id, 0, false);
                if(k != null)
                    output.writeObject(1, k, strategy.OBJECT_SCHEMA, false);
                if(v != null)
                    output.writeObject(3, v, strategy.OBJECT_SCHEMA, false);
                break;
            }
               
            case ID_UNMODIFIABLE_MAP:
                writeUnmodifiableMapTo(output, value, currentSchema, strategy, id);
                break;
               
            case ID_UNMODIFIABLE_SORTED_MAP:
                writeUnmodifiableMapTo(output, value, currentSchema, strategy, id);
                break;
               
            case ID_SYNCHRONIZED_MAP:
                writeSynchronizedMapTo(output, value, currentSchema, strategy, id);
                break;
               
            case ID_SYNCHRONIZED_SORTED_MAP:
                writeSynchronizedMapTo(output, value, currentSchema, strategy, id);
                break;
               
            case ID_CHECKED_MAP:
                writeCheckedMapTo(output, value, currentSchema, strategy, id);
                break;
               
            case ID_CHECKED_SORTED_MAP:
                writeCheckedMapTo(output, value, currentSchema, strategy, id);
                break;
               
            default:
                throw new RuntimeException("Should not happen.");
        }
    }
   
    private static void writeUnmodifiableMapTo(Output output, Object value,
            Schema<?> currentSchema, IdStrategy strategy, int id) throws IOException
    {
        final Object m;
        try
        {
            m = fUnmodifiableMap_m.get(value);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        output.writeObject(id, m, strategy.POLYMORPHIC_MAP_SCHEMA, false);
    }
   
    private static void writeSynchronizedMapTo(Output output, Object value,
            Schema<?> currentSchema, IdStrategy strategy, int id) throws IOException
    {
        final Object m, mutex;
        try
        {
            m = fSynchronizedMap_m.get(value);
            mutex = fSynchronizedMap_mutex.get(value);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        if(mutex != value)
        {
            // TODO for future release, introduce an interface(GraphOutput) so we
            // can check whether the output can retain references.
            throw new RuntimeException(
                    "This exception is thrown to fail fast. " +
                    "Synchronized collections with a different mutex would only " +
                    "work if graph format is used, since the reference is retained.");
        }
       
        output.writeObject(id, m, strategy.POLYMORPHIC_MAP_SCHEMA, false);
    }
   
    private static void writeCheckedMapTo(Output output, Object value,
            Schema<?> currentSchema, IdStrategy strategy, int id) throws IOException
    {
        final Object m, keyType, valueType;
        try
        {
            m = fCheckedMap_m.get(value);
            keyType = fCheckedMap_keyType.get(value);
            valueType = fCheckedMap_valueType.get(value);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        output.writeObject(id, m, strategy.POLYMORPHIC_MAP_SCHEMA, false);
        output.writeObject(1, keyType, strategy.CLASS_SCHEMA, false);
        output.writeObject(2, valueType, strategy.CLASS_SCHEMA, false);
    }
   
    @SuppressWarnings("unchecked")
    static Object readObjectFrom(Input input,  Schema<?> schema, Object owner,
            IdStrategy strategy) throws IOException
    {
        final boolean graph = input instanceof GraphInput;
        Object ret = null;
        final int number = input.readFieldNumber(schema);
        switch(number)
        {
            case ID_EMPTY_MAP:
                if(graph)
                {
                    // update the actual reference.
                    ((GraphInput)input).updateLast(Collections.EMPTY_MAP, owner);
                }
               
                if(0 != input.readUInt32())
                    throw new ProtostuffException("Corrupt input.");
               
                ret = Collections.EMPTY_MAP;
                break;
               
            case ID_SINGLETON_MAP:
            {
                final Object map = iSingletonMap.newInstance();
                if(graph)
                {
                    // update the actual reference.
                    ((GraphInput)input).updateLast(map, owner);
                }
               
                if(0 != input.readUInt32())
                    throw new ProtostuffException("Corrupt input.");
               
                return fillSingletonMapFrom(input, schema, owner, strategy, graph, map);
            }
               
            case ID_UNMODIFIABLE_MAP:
                ret = readUnmodifiableMapFrom(input, schema, owner, strategy, graph,
                        iUnmodifiableMap.newInstance(), false);
                break;
               
            case ID_UNMODIFIABLE_SORTED_MAP:
                ret = readUnmodifiableMapFrom(input, schema, owner, strategy, graph,
                        iUnmodifiableSortedMap.newInstance(), true);
                break;
               
            case ID_SYNCHRONIZED_MAP:
                ret = readSynchronizedMapFrom(input, schema, owner, strategy, graph,
                        iSynchronizedMap.newInstance(), false);
                break;
               
            case ID_SYNCHRONIZED_SORTED_MAP:
                ret = readSynchronizedMapFrom(input, schema, owner, strategy, graph,
                        iSynchronizedSortedMap.newInstance(), true);
                break;
               
            case ID_CHECKED_MAP:
                ret = readCheckedMapFrom(input, schema, owner, strategy, graph,
                        iCheckedMap.newInstance(), false);
                break;
               
            case ID_CHECKED_SORTED_MAP:
                ret = readCheckedMapFrom(input, schema, owner, strategy, graph,
                        iCheckedSortedMap.newInstance(), true);
                break;
               
            case ID_ENUM_MAP:
            {
                final Map<?,Object> em = strategy.resolveEnumFrom(input).newEnumMap();
               
                if(input instanceof GraphInput)
                {
                    // update the actual reference.
                    ((GraphInput)input).updateLast(em, owner);
                }
               
                strategy.MAP_SCHEMA.mergeFrom(input, (Map<Object, Object>)em);
               
                return em;
            }
            case ID_MAP:
            {
                final Map<Object,Object> map =
                    strategy.resolveMapFrom(input).newMessage();
               
                if(input instanceof GraphInput)
                {
                    // update the actual reference.
                    ((GraphInput)input).updateLast(map, owner);
                }
               
                strategy.MAP_SCHEMA.mergeFrom(input, map);
               
                return map;
            }
           
            default:
                throw new ProtostuffException("Corrupt input.");
        }
       
        if(0 != input.readFieldNumber(schema))
            throw new ProtostuffException("Corrupt input.");
       
        return ret;
    }
   
    /**
     * Return true to
     */
    private static Object fillSingletonMapFrom(Input input,  Schema<?> schema,
            Object owner, IdStrategy strategy, boolean graph,
            Object map) throws IOException
    {
        switch(input.readFieldNumber(schema))
        {
            case 0:
                // both are null
                return map;
            case 1:
            {
                // key exists
                break;
            }
            case 3:
            {
                // key is null
                final Wrapper wrapper = new Wrapper();
                Object v = input.mergeObject(wrapper, strategy.OBJECT_SCHEMA);
                if(!graph || !((GraphInput)input).isCurrentMessageReference())
                    v = wrapper.value;
               
                try
                {
                    fSingletonMap_v.set(map, v);
                }
                catch (IllegalArgumentException e)
                {
                    throw new RuntimeException(e);
                }
                catch (IllegalAccessException e)
                {
                    throw new RuntimeException(e);
                }
               
                if(0 != input.readFieldNumber(schema))
                    throw new ProtostuffException("Corrupt input.");
               
                return map;
            }
            default:
                throw new ProtostuffException("Corrupt input.");
        }
       
        final Wrapper wrapper = new Wrapper();
        Object k = input.mergeObject(wrapper, strategy.OBJECT_SCHEMA);
        if(!graph || !((GraphInput)input).isCurrentMessageReference())
            k = wrapper.value;
       
        switch(input.readFieldNumber(schema))
        {
            case 0:
                // key exists but null value
                try
                {
                    fSingletonMap_k.set(map, k);
                }
                catch (IllegalArgumentException e)
                {
                    throw new RuntimeException(e);
                }
                catch (IllegalAccessException e)
                {
                    throw new RuntimeException(e);
                }
               
                return map;
            case 3:
                // key and value exist
                break;
            default:
                throw new ProtostuffException("Corrupt input.");
        }
       
        Object v = input.mergeObject(wrapper, strategy.OBJECT_SCHEMA);
        if(!graph || !((GraphInput)input).isCurrentMessageReference())
            v = wrapper.value;
       
        try
        {
            fSingletonMap_k.set(map, k);
            fSingletonMap_v.set(map, v);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        if(0 != input.readFieldNumber(schema))
            throw new ProtostuffException("Corrupt input.");
       
        return map;
    }
   
    private static Object readUnmodifiableMapFrom(Input input,  Schema<?> schema,
            Object owner, IdStrategy strategy, boolean graph,
            Object map, boolean sm) throws IOException
    {
        if(graph)
        {
            // update the actual reference.
            ((GraphInput)input).updateLast(map, owner);
        }
       
        final Wrapper wrapper = new Wrapper();
        Object m = input.mergeObject(wrapper, strategy.POLYMORPHIC_MAP_SCHEMA);
        if(!graph || !((GraphInput)input).isCurrentMessageReference())
            m = wrapper.value;
        try
        {
            fUnmodifiableMap_m.set(map, m);
           
            if(sm)
                fUnmodifiableSortedMap_sm.set(map, m);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        return map;
    }
   
    private static Object readSynchronizedMapFrom(Input input,  Schema<?> schema,
            Object owner, IdStrategy strategy, boolean graph,
            Object map, boolean sm) throws IOException
    {
        if(graph)
        {
            // update the actual reference.
            ((GraphInput)input).updateLast(map, owner);
        }
       
        final Wrapper wrapper = new Wrapper();
        Object m = input.mergeObject(wrapper, strategy.POLYMORPHIC_MAP_SCHEMA);
        if(!graph || !((GraphInput)input).isCurrentMessageReference())
            m = wrapper.value;
        try
        {
            fSynchronizedMap_m.set(map, m);
            fSynchronizedMap_mutex.set(map, map);
           
            if(sm)
                fSynchronizedSortedMap_sm.set(map, m);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        return map;
    }
   
    private static Object readCheckedMapFrom(Input input,  Schema<?> schema,
            Object owner, IdStrategy strategy, boolean graph,
            Object map, boolean sm) throws IOException
    {
        if(graph)
        {
            // update the actual reference.
            ((GraphInput)input).updateLast(map, owner);
        }
       
        final Wrapper wrapper = new Wrapper();
        Object m = input.mergeObject(wrapper, strategy.POLYMORPHIC_MAP_SCHEMA);
        if(!graph || !((GraphInput)input).isCurrentMessageReference())
            m = wrapper.value;
       
        if(1 != input.readFieldNumber(schema))
            throw new ProtostuffException("Corrupt input.");
       
        Object keyType = input.mergeObject(wrapper, strategy.CLASS_SCHEMA);
        if(!graph || !((GraphInput)input).isCurrentMessageReference())
            keyType = wrapper.value;
       
        if(2 != input.readFieldNumber(schema))
            throw new ProtostuffException("Corrupt input.");
       
        Object valueType = input.mergeObject(wrapper, strategy.CLASS_SCHEMA);
        if(!graph || !((GraphInput)input).isCurrentMessageReference())
            valueType = wrapper.value;
       
        try
        {
            fCheckedMap_m.set(map, m);
            fCheckedMap_keyType.set(map, keyType);
            fCheckedMap_valueType.set(map, valueType);
           
            if(sm)
                fCheckedSortedMap_sm.set(map, m);
        }
        catch (IllegalArgumentException e)
        {
            throw new RuntimeException(e);
        }
        catch (IllegalAccessException e)
        {
            throw new RuntimeException(e);
        }
       
        return map;
    }
   
    static void transferObject(Pipe.Schema<Object> pipeSchema, Pipe pipe,
            Input input, Output output, IdStrategy strategy) throws IOException
    {
        final int number = input.readFieldNumber(pipeSchema.wrappedSchema);
        switch(number)
        {
            case ID_EMPTY_MAP:
                output.writeUInt32(number, input.readUInt32(), false);
                break;
               
            case ID_SINGLETON_MAP:
                if(0 != input.readUInt32())
                    throw new ProtostuffException("Corrupt input.");
               
                output.writeUInt32(number, 0, false);
               
                transferSingletonMap(pipeSchema, pipe, input, output, strategy);
                return;
               
            case ID_UNMODIFIABLE_MAP:
                output.writeObject(number, pipe, strategy.POLYMORPHIC_MAP_PIPE_SCHEMA, false);
                break;
               
            case ID_UNMODIFIABLE_SORTED_MAP:
                output.writeObject(number, pipe, strategy.POLYMORPHIC_MAP_PIPE_SCHEMA, false);
                break;
               
            case ID_SYNCHRONIZED_MAP:
                output.writeObject(number, pipe, strategy.POLYMORPHIC_MAP_PIPE_SCHEMA, false);
                break;
               
            case ID_SYNCHRONIZED_SORTED_MAP:
                output.writeObject(number, pipe, strategy.POLYMORPHIC_MAP_PIPE_SCHEMA, false);
                break;
               
            case ID_CHECKED_MAP:
                output.writeObject(number, pipe, strategy.POLYMORPHIC_MAP_PIPE_SCHEMA, false);
               
                if(1 != input.readFieldNumber(pipeSchema.wrappedSchema))
                    throw new ProtostuffException("Corrupt input.");
               
                output.writeObject(1, pipe, strategy.CLASS_PIPE_SCHEMA, false);
               
                if(2 != input.readFieldNumber(pipeSchema.wrappedSchema))
                    throw new ProtostuffException("Corrupt input.");
               
                output.writeObject(2, pipe, strategy.CLASS_PIPE_SCHEMA, false);
                break;
               
            case ID_CHECKED_SORTED_MAP:
                output.writeObject(number, pipe, strategy.POLYMORPHIC_MAP_PIPE_SCHEMA, false);
               
                if(1 != input.readFieldNumber(pipeSchema.wrappedSchema))
                    throw new ProtostuffException("Corrupt input.");
               
                output.writeObject(1, pipe, strategy.CLASS_PIPE_SCHEMA, false);
               
                if(2 != input.readFieldNumber(pipeSchema.wrappedSchema))
                    throw new ProtostuffException("Corrupt input.");
               
                output.writeObject(2, pipe, strategy.CLASS_PIPE_SCHEMA, false);
                break;
               
            case ID_ENUM_MAP:
                strategy.transferEnumId(input, output, number);
               
                if(output instanceof StatefulOutput)
                {
                    // update using the derived schema.
                    ((StatefulOutput)output).updateLast(strategy.MAP_PIPE_SCHEMA, pipeSchema);
                }
               
                Pipe.transferDirect(strategy.MAP_PIPE_SCHEMA, pipe, input, output);
                return;
            case ID_MAP:
                strategy.transferMapId(input, output, number);
               
                if(output instanceof StatefulOutput)
                {
                    // update using the derived schema.
                    ((StatefulOutput)output).updateLast(strategy.MAP_PIPE_SCHEMA, pipeSchema);
                }
               
                Pipe.transferDirect(strategy.MAP_PIPE_SCHEMA, pipe, input, output);
                return;
               
            default:
                throw new ProtostuffException("Corrupt input.");
        }
       
        if(0 != input.readFieldNumber(pipeSchema.wrappedSchema))
            throw new ProtostuffException("Corrupt input.");
    }
   
    static void transferSingletonMap(Pipe.Schema<Object> pipeSchema, Pipe pipe,
            Input input, Output output, IdStrategy strategy) throws IOException
    {
        switch(input.readFieldNumber(pipeSchema.wrappedSchema))
        {
            case 0:
                // both are null
                return;
            case 1:
            {
                // key exists
                break;
            }
            case 3:
            {
                // key is null
                output.writeObject(3, pipe, strategy.OBJECT_PIPE_SCHEMA, false);
               
                if(0 != input.readFieldNumber(pipeSchema.wrappedSchema))
                    throw new ProtostuffException("Corrupt input.");
               
                return;
            }
            default:
                throw new ProtostuffException("Corrupt input.");
        }
       
        output.writeObject(1, pipe, strategy.OBJECT_PIPE_SCHEMA, false);
       
        switch(input.readFieldNumber(pipeSchema.wrappedSchema))
        {
            case 0:
                // key exists but null value
                return;
            case 3:
                // key and value exist
                break;
            default:
                throw new ProtostuffException("Corrupt input.");
        }
       
        output.writeObject(3, pipe, strategy.OBJECT_PIPE_SCHEMA, false);

        if(0 != input.readFieldNumber(pipeSchema.wrappedSchema))
            throw new ProtostuffException("Corrupt input.");
    }
}
TOP

Related Classes of com.dyuproject.protostuff.runtime.PolymorphicMapSchema

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.