org.openlaszlo.remote.json.LZReturnObject.java Source code

Java tutorial

Introduction

Here is the source code for org.openlaszlo.remote.json.LZReturnObject.java

Source

/******************************************************************************
 * LZReturnObjectJSON.java
 * ****************************************************************************/

/* J_LZ_COPYRIGHT_BEGIN *******************************************************
* Copyright 2001-2009, 2011 Laszlo Systems, Inc.  All Rights Reserved.        *
* Use is subject to license terms.                                            *
* J_LZ_COPYRIGHT_END *********************************************************/

package org.openlaszlo.remote.json;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.sql.Timestamp;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.log4j.Logger;
import org.openlaszlo.sc.ScriptCompiler;

/**
 * Utility class to create JSON based on a server object.
 */
public class LZReturnObject {
    public static Logger mLogger = Logger.getLogger(LZReturnObject.class);
    public static final int RETTYPE_POJO = 0;
    public static final int RETTYPE_JAVA_BEAN = 1;

    StringBuffer body;
    int mObjRetType;

    public LZReturnObject(String objectReturnType) throws Exception {
        body = new StringBuffer();
        if (objectReturnType == null) {
            mObjRetType = RETTYPE_POJO;
        } else if ("javabean".equals(objectReturnType)) {
            mObjRetType = RETTYPE_JAVA_BEAN;
        } else {
            mObjRetType = RETTYPE_POJO;
        }
    }

    void pushInteger(int i) throws Exception {
        body.append(i);
    }

    void pushFloat(float f) throws Exception {
        body.append(f);
    }

    void pushString(String s) throws Exception {
        body.append(ScriptCompiler.JSONquote(s));
    }

    void pushDouble(double d) throws Exception {
        body.append(d);
    }

    void pushBoolean(boolean b) throws Exception {
        body.append(b ? "true" : "false");
    }

    void pushArray(Object object) throws Exception {
        body.append("[");
        int length = Array.getLength(object);
        for (int i = 0; i < length; i++) {
            if (i > 0) {
                body.append(",");
            }
            createReturnValue(Array.get(object, i));
        }
        body.append("]");
    }

    void pushList(List<?> list) throws Exception {
        body.append("[");
        int length = list.size();
        //mLogger.warn(length);
        for (int i = 0; i < length; i++) {
            if (i > 0) {
                body.append(",");
            }
            createReturnValue(list.get(i));
        }
        body.append("]");
    }

    void pushSet(Set<?> set) throws Exception {
        int i = 0;
        body.append("[");
        for (Iterator<?> iter = set.iterator(); iter.hasNext();) {
            if (i++ > 0) {
                body.append(", ");
            }
            createReturnValue(iter.next());
        }
        body.append("]");
    }

    void pushNull() throws Exception {
        body.append("null");
    }

    void pushObject(Object object) throws Exception {
        try {
            Class<?> cl = object.getClass();
            String classname = cl.getName();

            //------------------------------------------------------------
            //  {class: classname, key1: val1, key2: val2, ...}
            //------------------------------------------------------------
            // varname.class = classname
            body.append("{");
            body.append("\"class\": " + ScriptCompiler.JSONquote(classname));

            if (mObjRetType == RETTYPE_JAVA_BEAN) {
                pushObjectJavaBean(object);
            } else {
                pushObjectPOJO(object);
            }

            body.append("}");
        } catch (Exception err) {

            if (object != null) {
                mLogger.error("[pushObject]" + object.getClass().getName());
                mLogger.error("[pushObject]" + object.toString());
            }
            mLogger.error("[pushObject]", err);
        }
    }

    /**
     * Create JSON for an instance
     */
    void pushObjectPOJO(Object object) throws Exception {
        Class<?> cl = object.getClass();
        Field[] fields = cl.getFields();
        for (int i = 0; i < fields.length; i++) {
            if (!Modifier.isPublic(fields[i].getModifiers()))
                continue;

            String fieldName = fields[i].getName();
            Object value;
            try {
                value = fields[i].get(object);
            } catch (IllegalAccessException e) {
                mLogger.error("IllegalAccessException", e);
                continue;
            }
            if (mLogger.isDebugEnabled()) {
                mLogger.debug("add field name " + fieldName + ", " + (value != null ? value.getClass() : null));
            }
            body.append(",");
            body.append(ScriptCompiler.JSONquote(fieldName) + ": ");
            createReturnValue(value);
        }
    }

    /**
     * Create JSON for an object that conforms to JavaBean spec.
     */
    void pushObjectJavaBean(Object object) throws Exception {
        //------------------------------------------------------------
        // Just get the fields from the objects and add it to this object
        Map<?, ?> beanProps = null;
        try {
            //Use jakarta-commons beanutils to inspect the object
            beanProps = PropertyUtils.describe(object);

            if (beanProps != null) {
                Set<?> keys = beanProps.keySet();
                Iterator<?> iter = keys.iterator();
                while (iter.hasNext()) {
                    Object obj = iter.next();

                    mLogger.warn("serialize " + obj);
                    String fieldName = (String) obj;
                    //Don't add the class property as it is already set by the method
                    //mLogger.debug("fieldName equals Class ??");
                    if (!fieldName.equals("class")) {
                        //mLogger.debug("fieldName equals Class !!");
                        Object value = beanProps.get(fieldName);
                        //if (mLogger.isDebugEnabled()) {
                        mLogger.debug(
                                "add field name " + fieldName + ", " + ((value != null) ? value.getClass() : null));
                        //}
                        if (value != null) {
                            mLogger.debug("VC NAME: " + value.getClass().getName());
                        }

                        if (Timestamp.class.isInstance(value)) {
                            mLogger.warn("Found Timestamp");
                            value = value.toString();
                            body.append(", ");
                            body.append(ScriptCompiler.JSONquote(fieldName) + ": ");
                            createReturnValue(value);
                        } else {
                            body.append(", ");
                            body.append(ScriptCompiler.JSONquote(fieldName) + ": ");
                            createReturnValue(value);
                        }
                    }
                }
            }

        } catch (IllegalAccessException e) {
            mLogger.error("IllegalAccessException", e);
        } catch (InvocationTargetException e) {
            mLogger.error("InvocationTargetException", e);
        } catch (NoSuchMethodException e) {
            mLogger.error("NoSuchMethodException", e);
        } catch (Exception err) {

            if (object != null) {
                mLogger.error("[pushObjectJavaBean]" + object.getClass().getName());
                mLogger.error("[pushObjectJavaBean]" + object.toString());
            }
            mLogger.error("[pushObjectJavaBean]", err);
        }
    }

    void pushMap(Map<?, ?> map) throws Exception {

        Iterator<?> iter = map.keySet().iterator();
        int i = 0;

        body.append("{");
        while (iter.hasNext()) {
            Object key = iter.next();
            if (i++ > 0) {
                body.append(", ");
            }

            body.append(ScriptCompiler.JSONquote("" + key) + ": ");
            createReturnValue(map.get(key));
        }
        body.append("}");

    }

    /**
     * Recurse through this function to create return value
     */
    void createReturnValue(Object object) throws Exception {
        if (object == null) {
            pushNull();
            return;
        }

        Class<?> cl = object.getClass();
        if (cl.isArray()) {
            pushArray(object);
        } else if (List.class.isInstance(object)) {
            pushList((List<?>) object);
        } else if (Set.class.isInstance(object)) {
            pushSet((Set<?>) object);
        } else if (Map.class.isInstance(object)) {
            pushMap((Map<?, ?>) object);
        } else if (cl == Integer.class) {
            pushInteger(((Integer) object).intValue());
        } else if (cl == Long.class) {
            //------------------------------------------------------------
            // From: http://developer.irt.org/script/1031.htm
            //
            // In JavaScript all numbers are floating-point numbers.
            //
            // JavaScript uses the standard 8 byte IEEE floating-point numeric
            // format, which means the range is from:
            //
            // +/- 1.7976931348623157x10^308 - very large, and +/- 5x10^-324 -
            // very small.
            //
            // As JavaScript uses floating-point numbers the accuracy is only
            // assured for integers between: -9,007,199,254,740,992 (-2^53) and
            // 9,007,199,254,740,992 (2^53)
            //
            // All the above from "JavaScript The Definitive Guide" - O'Reilly. 
            // 
            //------------------------------------------------------------
            // Java long:
            // 8 bytes signed (two's complement). Ranges from
            // -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807.
            //------------------------------------------------------------

            // possible rounding inaccuracy
            pushInteger(((Long) object).intValue());

        } else if (cl == Short.class) {
            pushInteger(((Short) object).intValue());
        } else if (cl == Byte.class) {
            // push as number for now
            pushInteger(((Byte) object).intValue());
        } else if (cl == Character.class) {
            pushString(((Character) object).toString());
        } else if (cl == Float.class) {
            pushFloat(((Float) object).floatValue());
        } else if (cl == Double.class) {
            pushDouble(((Double) object).doubleValue());
        } else if (cl == Boolean.class) {
            pushBoolean(((Boolean) object).booleanValue());
        } else if (cl == String.class) {
            pushString((String) object);
        } else {
            pushObject(object);
        }
    }

    public String createObjectProgram(Object object) throws Exception {
        createReturnValue(object);
        return body.toString();
    }

}