com.pmeade.arya.gson.deserialize.ArrayFieldDeserializer.java Source code

Java tutorial

Introduction

Here is the source code for com.pmeade.arya.gson.deserialize.ArrayFieldDeserializer.java

Source

/*
 * ArrayFieldDeserializer.java
 * Copyright 2013 Patrick Meade.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.pmeade.arya.gson.deserialize;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.pmeade.arya.Arya;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Date;

/**
 * ArrayFieldDeserializer deserializes JSON arrays into Java arrays. The
 * content of a JsonArray object is converted into a Java array that populates
 * the specified field on the provided object.
 * @author pmeade
 */
public class ArrayFieldDeserializer implements FieldDeserializer {
    /**
     * Construct an ArrayFieldDeserializer.
     * @param arya allows additional deserialization requests
     * @param aryaDeserializer to determine if the component type of the array
     *                         requires deserialization, or is a simple type
     *                         that can be interpreted directly
     */
    public ArrayFieldDeserializer(Arya arya, AryaDeserializer aryaDeserializer) {
        this.arya = arya;
        this.aryaDeserializer = aryaDeserializer;
    }

    /**
     * Request deserialization of a JSON array into the provided Object.
     * @param jo JsonObject containing the JsonArray to be deserialized
     * @param t Object to be populated with the array content
     * @param field Field of the object to be populated (also identifies the
     *              name of the JsonArray to be deserialized)
     * @throws IllegalAccessException never thrown (you don't actually believe
     *                                what I just told you, right?)
     */
    public void deserialize(JsonObject jo, Object t, Field field) throws IllegalAccessException {
        // if the provided JsonObject has a key that maps to the field name
        if (jo.has(field.getName())) {
            // get the type of the field (which should be an array)
            Class objType = field.getType();
            // while the type is still an array
            while (objType.isArray()) {
                // determine the component type (this is an array OF what?)
                // example: int[][][] -> int[][] -> int[] -> int
                objType = objType.getComponentType();
            }
            // ask the AryaDeserializer if this is something that needs
            // to be deserialized (i.e.: a complex object) or if it is
            // a simple type that can be interpreted directly
            boolean loadRequired = aryaDeserializer.isLoadRequired(objType);
            // obtain the JsonArray that contains the data
            JsonArray ja = jo.getAsJsonArray(field.getName());
            // populate the field on the provided object with the data
            // deserialized from the JSON representation of the object
            field.set(t, deserializeArray(ja, field.getType(), loadRequired));
        }
    }

    /**
     * Deserialize a JsonArray into a Java array object.
     * @param jsonArray JsonArray containing the JSON data to be deserialized
     * @param objType the type of the array to be deserialized
     * @param loadRequired true, if the base component type is a complex object
     *                     that requires its own deserialization; false, if
     *                     the base type is simple and can be interpreted
     *                     directly from the JSON itself
     * @return Java array containing the objects deserialized from the JSON
     */
    private Object deserializeArray(JsonArray jsonArray, Class objType, boolean loadRequired) {
        // get the component type of the array (this is an array OF what?)
        Class componentType = objType.getComponentType();
        // instantiate an instance of the array of the component type
        Object array = Array.newInstance(componentType, jsonArray.size());
        // for each item in the JsonArray data
        for (int i = 0; i < jsonArray.size(); i++) {
            // define something to hold a reference to the thing we want to
            // put in the array; we'll populate it below
            Object value = null;
            // if the component type is ALSO an array (that is, we've got
            // a multi-dimensional array on our hands)
            if (componentType.isArray()) {
                // then, recursively deserialize the inner array; the return
                // value (an array of one less dimension) is what goes in the
                // outer multi-dimensional array
                value = deserializeArray(jsonArray.get(i).getAsJsonArray(), componentType, loadRequired);
            }
            // otherwise, this is the base component type (i.e.: no more array
            // dimensions need to be processed, we're at the actual type)
            else {
                // if the actual type is a complex object that also requires
                // deserialization
                if (loadRequired) {
                    // then, get the UUID identity of the object from the JSON
                    String sUuid = jsonArray.get(i).getAsString();
                    java.util.UUID uuid = java.util.UUID.fromString(sUuid);
                    // ask Arya to load the object, so it can go in the array
                    value = arya.load(uuid, componentType);
                }
                // otherwise, this is a simple type that can be interpreted
                // directly; so we'll just read it from the JSON
                else {
                    // TODO: Refactor this huge if-else block into something
                    //       a little nicer; perhaps FieldDeserializer could
                    //       require a little more functionality and
                    //       EnumFieldDeserializer could provide the correct
                    //       value by querying on the componentType
                    if (componentType.equals(boolean.class)) {
                        value = jsonArray.get(i).getAsBoolean();
                    } else if (componentType.equals(Boolean.class)) {
                        value = jsonArray.get(i).getAsBoolean();
                    } else if (componentType.equals(byte.class)) {
                        value = jsonArray.get(i).getAsByte();
                    } else if (componentType.equals(Byte.class)) {
                        value = jsonArray.get(i).getAsByte();
                    } else if (componentType.equals(char.class)) {
                        value = jsonArray.get(i).getAsCharacter();
                    } else if (componentType.equals(Character.class)) {
                        value = jsonArray.get(i).getAsCharacter();
                    } else if (componentType.equals(short.class)) {
                        value = jsonArray.get(i).getAsShort();
                    } else if (componentType.equals(Short.class)) {
                        value = jsonArray.get(i).getAsShort();
                    } else if (componentType.equals(int.class)) {
                        value = jsonArray.get(i).getAsInt();
                    } else if (componentType.equals(Integer.class)) {
                        value = jsonArray.get(i).getAsInt();
                    } else if (componentType.equals(long.class)) {
                        value = jsonArray.get(i).getAsLong();
                    } else if (componentType.equals(Long.class)) {
                        value = jsonArray.get(i).getAsLong();
                    } else if (componentType.equals(float.class)) {
                        value = jsonArray.get(i).getAsFloat();
                    } else if (componentType.equals(Float.class)) {
                        value = jsonArray.get(i).getAsFloat();
                    } else if (componentType.equals(double.class)) {
                        value = jsonArray.get(i).getAsDouble();
                    } else if (componentType.equals(Double.class)) {
                        value = jsonArray.get(i).getAsDouble();
                    } else if (componentType.equals(Date.class)) {
                        value = new Date(jsonArray.get(i).getAsLong());
                    } else if (componentType.equals(String.class)) {
                        value = jsonArray.get(i).getAsString();
                    } else if (componentType.equals(java.util.UUID.class)) {
                        value = java.util.UUID.fromString(jsonArray.get(i).getAsString());
                    } else {
                        throw new UnsupportedOperationException();
                    }
                }
            }
            // put the deserialized value object in the Java array
            Array.set(array, i, value);
        }
        // return the Java array to the caller
        return array;
    }

    /**
     * Arya reference allows ArrayFieldDeserializer to make additional
     * deserialization requests. It might do this when provided with an
     * array of complex objects that themselves need to be deserialized.
     */
    private Arya arya;

    /**
     * AryaDeserializer allows ArrayFieldDeserializer to determine if the
     * component type of the array is a complex object that requires
     * deserialization.
     */
    private AryaDeserializer aryaDeserializer;
}