Package com.jrjackson

Source Code of com.jrjackson.RubyObjectDeserializer

package com.jrjackson;

import java.io.IOException;
import java.util.*;

import com.fasterxml.jackson.core.*;

import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.util.ObjectBuffer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

import org.jruby.Ruby;
import org.jruby.RubyObject;
import org.jruby.RubyArray;
import org.jruby.RubyHash;
import org.jruby.javasupport.util.RuntimeHelpers;

public class RubyObjectDeserializer
        extends StdDeserializer<RubyObject> {

    private static final long serialVersionUID = 1L;

    private Ruby _ruby;

    private RubyKeyConverter converter;

    public RubyObjectDeserializer() {
        super(RubyObject.class);
    }

    public RubyObjectDeserializer withRuby(Ruby ruby) {
        _ruby = ruby;
        return this;
    }

    public RubyObjectDeserializer setStringStrategy() {
        converter = new RubyStringConverter();
        return this;
    }

    public RubyObjectDeserializer setSymbolStrategy() {
        converter = new RubySymbolConverter();
        return this;
    }

    /**
     * /**********************************************************
     * /* Deserializer API /**********************************************************
     * @param jp
     * @param ctxt
     * @return
     * @throws java.io.IOException
     * @throws com.fasterxml.jackson.core.JsonProcessingException
     */
   
    @Override
    public RubyObject deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        switch (jp.getCurrentToken()) {
            case START_OBJECT:
                return mapObject(jp, ctxt);

            case START_ARRAY:
                return mapArray(jp, ctxt);

            case FIELD_NAME:
                return converter.convert(_ruby, jp);

            case VALUE_EMBEDDED_OBJECT:
                return RubyUtils.rubyObject(_ruby, jp.getEmbeddedObject());

            case VALUE_STRING:
                // return RubyUtils.rubyString(_ruby, jp.getText().getBytes("UTF-8"));
                return RubyUtils.rubyString(_ruby, jp.getText());

            case VALUE_NUMBER_INT:
                /* [JACKSON-100]: caller may want to get all integral values
                 * returned as BigInteger, for consistency
                 */
                JsonParser.NumberType numberType = jp.getNumberType();
                if (ctxt.isEnabled(DeserializationFeature.USE_BIG_INTEGER_FOR_INTS) || numberType == JsonParser.NumberType.BIG_INTEGER) {
                    return RubyUtils.rubyBignum(_ruby, jp.getBigIntegerValue());
                }
                return RubyUtils.rubyFixnum(_ruby, jp.getLongValue());

            case VALUE_NUMBER_FLOAT:
                if (ctxt.isEnabled(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)) {
                    return RubyUtils.rubyBigDecimal(_ruby, jp.getDecimalValue());
                }
                return RubyUtils.rubyFloat(_ruby, jp.getDoubleValue());

            case VALUE_TRUE:
                return _ruby.newBoolean(Boolean.TRUE);

            case VALUE_FALSE:
                return _ruby.newBoolean(Boolean.FALSE);

            case VALUE_NULL: // should not get this but...
                return (RubyObject) _ruby.getNil();

            case END_ARRAY: // invalid
            case END_OBJECT: // invalid
            default:
                throw ctxt.mappingException(Object.class);
        }
    }

    /**
     * /**********************************************************
     * /* Internal methods /**********************************************************
     */
    /**
     * Method called to map a JSON Array into a Java value.
     * @param jp
     * @param ctxt
     * @return RubyObject
     * @throws java.io.IOException
     * @throws com.fasterxml.jackson.core.JsonProcessingException
     */
    protected RubyObject mapArray(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
    // if (ctxt.isEnabled(DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY)) {
        //     return mapArrayToArray(jp, ctxt);
        // }
        // Minor optimization to handle small lists (default size for ArrayList is 10)
        if (jp.nextToken() == JsonToken.END_ARRAY) {
            return RubyArray.newArray(_ruby);
        }
        ObjectBuffer buffer = ctxt.leaseObjectBuffer();
        Object[] values = buffer.resetAndStart();
        int ptr = 0;
        long totalSize = 0;
        do {
            Object value = deserialize(jp, ctxt);
            ++totalSize;
            if (ptr >= values.length) {
                values = buffer.appendCompletedChunk(values);
                ptr = 0;
            }
            values[ptr++] = value;
        } while (jp.nextToken() != JsonToken.END_ARRAY);
        // let's create almost full array, with 1/8 slack
        RubyArray result = RubyArray.newArray(_ruby, (totalSize + (totalSize >> 3) + 1));
        buffer.completeAndClearBuffer(values, ptr, result);
        return result;
    }

    /**
     * Method called to map a JSON Object into a Java value.
     * @param jp
     * @param ctxt
     * @return RubyObject
     * @throws java.io.IOException
     * @throws com.fasterxml.jackson.core.JsonProcessingException
     */
    protected RubyObject mapObject(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        JsonToken t = jp.getCurrentToken();
        if (t == JsonToken.START_OBJECT) {
            t = jp.nextToken();
        }
        // 1.6: minor optimization; let's handle 1 and 2 entry cases separately
        if (t != JsonToken.FIELD_NAME) { // and empty one too
            // empty map might work; but caller may want to modify... so better just give small modifiable
            return RubyHash.newHash(_ruby);
        }

        RubyObject field1 = converter.convert(_ruby, jp);
        jp.nextToken();
        RubyObject value1 = deserialize(jp, ctxt);
        if (jp.nextToken() != JsonToken.FIELD_NAME) { // single entry; but we want modifiable
            return RuntimeHelpers.constructHash(_ruby, field1, value1);
        }

        RubyObject field2 = converter.convert(_ruby, jp);
        jp.nextToken();
        RubyObject value2 = deserialize(jp, ctxt);
        if (jp.nextToken() != JsonToken.FIELD_NAME) {
            return RuntimeHelpers.constructHash(_ruby, field1, value1, field2, value2);
        }

        // And then the general case; default map size is 16
        RubyHash result = RuntimeHelpers.constructHash(_ruby, field1, value1, field2, value2);
        do {
            RubyObject fieldName = converter.convert(_ruby, jp);
            jp.nextToken();
            result.fastASetCheckString(_ruby, fieldName, deserialize(jp, ctxt));
        } while (jp.nextToken() != JsonToken.END_OBJECT);
        return result;
    }
}
TOP

Related Classes of com.jrjackson.RubyObjectDeserializer

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.