com.rejuvenation.parse.json.JProperty.java Source code

Java tutorial

Introduction

Here is the source code for com.rejuvenation.parse.json.JProperty.java

Source

/*
 * Copyright (C) 2013 'Chaos'.Personal
 *
 * 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 com.rejuvenation.parse.json;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;

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

import com.rejuvenation.parse.json.annotation.JFields;
import com.rejuvenation.reflect.ReflectUtils;
import com.rejuvenation.utils.RLog;

/**
 * the json property
 * 
 * @author Chaos
 * @date 2013-5-30
 */
public class JProperty {

    private static final String l = "<";
    private static final String r = ">";

    private Set<JFieldBean> mFieldSet;
    private Object mObj = null;

    /**
     * Queue notice:
     * HashMap<List<HashMap<String,Integer>,HashMap<Object,String>>
     * Queue? first --> List,HashMap,String,Integer then -->
     * HashMap,Object,String ,??AddQueue.
     */
    private Queue<Class<?>> mGenericQueue = null;

    private JProperty(String json, Class<?> target) {
        init();
        RLog.D.p("init ok");
        readObject(ReflectUtils.newObjectSilent(target));
        RLog.D.p("readObject ok");
    }

    private JProperty(Object obj) {
        init();
        RLog.D.p("init ok");
        readObject(obj);
        RLog.D.p("readObject ok");
    }

    private void init() {
        mFieldSet = new HashSet<JFieldBean>();
        mGenericQueue = new LinkedBlockingQueue<Class<?>>();
    }

    /**
     * Class?Set
     */
    private void readObject(Object obj) {
        mObj = obj;
        // step.1: ?target??
        Field[] fiedls = obj.getClass().getDeclaredFields();
        // step.2: ??field?,Set
        for (int i = 0; i < fiedls.length; i++) {
            Field field = fiedls[i];
            // step.2-1: JFieldBean
            JFieldBean bean = new JFieldBean(field);
            // step.2-2: init bean
            // set field name
            bean.setFieldName(field.getName());
            // set field json name
            JFields jField = field.getAnnotation(JFields.class);
            if (jField != null) {
                bean.setJsonFieldName(jField.name());
            }
            mFieldSet.add(bean);
        }
    }

    // ------ build -------
    public static String build(Object obj) {
        return new JProperty(obj).buildJson().toString();
    }

    public static JSONObject buildJsonObject(Object obj) {
        return new JProperty(obj).buildJson();
    }

    private JSONObject buildJson() {
        RLog.D.p("build json string...");
        JSONObject object = new JSONObject();
        for (JFieldBean bean : mFieldSet) {
            putObjectSilently(object, bean.getJsonFieldName(), ReflectUtils.getValue(mObj, bean.getField()));
        }
        RLog.D.p("build json string end..." + object.toString());
        return object;
    }

    private void putObjectSilently(JSONObject obj, String key, Object value) {
        try {
            RLog.D.p("putObjectSilently...");
            obj.put(key, getVeriestJson(value));
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    private Object getVeriestJson(Object value) throws JSONException {
        RLog.D.p("getVeriestJson -> " + value.getClass().getSimpleName());
        if (value instanceof Map) {
            RLog.D.p("isMap");
            return mapToJson((Map<?, ?>) value);
        } else if (value instanceof List) {
            RLog.D.p("isList");
            return listToJson((List<?>) value);
        } else if (value instanceof Set) {
            RLog.D.p("isSet");
            return setToJson((Set<?>) value);
        } else if (value instanceof JsonBean) {
            RLog.D.p("isOtherBean");
            return JProperty.buildJsonObject(value);
        } else {
            RLog.D.p("isCommon");
            return value;
        }
    }

    private JSONObject mapToJson(Map<?, ?> map) throws JSONException {
        JSONObject jobj = new JSONObject();
        for (@SuppressWarnings("rawtypes")
        Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
            Entry<?, ?> entry = (Entry<?, ?>) iterator.next();
            jobj.put(entry.getKey().toString(), getVeriestJson(entry.getValue()));
        }
        return jobj;
    }

    private JSONArray listToJson(List<?> list) throws JSONException {
        JSONArray jarray = new JSONArray();
        for (Object object : list) {
            jarray.put(getVeriestJson(object));
        }
        return jarray;
    }

    private JSONArray setToJson(Set<?> set) throws JSONException {
        JSONArray jarray = new JSONArray();
        for (Object object : set) {
            jarray.put(getVeriestJson(object));
        }
        return jarray;
    }

    // ------ reverseBuild ------
    public static <T> T toBean(String json, Class<? extends T> target) {
        return reverseBuild(json, target);
    }

    @SuppressWarnings("unchecked")
    public static <T> T reverseBuild(String json, Class<? extends T> target) {
        RLog.D.p("start -> reverseBuild");
        return (T) new JProperty(json, target).parseToClass(json);
    }

    private Object parseToClass(String json) {
        RLog.D.p("parseToClass...");
        JSONObject obj = getJsonObjectSilently(json);
        for (JFieldBean bean : mFieldSet) {
            ReflectUtils.setValue(mObj, bean.getFieldName(), getObjectSilently(obj, bean.getJsonFieldName(), bean));
        }
        return mObj;
    }

    private JSONObject getJsonObjectSilently(String json) {
        try {
            return new JSONObject(new JSONTokener(json));
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    private Object getObjectSilently(JSONObject obj, String key, JFieldBean bean) {
        try {
            RLog.D.p("getObjectSilently --> the field : " + bean.getFieldName());
            loadGenericIfNeed(bean);
            return getVeriest(obj.get(key), bean.getType());
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    }

    private void loadGenericIfNeed(JFieldBean bean) {
        RLog.D.p("loadGenericIfNeed() --->");
        // first, clear the 'queue', maybe no meaning.
        mGenericQueue.clear();

        // parse the generic and add the queue
        String[] generics = ReflectUtils.getGenericStr(bean.getField());

        // no generic
        if (generics == null) {
            RLog.D.p("the field is " + bean.getFieldName() + " it's no generic");
            return;
        } else {
            RLog.D.p("get generics complete , count is " + generics.length);

            for (int i = 0; i < generics.length; i++) {
                RLog.D.p("the " + (i + 1) + " is : " + generics[i]);
            }

            for (String generic : generics) {
                parseGenerice(generic, mGenericQueue);
            }
        }
    }

    private void parseGenerice(String str, Queue<Class<?>> queue) {
        RLog.D.p("parseGenerice() --->");
        // prototype ArrayList<HashMap<ArrayList<String>,Phone>>
        // like this : java.util.HashMap<java.util.ArrayList<java.lang.String>,
        // com.rejuvenation.database.Phone>

        // fix unknown bug at 2013-06-08...
        // i don't know why it maybe contains 'class' at the front
        if (str.contains("class")) {
            str = str.replaceAll("class", "");
        }

        List<String> list = parseStr(str);
        for (String string : list) {
            RLog.D.p("try to get the class  >" + string + "<");
            mGenericQueue.add(ReflectUtils.getClassSliently(string));
        }
    }

    private List<String> parseStr(String str) {
        RLog.D.p("parseStr(): >" + str + "<");
        // the result
        ArrayList<String> list = new ArrayList<String>();

        if (!str.contains(l) && !str.contains(r)) {
            list.add(clear(str));
            return list;
        }

        String[] left = str.split(l);
        int leftLength = left.length;
        String[] right = left[leftLength - 1].split(r);

        RLog.D.p("the left count is : " + left.length + " the right count it : " + right.length);

        for (String l : left) {
            RLog.D.p("left " + l);
            handleComma(l, list);
        }

        for (String r : right) {
            RLog.D.p("right " + r);
            handleComma(r, list);
        }
        return list;
    }

    private void handleComma(String str, List<String> list) {
        if (str.contains(", ")) {
            String[] commas = str.split(", ");
            for (String comma : commas) {
                list.add(clear(comma));
            }
        } else {
            list.add(clear(str));
        }
    }

    private String clear(String str) {
        // fix unknown bug at 2013-06-08...
        // i don't know why it maybe contains ">" at the last...
        if (str.endsWith(r)) {
            str = str.substring(0, str.length() - 1);
        }
        return str.trim();
    }

    private Object getVeriest(Object json, Class<?> type) throws JSONException {

        if (type == null) {
            RLog.D.p("getVeriest -> " + "type is null");
            return json;
        }

        RLog.D.p("getVeriest -> " + type == null ? " non-type" : type.getSimpleName());

        if (ReflectUtils.isImplements(type, Map.class)) {
            RLog.D.p("build map");
            return buildMap(json, type, ReflectUtils.buildMap(type));
        } else if (ReflectUtils.isImplements(type, List.class)) {
            RLog.D.p("build list");
            return buildList(json, type, ReflectUtils.buildList(type));
        } else if (ReflectUtils.isImplements(type, Set.class)) {
            RLog.D.p("build set");
            return buildSet(json, type, ReflectUtils.buildSet(type));
        } else if (ReflectUtils.isImplements(type, JsonBean.class)) {
            RLog.D.p("build other bean");
            return buildOtherBean(json, type);
        } else {
            RLog.D.p("build common");
            return json;
        }
    }

    private Object buildOtherBean(Object json, Class<?> type) throws JSONException {
        String jsonStr = json.toString();
        RLog.D.p("build other bean -> json: " + json + " type: " + type.getSimpleName());
        return JProperty.reverseBuild(jsonStr, type);
    }

    private Set<Object> buildSet(Object json, Class<?> type, Set<Object> set) throws JSONException {
        // now , i'm sure the json should be 'JsonArray'
        JSONArray array = (JSONArray) json;
        // get the next generice
        Class<?> generice = mGenericQueue.poll();
        for (int i = 0; i < array.length(); i++) {
            set.add(getVeriest(array.get(i), generice));
        }
        return set;
    }

    private List<Object> buildList(Object json, Class<?> type, List<Object> list) throws JSONException {
        // now , i'm sure the 'json' should be 'JsonArray'
        // don't worry cast exception,let's do it...
        JSONArray array = (JSONArray) json;
        // get the next generice
        Class<?> generice = mGenericQueue.poll();
        for (int i = 0; i < array.length(); i++) {
            list.add(getVeriest(array.get(i), generice));
        }
        return list;
    }

    private Map<Object, Object> buildMap(Object json, Class<?> type, Map<Object, Object> map) throws JSONException {
        // now , i'm sure the 'json' should be 'JsonObject'
        // don't worry cast exception,let's do it...
        JSONObject jobj = (JSONObject) json;
        Class<?> g1 = mGenericQueue.poll();
        Class<?> g2 = mGenericQueue.poll();
        for (Iterator<Object> iterator2 = jobj.keys(); iterator2.hasNext();) {
            Object key = iterator2.next();
            Object value = jobj.get(key.toString());
            map.put(getVeriest(key, g1), getVeriest(value, g2));
        }
        return map;
    }
}