com.madrobot.di.wizard.json.JSONDeserializer.java Source code

Java tutorial

Introduction

Here is the source code for com.madrobot.di.wizard.json.JSONDeserializer.java

Source

/*******************************************************************************
 * Copyright (c) 2012 MadRobot.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the GNU Lesser Public License v2.1
 *  which accompanies this distribution, and is available at
 *  http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *  
 *  Contributors:
 *  Elton Kent - initial API and implementation
 ******************************************************************************/
package com.madrobot.di.wizard.json;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Stack;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.madrobot.di.Converter;
import com.madrobot.di.wizard.json.annotations.ItemType;
import com.madrobot.di.wizard.json.annotations.SerializedName;

import android.util.Log;

/**
 * Utility class for json deserializer , by using this utility you can convert json into predefined java object
 * 
 * @author n.ayyanar
 * 
 */
public final class JSONDeserializer {

    /**
     * default collection size , meaning user need whole json array
     */
    public final static int DEFAULT_ITEM_COLLECTION_SIZE = -100;

    private static JSONDeserializer jsonDeserializer = new JSONDeserializer();

    /**
     * Logger tag for json deserializer
     */
    public final static String TAG = "JSONUtils -> JSONDeserializer";

    public static JSONDeserializer getInstance() {
        return jsonDeserializer;
    }

    private JSONDeserializer() {

    }

    private String convertStreamToString(final InputStream is) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
            sb.append(line + "\n");
        }
        is.close();
        return sb.toString();
    }

    /**
     * Deserialize the json data from the input to the corresponding entity type <br/>
     * If there is an error while parsing, if possible it will try to ignore it, otherwise returns a null value.
     * 
     * @param input
     *            Input stream to read data from
     * @param objType
     *            Type of the entity to deserialize data to
     * 
     * @return {@link #deserialize(Class, JSONObject)}
     * 
     * @see #deserialize(Class, JSONObject)
     * 
     * @throws JSONException
     *             If an exception occurs during parsing
     * 
     * @throws IOException
     *             If an exception occurs during reading
     */
    public <T> T deserialize(final Class<T> objType, final InputStream jsonContentStream)
            throws JSONException, IOException {
        return deserialize(objType, new JSONObject(convertStreamToString(jsonContentStream)));
    }

    /**
     * Deserializes the JSON data from the input to the corresponding entity type <br/>
     * If there is an error while parsing, if possible it will try to ignore it, otherwise returns a null value.
     * 
     * @param parser
     *            Parser to read XML from
     * @param objType
     *            Type of the entity to deserialize data to
     * 
     * @return Deserialized object, if successful, null otherwise
     * @see #deserialize(InputStream, Class)
     */
    public <T> T deserialize(final Class<T> objType, final JSONObject jsonObject) throws JSONException {

        try {

            Stack<Class<?>> stack = new Stack<Class<?>>();
            stack.push(objType);

            T resultObject = objType.newInstance();

            deserialize(resultObject, jsonObject, stack);

            return resultObject;
        } catch (IllegalAccessException e) {
            Log.e(TAG, e.getMessage());
        } catch (InstantiationException e) {
            Log.e(TAG, e.getMessage());
        }

        return null;
    }

    /**
     * Deserialize the json data from the input to the corresponding entity type <br/>
     * If there is an error while parsing, if possible it will try to ignore it, otherwise returns a null value.
     * 
     * @param jsonContent
     *            String to read data from
     * @param objType
     *            Type of the entity to deserialize data to
     * 
     * @return {@link #deserialize(Class, JSONObject)}
     * 
     * @see #deserialize(Class, JSONObject)
     * 
     * @throws JSONException
     *             If an exception occurs during parsing
     */
    public <T> T deserialize(final Class<T> objType, final String jsonContent) throws JSONException {
        return deserialize(objType, new JSONObject(jsonContent));
    }

    /**
     * Deserialize a specific element, recursively.
     * 
     * @param obj
     *            Object whose fields need to be set
     * @param jsonObject
     *            JSON Parser to read data from
     * @param stack
     *            Stack of {@link ClassInfo} - entity type under consideration
     * @throws JSONException
     *             If an exception occurs during parsing
     */
    private void deserialize(Object obj, JSONObject jsonObject, Stack<Class<?>> stack) throws JSONException {

        Iterator<?> iterator = jsonObject.keys();
        Class<?> userClass = stack.peek();

        while (iterator.hasNext()) {
            Object jsonKey = iterator.next();

            if (jsonKey instanceof String) {
                String key = (String) jsonKey;
                Object jsonElement = jsonObject.get(key);

                try {

                    Field field = getField(userClass, key);
                    String fieldName = field.getName();
                    Class<?> classType = field.getType();

                    if (jsonElement instanceof JSONObject) {
                        if (!Converter.isPseudoPrimitive(classType)) {

                            String setMethodName = getSetMethodName(fieldName, classType);
                            Method setMethod = userClass.getDeclaredMethod(setMethodName, classType);

                            JSONObject fieldObject = (JSONObject) jsonElement;

                            stack.push(classType);
                            Object itemObj = classType.newInstance();
                            deserialize(itemObj, fieldObject, stack);

                            setMethod.invoke(obj, itemObj);
                        } else {
                            Log.e(TAG, "Expecting composite type for " + fieldName);
                        }
                    } else if (jsonElement instanceof JSONArray) {
                        if (Converter.isCollectionType(classType)) {
                            if (field.isAnnotationPresent(ItemType.class)) {
                                ItemType itemType = field.getAnnotation(ItemType.class);
                                Class<?> itemValueType = itemType.value();
                                int size = itemType.size();

                                JSONArray fieldArrayObject = (JSONArray) jsonElement;

                                if (size == JSONDeserializer.DEFAULT_ITEM_COLLECTION_SIZE
                                        || size > fieldArrayObject.length()) {
                                    size = fieldArrayObject.length();
                                }

                                for (int index = 0; index < size; index++) {
                                    Object value = fieldArrayObject.get(index);
                                    if (value instanceof JSONObject) {
                                        stack.push(itemValueType);
                                        Object itemObj = itemValueType.newInstance();
                                        deserialize(itemObj, (JSONObject) value, stack);

                                        String addMethodName = getAddMethodName(fieldName);
                                        Method addMethod = userClass.getDeclaredMethod(addMethodName,
                                                itemValueType);
                                        addMethod.invoke(obj, itemObj);
                                    }
                                }
                            }
                        } else {
                            Log.e(TAG, "Expecting collection type for " + fieldName);
                        }
                    } else if (Converter.isPseudoPrimitive(classType)) {

                        Object value = Converter.convertTo(jsonObject, key, classType, field);

                        String setMethodName = getSetMethodName(fieldName, classType);
                        Method setMethod = userClass.getDeclaredMethod(setMethodName, classType);
                        setMethod.invoke(obj, value);
                    } else {
                        Log.e(TAG, "Unknown datatype");
                    }

                } catch (NoSuchFieldException e) {
                    Log.e(TAG, e.getMessage());
                } catch (NoSuchMethodException e) {
                    Log.e(TAG, e.getMessage());
                } catch (IllegalAccessException e) {
                    Log.e(TAG, e.getMessage());
                } catch (InvocationTargetException e) {
                    Log.e(TAG, e.getMessage());
                } catch (InstantiationException e) {
                    Log.e(TAG, e.getMessage());
                }
            }
        }
    }

    private String getAddMethodName(String fieldName) {
        return "add" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
    }

    private Field getField(final Class<?> userClass, final String jsonKey) throws NoSuchFieldException {

        Field targetField = null;
        for (Field field : userClass.getDeclaredFields()) {
            if (field.getName().equals(jsonKey)) {
                targetField = field;
                break;
            } else if (field.isAnnotationPresent(SerializedName.class)) {
                SerializedName serializedNameObj = field.getAnnotation(SerializedName.class);
                if (serializedNameObj.value().equals(jsonKey)) {
                    targetField = field;
                    break;
                }
            }
        }

        if (targetField == null)
            throw new NoSuchFieldException("NoSuchFieldException : " + jsonKey);

        return targetField;
    }

    private String getSetMethodName(final String fieldName, final Class<?> classType) {
        String methodName = null;
        if (Converter.isBoolean(classType) && fieldName.startsWith("is")) {
            methodName = "set" + Character.toUpperCase(fieldName.charAt(2)) + fieldName.substring(3);
        } else {
            methodName = "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
        }
        return methodName;
    }
}