Package org.nutz.json

Source Code of org.nutz.json.JsonRendering$Pair

package org.nutz.json;

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

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)
*
*/
public class JsonRendering {
  private static String NL = "\n";

  private HashMap<Object, Object> memo;

  private Writer writer;

  JsonRendering(Writer writer, JsonFormat format) {
    this.format = format;
    this.writer = writer;
    // TODO make a new faster collection
    // implementation
    memo = new HashMap<Object, Object>();
  }

  private JsonFormat format;

  private static boolean isCompact(JsonRendering 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) ? " :" : ":");
  }

  private void appendPair(String name, Object value) throws IOException {
    appendPairBegin();
    appendName(name);
    appendPairSep();
    render(value);
  }

  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", "rawtypes"})
  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));
    }
    for (Iterator<Pair> it = list.iterator(); it.hasNext();) {
      Pair p = it.next();
      this.appendPair(p.name, p.value);
      if (it.hasNext())
        this.appendPairEnd();
    }
    decreaseFormatIndent();
    appendBraceEnd();
  }

  private void pojo2Json(Object obj) throws IOException {
    if (null == obj)
      return;
    Class<? extends Object> type = obj.getClass();
    ToJson tj = type.getAnnotation(ToJson.class);
    String myMethodName = Strings.sNull(null == tj ? null : tj.value(), "toJson");
    try {
      /*
       * toJson()
       */
      try {
        Method myMethod = type.getMethod(myMethodName);
        if (!myMethod.isAccessible())
          myMethod.setAccessible(true);
        Object re = myMethod.invoke(obj);
        writer.append(String.valueOf(re));
        return;
      }
      /*
       * toJson(JsonFormat fmt)
       */
      catch (NoSuchMethodException e1) {
        try {
          Method myMethod = type.getMethod(myMethodName, JsonFormat.class);
          if (!myMethod.isAccessible())
            myMethod.setAccessible(true);
          Object re = myMethod.invoke(obj, format);
          writer.append(String.valueOf(re));
          return;
        }
        catch (NoSuchMethodException e) {}
      }
    }
    catch (IllegalArgumentException e) {
      throw Lang.wrapThrow(e);
    }
    catch (IllegalAccessException e) {
      throw Lang.wrapThrow(e);
    }
    catch (InvocationTargetException e) {
      throw Lang.wrapThrow(e);
    }
    /*
     * Default
     */
    JsonEntity jen = Json.getEntity(type);
    List<JsonEntityField> fields = jen.getFields();
    appendBraceBegin();
    increaseFormatIndent();
    ArrayList<Pair> list = new ArrayList<Pair>(fields.size());
    for (JsonEntityField jef : fields) {
      String name = jef.getName();
      try {
        Object value = jef.getValue(obj);
        if (!this.isIgnore(name, value))
          list.add(new Pair(name, value));
      }
      catch (FailToGetValueException e) {}
    }
    for (Iterator<Pair> it = list.iterator(); it.hasNext();) {
      Pair p = it.next();
      this.appendPair(p.name, p.value);
      if (it.hasNext())
        this.appendPairEnd();
    }
    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':
          writer.append("\\t");
          break;
        case '\r':
          writer.append("\\r");
          break;
        case '\\':
          writer.append("\\\\");
          break;
        default:
          if (c >= 256 && format.isAutoUnicode())
            writer.append("\\u").append(Integer.toHexString(c).toUpperCase());
          else
            writer.append(c);
        }
      }
      writer.append(format.getSeparator());
    }
  }

  @SuppressWarnings({"rawtypes"})
  public void render(Object obj) throws IOException {
    if (null == obj) {
      writer.write("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 if (memo.containsKey(obj)) {
        writer.append("null");
      } else {
        memo.put(obj, null);
        if (obj instanceof Map)
          map2Json((Map) obj);
        else if (obj instanceof Collection)
          coll2Json((Collection) obj);
        else if (obj.getClass().isArray())
          array2Json(obj);
        else {
          pojo2Json(obj);
        }
        memo.remove(obj);
      }
    }
  }

  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));
        writer.append(',').append(' ');
      }
      render(Array.get(obj, i));
    }
    writer.append(']');
  }

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

Related Classes of org.nutz.json.JsonRendering$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.