org.apache.geode.management.internal.cli.util.JsonUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.geode.management.internal.cli.util.JsonUtil.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.management.internal.cli.util;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.geode.internal.ClassPathLoader;
import org.apache.geode.management.internal.cli.json.GfJsonArray;
import org.apache.geode.management.internal.cli.json.GfJsonException;
import org.apache.geode.management.internal.cli.json.GfJsonObject;
import org.apache.geode.management.internal.cli.result.CliJsonSerializable;
import org.apache.geode.management.internal.cli.result.CliJsonSerializableFactory;
import org.apache.geode.management.internal.cli.result.ResultDataException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * This class contains utility methods for JSON (http://www.json.org/) which is used by classes used
 * for the Command Line Interface (CLI).
 * 
 * 
 * @since GemFire 7.0
 */
public class JsonUtil {

    /**
     * Converts given JSON String in to a Map. Refer http://www.json.org/ to construct a JSON format.
     * 
     * @param jsonString jsonString to be converted in to a Map.
     * @return a Map created from
     * 
     * @throws IllegalArgumentException if the specified JSON string can not be converted in to a Map
     */
    public static Map<String, String> jsonToMap(String jsonString) {
        Map<String, String> jsonMap = new TreeMap<String, String>();
        try {
            GfJsonObject jsonObject = new GfJsonObject(jsonString);
            Iterator<String> keys = jsonObject.keys();

            while (keys.hasNext()) {
                String key = keys.next();
                jsonMap.put(key, jsonObject.getString(key));
            }

        } catch (GfJsonException e) {
            throw new IllegalArgumentException("Could not convert jsonString : '" + jsonString + "' to map.");
        }
        return jsonMap;
    }

    /**
     * Converts given Map in to a JSON string representing a Map. Refer http://www.json.org/ for more.
     * 
     * @param properties a Map of Strings to be converted in to JSON String
     * @return a JSON string representing the specified Map.
     */
    public static String mapToJson(Map<String, String> properties) {
        return new GfJsonObject(properties).toString();
    }

    /**
     * Converts given Object in to a JSON string representing an Object. Refer http://www.json.org/
     * for more.
     * 
     * @param object an Object to be converted in to JSON String
     * @return a JSON string representing the specified object.
     */
    public static String objectToJson(Object object) {
        return new GfJsonObject(object).toString();
    }

    /**
     * Converts given Object in to a JSON string representing an Object. If object contains an
     * attribute which itself is another object it will be displayed as className if its json
     * representation exceeds the length
     * 
     * @param object an Object to be converted in to JSON String
     * @return a JSON string representing the specified object.
     */
    public static String objectToJsonNested(Object object, int length) {
        return objectToJsonNestedChkCDep(object, length, false);
    }

    public static String objectToJsonNestedChkCDep(Object object, int length) {
        return objectToJsonNestedChkCDep(object, length, true);
    }

    private static String objectToJsonNestedChkCDep(Object object, int length, boolean checkCyclicDep) {
        GfJsonObject jsonObject = new GfJsonObject(object, checkCyclicDep);
        Iterator<String> iterator = jsonObject.keys();
        while (iterator.hasNext()) {
            String key = iterator.next();
            Object value = jsonObject.get(key);
            if (value != null && !isPrimitiveOrWrapper(value.getClass())) {
                GfJsonObject jsonified = new GfJsonObject(value);
                String stringified = jsonified.toString();
                try {
                    if (stringified.length() > length) {
                        jsonObject.put(key, jsonified.getType());
                    } else {
                        jsonObject.put(key, stringified);
                    }
                } catch (GfJsonException e) {
                    e.printStackTrace();
                }
            }
        }
        return jsonObject.toString();
    }

    /**
     * Converts given JSON String in to a Object. Refer http://www.json.org/ to construct a JSON
     * format.
     * 
     * @param jsonString jsonString to be converted in to a Map.
     * @return an object constructed from given JSON String
     * 
     * @throws IllegalArgumentException if the specified JSON string can not be converted in to an
     *         Object
     */
    public static <T> T jsonToObject(String jsonString, Class<T> klass) {
        T objectFromJson = null;
        try {
            GfJsonObject jsonObject = new GfJsonObject(jsonString);
            objectFromJson = klass.newInstance();
            Method[] declaredMethods = klass.getMethods();
            Map<String, Method> methodsMap = new HashMap<String, Method>();
            for (Method method : declaredMethods) {
                methodsMap.put(method.getName(), method);
            }

            int noOfFields = jsonObject.size();
            Iterator<String> keys = jsonObject.keys();

            while (keys.hasNext()) {
                String key = keys.next();
                Method method = methodsMap.get("set" + capitalize(key));
                if (method != null) {
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    if (parameterTypes.length == 1) {
                        Class<?> parameterType = parameterTypes[0];

                        Object value = jsonObject.get(key);
                        if (isPrimitiveOrWrapper(parameterType)) {
                            value = ConvertUtils.convert(getPrimitiveOrWrapperValue(parameterType, value),
                                    parameterType);
                        }
                        // Bug #51175
                        else if (isArray(parameterType)) {
                            value = toArray(value, parameterType);
                        } else if (isList(parameterType)) {
                            value = toList(value, parameterType);
                        } else if (isMap(parameterType)) {
                            value = toMap(value, parameterType);
                        } else if (isSet(parameterType)) {
                            value = toSet(value, parameterType);
                        } else {
                            value = jsonToObject(value.toString(), parameterType);
                        }
                        method.invoke(objectFromJson, new Object[] { value });
                        noOfFields--;
                    }

                }
            }

            if (noOfFields != 0) {
                throw new IllegalArgumentException("Not enough setter methods for fields in given JSON String : "
                        + jsonString + " in class : " + klass);
            }

        } catch (InstantiationException e) {
            throw new IllegalArgumentException("Couldn't convert JSON to Object of type " + klass, e);
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException("Couldn't convert JSON to Object of type " + klass, e);
        } catch (GfJsonException e) {
            throw new IllegalArgumentException("Couldn't convert JSON to Object of type " + klass, e);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Couldn't convert JSON to Object of type " + klass, e);
        } catch (InvocationTargetException e) {
            throw new IllegalArgumentException("Couldn't convert JSON to Object of type " + klass, e);
        }
        return objectFromJson;
    }

    private static Object toArray(Object value, Class<?> parameterType) throws GfJsonException {
        Class arrayComponentType = parameterType.getComponentType();
        if (isPrimitiveOrWrapper(arrayComponentType)) {
            if (value instanceof JSONArray) {
                try {
                    JSONArray jsonArray = (JSONArray) value;
                    Object jArray = Array.newInstance(arrayComponentType, jsonArray.length());
                    for (int i = 0; i < jsonArray.length(); i++) {
                        Array.set(jArray, i, jsonArray.get(i));
                    }
                    return jArray;
                } catch (ArrayIndexOutOfBoundsException e) {
                    throw new GfJsonException(e);
                } catch (IllegalArgumentException e) {
                    throw new GfJsonException(e);
                } catch (JSONException e) {
                    throw new GfJsonException(e);
                }
            } else {
                throw new GfJsonException("Expected JSONArray for array type");
            }
        } else
            throw new GfJsonException(
                    "Array contains non-primitive element. Non-primitive elements are not supported in json array");
    }

    /**
     * This is used in Put command this method uses HashSet as default implementation
     * 
     * @param value
     * @param parameterType
     * @return setValue
     * @throws GfJsonException
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    private static Object toSet(Object value, Class<?> parameterType) throws GfJsonException {
        try {
            JSONArray array = (JSONArray) value;
            Set set = new HashSet();
            for (int i = 0; i < array.length(); i++) {
                Object element = array.get(i);
                if (isPrimitiveOrWrapper(element.getClass())) {
                    set.add(element);
                } else
                    throw new GfJsonException("Only primitive types are supported in set type for input commands");
            }
            return set;
        } catch (JSONException e) {
            throw new GfJsonException(e);
        }
    }

    private static Object toMap(Object value, Class<?> parameterType) throws GfJsonException {
        try {
            if (value instanceof JSONObject) {
                JSONObject obj = (JSONObject) value;
                Iterator iterator = obj.keys();
                Map map = new HashMap();
                while (iterator.hasNext()) {
                    String key = (String) iterator.next();
                    Object elem;
                    elem = obj.get(key);
                    if (isPrimitiveOrWrapper(elem.getClass())) {
                        map.put(key, elem);
                    } else
                        throw new GfJsonException(
                                "Only primitive types are supported in map type for input commands");
                }
                return map;
            } else
                throw new GfJsonException("Expected JSONObject for Map. Retrieved type is " + value.getClass());
        } catch (JSONException e) {
            throw new GfJsonException(e);
        }
    }

    private static Object toList(Object value, Class<?> parameterType) throws GfJsonException {
        try {
            JSONArray array = (JSONArray) value;
            List list = new ArrayList();
            for (int i = 0; i < array.length(); i++) {
                Object element = array.get(i);
                if (isPrimitiveOrWrapper(element.getClass())) {
                    list.add(element);
                } else
                    throw new GfJsonException("Only primitive types are supported in set type for input commands");
            }
            return list;
        } catch (JSONException e) {
            throw new GfJsonException(e);
        }
    }

    public static Object jsonToObject(String jsonString) {
        Object objectFromJson = null;
        try {
            GfJsonObject jsonObject = new GfJsonObject(jsonString);

            Iterator<String> keys = jsonObject.keys();

            Object[] arr = new Object[jsonObject.size()];
            int i = 0;

            while (keys.hasNext()) {
                String key = keys.next();
                Class<?> klass = ClassPathLoader.getLatest().forName(key);
                arr[i++] = jsonToObject((String) jsonObject.get(key).toString(), klass);
            }

            if (arr.length == 1) {
                objectFromJson = arr[0];
            } else {
                objectFromJson = arr;
            }
        } catch (GfJsonException e) {
            throw new IllegalArgumentException("Couldn't convert JSON to Object.", e);
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException("Couldn't convert JSON to Object.", e);
        }

        return objectFromJson;
    }

    public static String capitalize(String str) {
        String capitalized = str;
        if (str == null || str.isEmpty()) {
            return capitalized;
        }
        capitalized = String.valueOf(str.charAt(0)).toUpperCase() + str.substring(1);

        return capitalized;
    }

    private static boolean isArray(Class<?> parameterType) {
        return parameterType.isArray();
    }

    public static boolean isList(Class<?> klass) {
        return klass.isAssignableFrom(List.class);
    }

    public static boolean isSet(Class<?> klass) {
        return klass.isAssignableFrom(Set.class);
    }

    public static boolean isMap(Class<?> klass) {
        return klass.isAssignableFrom(Map.class);
    }

    public static boolean isPrimitiveOrWrapper(Class<?> klass) {
        return klass.isAssignableFrom(Byte.class) || klass.isAssignableFrom(byte.class)
                || klass.isAssignableFrom(Short.class) || klass.isAssignableFrom(short.class)
                || klass.isAssignableFrom(Integer.class) || klass.isAssignableFrom(int.class)
                || klass.isAssignableFrom(Long.class) || klass.isAssignableFrom(long.class)
                || klass.isAssignableFrom(Float.class) || klass.isAssignableFrom(float.class)
                || klass.isAssignableFrom(Double.class) || klass.isAssignableFrom(double.class)
                || klass.isAssignableFrom(Boolean.class) || klass.isAssignableFrom(boolean.class)
                || klass.isAssignableFrom(String.class) || klass.isAssignableFrom(Character.class)
                || klass.isAssignableFrom(char.class);
    }

    public static Object getPrimitiveOrWrapperValue(Class<?> klass, Object value) throws IllegalArgumentException {
        if (klass.isAssignableFrom(Byte.class) || klass.isAssignableFrom(byte.class)) {
            return value;
        } else if (klass.isAssignableFrom(Short.class) || klass.isAssignableFrom(short.class)) {
            return value;
        } else if (klass.isAssignableFrom(Integer.class) || klass.isAssignableFrom(int.class)) {
            return value;
        } else if (klass.isAssignableFrom(Long.class) || klass.isAssignableFrom(long.class)) {
            return value;
        } else if (klass.isAssignableFrom(Float.class) || klass.isAssignableFrom(float.class)) {
            return value;
        } else if (klass.isAssignableFrom(Double.class) || klass.isAssignableFrom(double.class)) {
            return value;
        } else if (klass.isAssignableFrom(Boolean.class) || klass.isAssignableFrom(boolean.class)) {
            return value;
        } else if (klass.isAssignableFrom(String.class)) {
            return String.valueOf(value);
        } else if (klass.isAssignableFrom(Character.class)) {
            // Need to take care of converting between string to char values
            if (value instanceof String) {
                String str = (String) value;
                if (str.length() == 1)
                    return new Character(str.charAt(0));
                else if (str.length() > 1 || str.length() == 0) {
                    throw new IllegalArgumentException(
                            "Expected Character value but found String with length " + str.length());
                }
            } else if (value instanceof Character) {
                return value;
            } else {
                throw new IllegalArgumentException("Expected Character value but found " + value.getClass());
            }
        } else if (klass.isAssignableFrom(char.class)) {
            // Need to take care of converting between string to char values
            if (value instanceof String) {
                String str = (String) value;
                if (str.length() == 1)
                    return str.charAt(0);
                else if (str.length() > 1 || str.length() == 0) {
                    throw new IllegalArgumentException(
                            "Expected Character value but found String with length " + str.length());
                }
            } else if (value instanceof Character) {
                return ((Character) value).charValue();
            } else {
                throw new IllegalArgumentException("Expected Character value but found " + value.getClass());
            }
        } else {
            return null;
        }
        return value;
    }

    public static int getInt(GfJsonObject jsonObject, String byName) {
        return jsonObject.getInt(byName);
    }

    public static long getLong(GfJsonObject jsonObject, String byName) {
        return jsonObject.getLong(byName);
    }

    public static double getDouble(GfJsonObject jsonObject, String byName) {
        return jsonObject.getDouble(byName);
    }

    public static boolean getBoolean(GfJsonObject jsonObject, String byName) {
        return jsonObject.getBoolean(byName);
    }

    public static String getString(GfJsonObject jsonObject, String byName) {
        return jsonObject.getString(byName);
    }

    public static GfJsonObject getJSONObject(GfJsonObject jsonObject, String byName) {
        return jsonObject.getJSONObject(byName);
    }

    public static String[] getStringArray(GfJsonObject jsonObject, String byName) {
        String[] stringArray = null;
        try {
            GfJsonArray jsonArray = jsonObject.getJSONArray(byName);
            stringArray = GfJsonArray.toStringArray(jsonArray);
        } catch (GfJsonException e) {
            throw new ResultDataException(e.getMessage());
        }
        return stringArray;
    }

    public static byte[] getByteArray(GfJsonObject jsonObject, String byName) {
        byte[] byteArray = null;
        try {
            GfJsonArray jsonArray = jsonObject.getJSONArray(byName);
            byteArray = GfJsonArray.toByteArray(jsonArray);
        } catch (GfJsonException e) {
            throw new ResultDataException(e.getMessage());
        }
        return byteArray;
    }

    public static List<CliJsonSerializable> getList(GfJsonObject jsonObject, String byName) {
        List<CliJsonSerializable> cliJsonSerializables = Collections.emptyList();
        try {
            GfJsonArray cliJsonSerializableArray = jsonObject.getJSONArray(byName);
            int size = cliJsonSerializableArray.size();
            if (size > 0) {
                cliJsonSerializables = new ArrayList<CliJsonSerializable>();
            }
            for (int i = 0; i < size; i++) {
                GfJsonObject cliJsonSerializableState = cliJsonSerializableArray.getJSONObject(i);
                int jsId = cliJsonSerializableState.getInt(CliJsonSerializable.JSID);
                CliJsonSerializable cliJsonSerializable = CliJsonSerializableFactory.getCliJsonSerializable(jsId);
                cliJsonSerializable.fromJson(cliJsonSerializableState);
                cliJsonSerializables.add(cliJsonSerializable);
            }
        } catch (GfJsonException e) {
            throw new ResultDataException(e.getMessage());
        }
        return cliJsonSerializables;
    }

    public static Set<CliJsonSerializable> getSet(GfJsonObject jsonObject, String byName) {
        Set<CliJsonSerializable> cliJsonSerializables = Collections.emptySet();
        try {
            GfJsonArray cliJsonSerializableArray = jsonObject.getJSONArray(byName);
            int size = cliJsonSerializableArray.size();
            if (size > 0) {
                cliJsonSerializables = new HashSet<CliJsonSerializable>();
            }
            for (int i = 0; i < size; i++) {
                GfJsonObject cliJsonSerializableState = cliJsonSerializableArray.getJSONObject(i);
                int jsId = cliJsonSerializableState.getInt(CliJsonSerializable.JSID);
                CliJsonSerializable cliJsonSerializable = CliJsonSerializableFactory.getCliJsonSerializable(jsId);
                cliJsonSerializable.fromJson(cliJsonSerializableState);
                cliJsonSerializables.add(cliJsonSerializable);
            }
        } catch (GfJsonException e) {
            throw new ResultDataException(e.getMessage());
        }
        return cliJsonSerializables;
    }

    // For testing purpose
    public static void main(String[] args) {
        System.out.println(capitalize("key"));
        System.out.println(capitalize("Key"));

        String str = "{\"org.apache.geode.management.internal.cli.JsonUtil$Employee\":{\"id\":1234,\"name\":\"Foo BAR\",\"department\":{\"id\":456,\"name\":\"support\"}}}";
        Object jsonToObject = jsonToObject(str);
        System.out.println(jsonToObject);

        str = "{\"id\":1234,\"name\":\"Foo BAR\",\"department\":{\"id\":456,\"name\":\"support\"}}";
        Object jsonToObject2 = jsonToObject(str, Employee.class);
        System.out.println(jsonToObject2);
    }

    public static class Employee {
        private int id;
        private String name;
        private Department department;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Department getDepartment() {
            return department;
        }

        public void setDepartment(Department department) {
            this.department = department;
        }

        @Override
        public String toString() {
            return "Employee [id=" + id + ", name=" + name + ", department=" + department + "]";
        }
    }

    public static class Department {
        private int id;
        private String name;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Department [id=" + id + ", name=" + name + "]";
        }
    }

}