de.pribluda.android.jsonmarshaller.JSONMarshaller.java Source code

Java tutorial

Introduction

Here is the source code for de.pribluda.android.jsonmarshaller.JSONMarshaller.java

Source

/*
 * Copyright (c) 2010. Konstantin Pribluda (konstantin.pribluda@gmail.com)
 *
 *
 *  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 de.pribluda.android.jsonmarshaller;

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

import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Date;

/**
 * marshall beans to JSON into writer
 */
public class JSONMarshaller {
    private static final String GETTER_PREFIX = "get";
    private static final int BEGIN_INDEX = GETTER_PREFIX.length();
    public static final String IS_PREFIX = "is";
    public static final int IS_LENGTH = 2;

    /**
     * marshall supplied object (tree?) to JSON
     *
     * @param object
     * @return
     */
    public static JSONObject marshall(Object object)
            throws InvocationTargetException, JSONException, IllegalAccessException, NoSuchMethodException {
        JSONObject retval = new JSONObject();
        marshallRecursive(retval, object);
        return retval;
    }

    /**
     * recursively marshall to JSON
     *
     * @param sink
     * @param object
     */
    static void marshallRecursive(JSONObject sink, Object object)
            throws JSONException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        // nothing to marshall
        if (object == null)
            return;
        // primitive object is a field and does not interes us here
        if (object.getClass().isPrimitive())
            return;
        // object not null,  and is not primitive - iterate through getters
        for (Method method : object.getClass().getMethods()) {
            // our getters are parameterless and start with "get"
            if ((method.getName().startsWith(GETTER_PREFIX) && method.getName().length() > BEGIN_INDEX
                    || method.getName().startsWith(IS_PREFIX) && method.getName().length() > IS_LENGTH)
                    && (method.getModifiers() & Modifier.PUBLIC) != 0 && method.getParameterTypes().length == 0
                    && method.getReturnType() != void.class) {
                // is return value primitive?
                Class<?> type = method.getReturnType();
                if (type.isPrimitive() || String.class.equals(type)) {
                    // it is, marshall it
                    Object val = method.invoke(object);
                    if (val != null) {
                        sink.put(propertize(method.getName()), val);
                    }
                    continue;
                } else if (type.isArray()) {
                    Object val = marshallArray(method.invoke(object));
                    if (val != null) {
                        sink.put(propertize(method.getName()), val);
                    }
                    continue;
                } else if (type.isAssignableFrom(Date.class)) {
                    Date date = (Date) method.invoke(object);
                    if (date != null) {
                        sink.put(propertize(method.getName()), date.getTime());
                    }
                    continue;
                } else if (type.isAssignableFrom(Boolean.class)) {
                    Boolean b = (Boolean) method.invoke(object);
                    if (b != null) {
                        sink.put(propertize(method.getName()), b.booleanValue());
                    }
                    continue;
                } else if (type.isAssignableFrom(Integer.class)) {
                    Integer i = (Integer) method.invoke(object);
                    if (i != null) {
                        sink.put(propertize(method.getName()), i.intValue());
                    }
                    continue;
                } else if (type.isAssignableFrom(Long.class)) {
                    Long l = (Long) method.invoke(object);
                    if (l != null) {
                        sink.put(propertize(method.getName()), l.longValue());
                    }
                    continue;
                } else {
                    // does it have default constructor?
                    try {
                        if (method.getReturnType().getConstructor() != null) {
                            Object val = marshall(method.invoke(object));
                            if (val != null) {
                                sink.put(propertize(method.getName()), val);
                            }
                            continue;
                        }
                    } catch (NoSuchMethodException ex) {
                        // just ignore it here, it means no such constructor was found
                    }
                }
            }
        }
    }

    /**
     * recursively marshall [multidimensional? - of course!!! ] array
     *
     * @param array
     * @return
     */
    public static JSONArray marshallArray(Object array)
            throws InvocationTargetException, NoSuchMethodException, JSONException, IllegalAccessException {
        if (array != null && array.getClass().isArray()) {
            Class<?> componentType = array.getClass().getComponentType();
            JSONArray retval = new JSONArray();
            final int arrayLength = Array.getLength(array);
            // stirngs and primitives must be marshalled directly
            if (componentType.isPrimitive() || String.class.equals(componentType)) {

                for (int i = 0; i < arrayLength; i++) {
                    retval.put(Array.get(array, i));
                }
            } else if (componentType.isArray()) {
                // that's cool, nested array recurse
                for (int i = 0; i < arrayLength; i++) {
                    retval.put(marshallArray(Array.get(array, i)));
                }
            } else {
                // treat component as a bean   if it got default constructor
                try {
                    if (componentType.getConstructor() != null) {
                        for (int i = 0; i < arrayLength; i++) {
                            retval.put(marshall(Array.get(array, i)));
                        }
                    }
                } catch (NoSuchMethodException ex) {
                    // just ignore it here, it means no such constructor was found
                }
            }

            return retval;
        }

        return null;
    }

    /**
     * convert method name to property
     *
     * @param name
     */
    public static String propertize(String name) {
        int offset = name.startsWith(IS_PREFIX) ? IS_LENGTH : BEGIN_INDEX;
        return name.substring(offset, offset + 1).toLowerCase() + name.substring(offset + 1);
    }
}