com.parabay.client.utils.JSONCodec.java Source code

Java tutorial

Introduction

Here is the source code for com.parabay.client.utils.JSONCodec.java

Source

package com.parabay.client.utils;

/*
 * Copyright 2006 Florian Fankhauser f.fankhauser@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.
 */

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONValue;

/**
 * A simple JSON de- and encoder. And a json-rpc client.
 * 
 * @author Flo
 * 
 */
public class JSONCodec {

    /**
     * Decodes a json string. Primitives are decoded to their object wrappers,
     * json-objects are decoded to HashMaps and json-arrays are decoded to a
     * java array of objects.
     * 
     * @param json
     *            string
     * @return decoded object
     */
    public Object decode(String json) {
        if (json == null)
            throw new RuntimeException("Json string must not be null.");
        try {
            JSONValue value = JSONParser.parse(json);
            Object jsonObject = buildJavaObjectFromJSONValue(value);
            return jsonObject;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public Object decode(JSONValue value) {
        if (value == null)
            throw new RuntimeException("Json must not be null.");
        try {
            Object jsonObject = buildJavaObjectFromJSONValue(value);
            return jsonObject;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Converts a JSONValue to a Java object.
     * 
     * @param value
     * @return
     */
    private Object buildJavaObjectFromJSONValue(JSONValue value) {
        if (value.isNull() != null) {
            return null;
        }
        if (value.isBoolean() != null) {
            return Boolean.valueOf(value.isBoolean().booleanValue());
        }
        if (value.isString() != null) {
            return value.isString().stringValue();
        }
        if (value.isNumber() != null) {
            return buildNumber(value.isNumber().toString());
        }
        if (value.isArray() != null) {
            return buildJavaArrayFromJSONArray(value.isArray());
        }
        if (value.isObject() != null) {
            return buildJavaMapFromJSONObject(value.isObject());
        }
        return null;
    }

    /**
     * Converts a JSONObject to a Java Map.
     * 
     * @param value
     *            The JSONObject
     * @return Map
     */
    private Map buildJavaMapFromJSONObject(JSONObject jsonObject) {
        HashMap map = new HashMap();
        Set keys = jsonObject.keySet();
        for (Iterator iterator = keys.iterator(); iterator.hasNext();) {
            String key = (String) iterator.next();
            map.put(key, buildJavaObjectFromJSONValue(jsonObject.get(key)));
        }
        return map;
    }

    /**
     * Converts a JSONArray to a Java array of objects.
     * 
     * @param jsonArray
     *            The JSONArray
     * @return Array of objects
     */
    private Object[] buildJavaArrayFromJSONArray(JSONArray jsonArray) {
        Object[] array = new Object[jsonArray.size()];
        for (int i = 0; i < jsonArray.size(); i++) {
            array[i] = buildJavaObjectFromJSONValue(jsonArray.get(i));
        }
        return array;
    }

    /**
     * Encodes a java object. Supported are primitive types in their object
     * wrappers, arrays of primitives, arrays of objects, arrays of arrays,
     * Lists, Maps, Sets, Vectors and Dates. You can nest objects without limit.
     * Arrays, Lists, Sets and Vectors are encodet to json-arrays. Maps are
     * encoded to json-objects. Dates are encoded with their getTime() method,
     * which results in an unix-timestamp.
     * 
     * @param object
     *            java object to encode
     * @return json string
     */
    public String encode(Object object) {
        StringBuffer buffer = new StringBuffer();
        encodeValue(buffer, object);
        return buffer.toString();
    }

    /**
     * To add new serializable type override this method, add your serializing
     * code and than call super.
     * 
     * @param buffer
     * @param object
     */
    protected void encodeValue(StringBuffer buffer, Object object) {
        if (object == null) {
            buffer.append("null");
            return;
        }

        if (object instanceof Boolean) {
            Boolean bool = (Boolean) object;
            buffer.append(bool.booleanValue() ? "true" : "false");
            return;
        }

        if (object instanceof String) {
            encodeString(buffer, (String) object);
            return;
        }

        if (object instanceof Number) {
            buffer.append(object.toString());
            return;
        }

        if (object instanceof Object[]) {
            encodeArray(buffer, (Object[]) object);
            return;
        }

        if (object instanceof Map) {
            encodeObject(buffer, (Map) object);
            return;
        }

        if (object instanceof List) {
            encodeList(buffer, (List) object);
            return;
        }

        if (object instanceof Set) {
            encodeSet(buffer, (Set) object);
            return;
        }

        if (object instanceof Date) {
            encodeDate(buffer, (Date) object);
            return;
        }

        if (encodeArrayOfPrimitive(buffer, object)) {
            return;
        }

        throw new RuntimeException("Not serializable: " + object);
    }

    protected void encodeSet(StringBuffer buffer, Set set) {
        encodeArray(buffer, set.toArray());
    }

    /**
     * Dates get encoded as number of milliseconds since January 1, 1970,
     * 00:00:00 GMT (Unix Timestamp). Thats because JSON has no date type and
     * most languages can handle these unix timestamps easily. Override it if
     * you prefer another encoding for dates.
     * 
     * @param buffer
     * @param date
     */
    protected void encodeDate(StringBuffer buffer, Date date) {
        encodeValue(buffer, new Long(date.getTime()));
    }

    /**
     * Lists get encoded as arrays. Override it if you prefer another encoding
     * for lists.
     * 
     * @param buffer
     * @param list
     */
    protected void encodeList(StringBuffer buffer, List list) {
        encodeArray(buffer, list.toArray());
    }

    private boolean encodeArrayOfPrimitive(StringBuffer buffer, Object array) {
        if (array instanceof boolean[]) {
            encodeArray(buffer, convertBooleanToObjectArray((boolean[]) array));
        } else if (array instanceof byte[]) {
            encodeArray(buffer, convertByteToObjectArray((byte[]) array));
        } else if (array instanceof char[]) {
            encodeArray(buffer, convertCharToObjectArray((char[]) array));
        } else if (array instanceof double[]) {
            encodeArray(buffer, convertDoubleToObjectArray((double[]) array));
        } else if (array instanceof float[]) {
            encodeArray(buffer, convertFloatToObjectArray((float[]) array));
        } else if (array instanceof int[]) {
            encodeArray(buffer, convertIntToObjectArray((int[]) array));
        } else if (array instanceof long[]) {
            encodeArray(buffer, convertLongToObjectArray((long[]) array));
        } else if (array instanceof short[]) {
            encodeArray(buffer, convertShortToObjectArray((short[]) array));
        } else {
            return false;
        }
        return true;
    }

    private Object[] convertShortToObjectArray(short[] s) {
        Object[] result = new Object[s.length];
        for (int i = 0; i < s.length; i++) {
            result[i] = new Short(s[i]);
        }
        return result;
    }

    private Object[] convertLongToObjectArray(long[] ls) {
        Object[] result = new Object[ls.length];
        for (int i = 0; i < ls.length; i++) {
            result[i] = new Long(ls[i]);
        }
        return result;
    }

    private Object[] convertIntToObjectArray(int[] is) {
        Object[] result = new Object[is.length];
        for (int i = 0; i < is.length; i++) {
            result[i] = new Integer(is[i]);
        }
        return result;
    }

    private Object[] convertFloatToObjectArray(float[] fs) {
        Object[] result = new Object[fs.length];
        for (int i = 0; i < fs.length; i++) {
            result[i] = new Float(fs[i]);
        }
        return result;
    }

    private Object[] convertDoubleToObjectArray(double[] ds) {
        Object[] result = new Object[ds.length];
        for (int i = 0; i < ds.length; i++) {
            result[i] = new Double(ds[i]);
        }
        return result;
    }

    private Object[] convertCharToObjectArray(char[] cs) {
        Object[] result = new Object[cs.length];
        for (int i = 0; i < cs.length; i++) {
            result[i] = new Character(cs[i]);
        }
        return result;
    }

    private Object[] convertByteToObjectArray(byte[] bs) {
        Object[] result = new Object[bs.length];
        for (int i = 0; i < bs.length; i++) {
            result[i] = new Byte(bs[i]);
        }
        return result;
    }

    private Object[] convertBooleanToObjectArray(boolean[] booleanArray) {
        Object[] result = new Object[booleanArray.length];
        for (int i = 0; i < booleanArray.length; i++) {
            result[i] = Boolean.valueOf(booleanArray[i]);
        }
        return result;
    }

    private void encodeObject(StringBuffer buffer, Map map) {
        buffer.append("{");
        for (Iterator iter = map.keySet().iterator(); iter.hasNext();) {
            String key = (String) iter.next();
            buffer.append("\"").append(key).append("\":");
            encodeValue(buffer, map.get(key));
            if (iter.hasNext()) {
                buffer.append(",");
            }
        }
        buffer.append("}");
    }

    private void encodeArray(StringBuffer buffer, Object[] objects) {
        buffer.append("[");
        for (int i = 0; i < objects.length; i++) {
            encodeValue(buffer, objects[i]);
            if (i < objects.length - 1) {
                buffer.append(",");
            }
        }
        buffer.append("]");
    }

    private void encodeString(StringBuffer buffer, String string) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < string.length(); i++) {
            char c = string.charAt(i);
            switch (c) {
            case '"':
                sb.append("\\\"");
                break;
            case '\\':
                sb.append("\\\\");
                break;
            case '\b':
                sb.append("\\b");
                break;
            case '\f':
                sb.append("\\f");
                break;
            case '\n':
                sb.append("\\n");
                break;
            case '\r':
                sb.append("\\r");
                break;
            case '\t':
                sb.append("\\t");
                break;
            case '/':
                sb.append("\\/");
                break;
            default:
                if (c >= '\u0000' && c <= '\u001F') {
                    String hex = Integer.toHexString(c);
                    sb.append("\\u");
                    for (int j = 0; j < 4 - hex.length(); j++) {
                        sb.append('0');
                    }
                    sb.append(hex.toUpperCase());
                } else {
                    sb.append(c);
                }
            }
        }
        buffer.append("\"").append(sb.toString()).append("\"");
    }

    private Number buildNumber(String value) {
        try {
            Integer i = new Integer(value);
            if (!value.equals(i.toString()))
                throw new RuntimeException("Not an integer");
            return i;
        } catch (Exception e) {
            try {
                Long l = new Long(value);
                if (!value.equals(l.toString()))
                    throw new RuntimeException("Not a long");
                return l;
            } catch (Exception e2) {
                try {
                    Double d = new Double(value);
                    return d;
                } catch (Exception e3) {
                }
            }
        }
        throw new RuntimeException("Cannot parse number: " + value);
    }

}