Package org.nutz.json.impl

Source Code of org.nutz.json.impl.JsonRenderImpl$Pair

package org.nutz.json.impl;

import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Pattern;

import org.nutz.json.Json;
import org.nutz.json.JsonFormat;
import org.nutz.json.JsonRender;
import org.nutz.json.entity.JsonEntity;
import org.nutz.json.entity.JsonEntityField;
import org.nutz.lang.FailToGetValueException;
import org.nutz.lang.Lang;
import org.nutz.lang.Mirror;
import org.nutz.lang.Strings;

/**
* @author zozoh(zozohtnt@gmail.com)
* @author wendal(wendal1985@gmail.com)
*
*/
@SuppressWarnings({"rawtypes"})
public class JsonRenderImpl implements JsonRender {

    private static String NL = "\n";

    private JsonFormat format;

    private Writer writer;

    private Set<Object> memo = new HashSet<Object>();

    public JsonFormat getFormat() {
        return format;
    }

    public void setFormat(JsonFormat format) {
        this.format = format;
    }

    public Writer getWriter() {
        return writer;
    }

    public void setWriter(Writer writer) {
        this.writer = writer;
    }

    public void render(Object obj) throws IOException {
        if (null == obj) {
            writer.write("null");
        } else if (obj instanceof JsonRender) {
            ((JsonRender) obj).render(null);
        } else if (obj instanceof Class) {
            string2Json(((Class<?>) obj).getName());
        } else if (obj instanceof Mirror) {
            string2Json(((Mirror<?>) obj).getType().getName());
        } else {
            Mirror mr = Mirror.me(obj.getClass());
            // 枚举
            if (mr.isEnum()) {
                string2Json(((Enum) obj).name());
            }
            // 数字,布尔等
            else if (mr.isNumber() || mr.isBoolean()) {
                writer.append(obj.toString());
            }
            // 字符串
            else if (mr.isStringLike() || mr.isChar()) {
                string2Json(obj.toString());
            }
            // 日期时间
            else if (mr.isDateTimeLike()) {
                string2Json(format.getCastors().castToString(obj));
            }
            // 其他
            else {
                // Map
                if (obj instanceof Map) {
                    map2Json((Map) obj);
                }
                // 集合
                else if (obj instanceof Collection) {
                    coll2Json((Collection) obj);
                }
                // 数组
                else if (obj.getClass().isArray()) {
                    array2Json(obj);
                }
                // 普通 Java 对象
                else {
                    memo.add(obj);
                    pojo2Json(obj);
                    memo.remove(obj);
                }
            }
        }
    }

    public JsonRenderImpl() {}

    public JsonRenderImpl(Writer writer, JsonFormat format) {
        this.format = format;
        this.writer = writer;
    }

    private static boolean isCompact(JsonRenderImpl render) {
        return render.format.isCompact();
    }

    private static final Pattern p = Pattern.compile("^[a-z_A-Z$]+[a-zA-Z_0-9$]*$");

    private void appendName(String name) throws IOException {
        if (format.isQuoteName() || !p.matcher(name).find())
            string2Json(name);
        else
            writer.append(name);
    }

    private void appendPairBegin() throws IOException {
        if (!isCompact(this))
            writer.append(NL).append(Strings.dup(format.getIndentBy(),
                                                 format.getIndent()));
    }

    private void appendPairSep() throws IOException {
        writer.append(!isCompact(this) ? " :" : ":");
    }

    protected void appendPair(boolean needPairEnd, String name, Object value)
            throws IOException {
        appendPairBegin();
        appendName(name);
        appendPairSep();
        render(value);
        if (needPairEnd) {
            appendPairEnd();
        }
    }

    private boolean isIgnore(String name, Object value) {
        if (null == value && format.isIgnoreNull())
            return true;
        return format.ignore(name);
    }

    private void appendPairEnd() throws IOException {
        writer.append(',');
    }

    private void appendBraceBegin() throws IOException {
        writer.append('{');
    }

    private void appendBraceEnd() throws IOException {
        if (!isCompact(this))
            writer.append(NL).append(Strings.dup(format.getIndentBy(),
                                                 format.getIndent()));
        writer.append('}');
    }

    static class Pair {

        public Pair(String name, Object value) {
            this.name = name;
            this.value = value;
        }

        String name;
        Object value;
    }

    @SuppressWarnings({"unchecked"})
    private void map2Json(Map map) throws IOException {
        if (null == map)
            return;
        appendBraceBegin();
        increaseFormatIndent();
        ArrayList<Pair> list = new ArrayList<Pair>(map.size());
        Set<Entry<?, ?>> entrySet = map.entrySet();
        for (Entry entry : entrySet) {
            String name = null == entry.getKey() ? "null" : entry.getKey()
                                                                 .toString();
            Object value = entry.getValue();
            if (!this.isIgnore(name, value))
                list.add(new Pair(name, value));
        }
        writeItem(list);
    }

    @SuppressWarnings("unchecked")
    private void pojo2Json(Object obj) throws IOException {
        if (null == obj)
            return;
        /*
         * Default
         */
        Class<?> type = obj.getClass();
        JsonEntity jen = Json.getEntity(Mirror.me(type));
        Method toJsonMethod = jen.getToJsonMethod();
        if (toJsonMethod != null) {
            try {
                if (toJsonMethod.getParameterTypes().length == 0) {
                    writer.append(String.valueOf(toJsonMethod.invoke(obj)));
                } else {
                    writer.append(String.valueOf(toJsonMethod.invoke(obj,
                                                                     format)));
                }
                return;
            }
            catch (Exception e) {
                throw Lang.wrapThrow(e);
            }
        }
        List<JsonEntityField> fields = jen.getFields();
        appendBraceBegin();
        increaseFormatIndent();
        ArrayList<Pair> list = new ArrayList<Pair>(fields.size());
        for (JsonEntityField jef : fields) {
            if (jef.isIgnore())
                continue;
            String name = jef.getName();
            try {
                Object value = jef.getValue(obj);
                // 判断是否应该被忽略
                if (!this.isIgnore(name, value)) {
                    // 以前曾经输出过 ...
                    if (null != value) {
                        // zozoh: 循环引用的默认行为,应该为 null,以便和其他语言交换数据
                        Mirror mirror = Mirror.me(value);
                        if (mirror.isPojo()) {
                            if (memo.contains(value))
                                value = null;
                        }
                    }
                    // 如果是强制输出为字符串的
                    if (null != value && jef.isForceString()) {
                        // 数组
                        if (value.getClass().isArray()) {
                            String[] ss = new String[Array.getLength(value)];
                            for (int i = 0; i < ss.length; i++) {
                                ss[i] = Array.get(value, i).toString();
                            }
                            value = ss;
                        }
                        // 集合
                        else if (value instanceof Collection) {
                            Collection col = (Collection) Mirror.me(value)
                                                                .born();
                            for (Object ele : (Collection) value) {
                                col.add(ele.toString());
                            }
                            value = col;
                        }
                        // 其他统统变字符串
                        else {
                            value = value.toString();
                        }
                    }

                    // 加入输出列表 ...
                    list.add(new Pair(name, value));
                }
            }
            catch (FailToGetValueException e) {}
        }
        writeItem(list);
    }

    private void writeItem(List<Pair> list) throws IOException {
        Iterator<Pair> it = list.iterator();
        while (it.hasNext()) {
            Pair p = it.next();
            appendPair(it.hasNext(), p.name, p.value);
        }
        decreaseFormatIndent();
        appendBraceEnd();
    }

    private void decreaseFormatIndent() {
        if (!isCompact(this))
            format.decreaseIndent();
    }

    private void increaseFormatIndent() {
        if (!isCompact(this))
            format.increaseIndent();
    }

    private void string2Json(String s) throws IOException {
        if (null == s)
            writer.append("null");
        else {
            char[] cs = s.toCharArray();
            writer.append(format.getSeparator());
            for (char c : cs) {
                switch (c) {
                case '"':
                    writer.append("\\\"");
                    break;
                case '\n':
                    writer.append("\\n");
                    break;
                case '\t':
                case 0x0B: // \v
                    writer.append("\\t");
                    break;
                case '\r':
                    writer.append("\\r");
                    break;
                case '\f':
                  writer.append("\\f");
                  break;
                case '\b':
                  writer.append("\\b");
                  break;
                case '\\':
                    writer.append("\\\\");
                    break;
                default:
                    if (c >= 256 && format.isAutoUnicode())
                        writer.append("\\u").append(Strings.fillHex(c, 4)
                                                           .toUpperCase());
                    else
                        writer.append(c);
                }
            }
            writer.append(format.getSeparator());
        }
    }

    private void array2Json(Object obj) throws IOException {
        writer.append('[');
        int len = Array.getLength(obj) - 1;
        if (len > -1) {
            int i;
            for (i = 0; i < len; i++) {
                render(Array.get(obj, i));
                appendPairEnd();
                writer.append(' ');
            }
            render(Array.get(obj, i));
        }
        writer.append(']');
    }

    private void coll2Json(Collection iterable) throws IOException {
        writer.append('[');
        for (Iterator<?> it = iterable.iterator(); it.hasNext();) {
            render(it.next());
            if (it.hasNext()) {
                appendPairEnd();
                writer.append(' ');
            } else
                break;
        }
        writer.append(']');
    }

}
TOP

Related Classes of org.nutz.json.impl.JsonRenderImpl$Pair

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.