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

com.dyuproject.protostuff.GraphCodedInput Maven / Gradle / Ivy

There is a newer version: 1.3.1
Show newest version
//========================================================================
//Copyright 2007-2011 David Yu [email protected]
//------------------------------------------------------------------------
//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.dyuproject.protostuff;

import static com.dyuproject.protostuff.WireFormat.WIRETYPE_REFERENCE;

import java.io.IOException;
import java.util.ArrayList;

/**
 * A CodedInput w/c can handle cyclic dependencies when deserializing 
 * objects with graph transformations.
 *
 * @author David Yu
 * @created Jan 17, 2011
 */
public final class GraphCodedInput extends FilterInput 
implements GraphInput, Schema
{
    
    private final ArrayList references;
    private int lastRef = -1;
    
    private Schema lastSchema;
    private boolean messageReference = false;
    
    public GraphCodedInput(CodedInput input)
    {
        super(input);
        
        // protostuff format only.
        assert input.decodeNestedMessageAsGroup;
        
        references = new ArrayList();
    }

    public GraphCodedInput(CodedInput input, int initialCapacity)
    {
        super(input);
        
        // protostuff format only.
        assert input.decodeNestedMessageAsGroup;
        
        references = new ArrayList(initialCapacity);
    }
    
    public void updateLast(Object morphedMessage, Object lastMessage)
    {
        final int last = references.size()-1;
        if(lastMessage != null && lastMessage == references.get(last))
        {
            // update the reference
            references.set(last, morphedMessage);
        }
    }
    
    public boolean isCurrentMessageReference()
    {
        return messageReference;
    }
    
    public  int readFieldNumber(Schema schema) throws IOException
    {
        final int fieldNumber = input.readFieldNumber(schema);
        if(WireFormat.getTagWireType(input.getLastTag()) == WIRETYPE_REFERENCE)
        {
            // a reference.
            lastRef = input.readUInt32();
            messageReference = true;
        }
        else
        {
            // always unset.
            messageReference = false;
        }
        
        return fieldNumber;
    }
    
    @SuppressWarnings("unchecked")
    public  T mergeObject(T value, Schema schema) throws IOException
    {
        if(messageReference)
        {
            // a reference.
            return (T)references.get(lastRef);
        }

        lastSchema = (Schema)schema;
        
        if(value == null)
            value = schema.newMessage();
        
        references.add(value);
        
        input.mergeObject(value, this);
        
        return value;
    }
    
    @Override
    public  void handleUnknownField(int fieldNumber, Schema schema) throws IOException
    {
        if (!messageReference)
            input.skipField(input.getLastTag());
    }
    
    public String getFieldName(int number)
    {
        throw new UnsupportedOperationException();
    }

    public int getFieldNumber(String name)
    {
        throw new UnsupportedOperationException();
    }

    public boolean isInitialized(Object owner)
    {
        return true;
    }

    public String messageFullName()
    {
        throw new UnsupportedOperationException();
    }

    public String messageName()
    {
        throw new UnsupportedOperationException();
    }

    public Object newMessage()
    {
        throw new UnsupportedOperationException();
    }

    public Class typeClass()
    {
        throw new UnsupportedOperationException();
    }

    public void mergeFrom(Input input, final Object message) throws IOException
    {
        final Schema schema = lastSchema;
        
        // merge using this input.
        schema.mergeFrom(this, message);
        if(!schema.isInitialized(message))
            throw new UninitializedMessageException(message, schema);
        
        // restore
        lastSchema = schema;
    }

    public void writeTo(Output output, Object message) throws IOException
    {
        // only using mergeFrom.
        throw new UnsupportedOperationException();
    }

}