Package winterwell.utils.web

Source Code of winterwell.utils.web.SimpleJson

package winterwell.utils.web;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import winterwell.utils.FailureException;
import winterwell.utils.Mutable;
import winterwell.utils.Printer.IPrinter;
import winterwell.utils.StrUtils;
import winterwell.utils.containers.Containers;

/**
* A simple but friendly JSON import/export class.
*
* TODO should we use Jetty's JSON class instead? Or Gson?
*
* @testedby {@link SimpleJsonTest}
* @author daniel
*/
public class SimpleJson {

  private static final Object END_OF_ARRAY = "]";
  private static final Object END_OF_MAP = "}";
  static final Map<Class, IPrinter> useMe = new HashMap<Class, IPrinter>();

  public static final <X> void addPlugin(Class<X> klass, IPrinter<X> convertor) {
    useMe.put(klass, convertor);
  }

  /**
   * Convenience for drilling down through the map-of-maps data structures
   * that JSON tends to throw up. Does not do any conversion.
   *
   * @param <X>
   * @param jsonObj
   * @param fields
   *            or integers for array indices
   * @return e.g. jsonObj.field1.field2
   * @throws NullPointerException
   *             if any field _except the final one_ is missing.
   */
  public static <X> X get(Object jsonObj, Object... fields) {
    assert jsonObj instanceof Map || jsonObj instanceof List : jsonObj;
    for (int i = 0; i < fields.length; i++) {
      Object fi = fields[i];
      if (fi instanceof String) {
        String f = (String) fi;
        Object jsonObj2 = ((Map) jsonObj).get(f);
        if (jsonObj2 == null)
          throw new NullPointerException(jsonObj + ".." + f);
        jsonObj = jsonObj2;
        continue;
      }
      Integer f = ((Number) fi).intValue();
      jsonObj = ((List) jsonObj).get(f);
      if (jsonObj == null)
        throw new NullPointerException(jsonObj + ".." + f);
    }
    return (X) jsonObj;
  }

  public void appendJson(StringBuilder sb, Object x) {
    if (x == null) {
      sb.append("null");
      return;
    }
    // use a plugin?
    IPrinter prntr = useMe.get(x.getClass());
    if (prntr != null) {
      prntr.append(x, sb);
      return;
    }
    if (x instanceof CharSequence) {
      // Escape "s
      sb.append('"');
      escape(sb, (CharSequence) x);
      sb.append('"');
      return;
    }
    if (x instanceof Number) {
      sb.append(x.toString());
      return;
    }
    if (x instanceof Boolean) {
      sb.append(x.toString());
      return;
    }
    if (x instanceof Map) {
      appendJson2_map((Map) x, sb);
      return;
    }
    if (x.getClass().isArray()) {
      x = Containers.arrayAsList(x);
    }
    if (x instanceof Collection) {
      appendJson2_list((Collection) x, sb);
      return;
    }
    // fallback to toString()
    // Escape "s
    sb.append('"');
    escape(sb, x.toString());
    sb.append('"');
    // Log.report("SimpleJson: ...Unknown type: "+x.getClass());
  }

  private void appendJson2_list(Collection list, StringBuilder sb) {
    sb.append("[");
    for (Object x : list) {
      appendJson(sb, x);
      sb.append(", ");
    }
    if (!list.isEmpty()) {
      StrUtils.pop(sb, 2);
    }
    sb.append("]");
  }

  private void appendJson2_map(Map map, StringBuilder sb) {
    sb.append("{");
    for (Object key : map.keySet()) {
      appendJson(sb, key);
      sb.append(":");
      appendJson(sb, map.get(key));
      sb.append(", ");
    }
    if (!map.isEmpty()) {
      StrUtils.pop(sb, 2);
    }
    sb.append("}");
  }

  /**
   * Escape "s, tabs, \r, \n
   *
   * @param sb
   * @param x
   */
  private void escape(StringBuilder sb, CharSequence x) {
    char b;
    char c = 0;
    String hhhh;
    int len = x.length();

    for (int i = 0, n = x.length(); i < n; i++) {
      b = c;
      c = x.charAt(i);

      switch (c) {
      case '\\':
      case '"':
        sb.append('\\');
        sb.append(c);
        break;
      case '/':
        if (b == '<') {
          sb.append('\\');
        }
        sb.append(c);
        break;
      case '\b':
        sb.append("\\b");
        break;
      case '\t':
        sb.append("\\t");
        break;
      case '\n':
        sb.append("\\n");
        break;
      case '\f':
        sb.append("\\f");
        break;
      case '\r':
        sb.append("\\r");
        break;
      default:
        if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
            || (c >= '\u2000' && c < '\u2100')) {
          hhhh = "000" + Integer.toHexString(c);
          sb.append("\\u" + hhhh.substring(hhhh.length() - 4));
        } else {
          sb.append(c);
        }
      }
    }
  }

  @Deprecated
  // doesn't work yet
  public Object fromJson(String json) {
    return fromJson2(json, new Mutable.Int(0));
  }

  Object fromJson2(String json, Mutable.Int index) {
    // String?
    char ci = json.charAt(index.value);
    if (ci == '"' || ci == '\'') {
      // find closing quote
      StringBuilder word = new StringBuilder();
      index.value++;
      boolean escaped = false;
      for (; index.value < json.length(); index.value++) {
        char c = json.charAt(index.value);
        if (escaped) {
          word.append(c);
          escaped = false;
          continue;
        }
        if (c == ci)
          // index.value++;
          return word.toString();
        if (c == '\\') {
          escaped = true;
        } else {
          word.append(c);
        }
      }
      throw new IllegalArgumentException(json);
    }
    if (StrUtils.isNumber(json))
      return Double.valueOf(json);
    if (json.startsWith("null", index.value)) {
      index.value += 4;
      return null;
    }
    if (json.startsWith("true", index.value)) {
      index.value += 4;
      return Boolean.TRUE;
    }
    if (json.startsWith("false", index.value)) {
      index.value += 5;
      return Boolean.FALSE;
    }
    // array
    if (ci == '[') {
      index.value++;
      List array = new ArrayList();
      for (; index.value < json.length(); index.value++) {
        Object e = fromJson2(json, index);
        if (e == END_OF_ARRAY) {
          break;
        }
        array.add(e);
      }
      return array;
    }
    if (ci == ']')
      return END_OF_ARRAY;
    // map
    if (ci == '{') {
      index.value++;
      Map array = new HashMap();
      for (; index.value < json.length(); index.value++) {
        Object k = fromJson2(json, index);
        Object marker = fromJson2(json, index);
        Object v = fromJson2(json, index);
        if (marker != ":")
          throw new FailureException(json);
        array.put(k, v);
      }
      return array;
    }
    if (ci == '}')
      return END_OF_MAP;
    if (ci == ':')
      return ":";
    throw new RuntimeException("TODO! " + json.substring(0, index.value)
        + "^" + json.substring(index.value));
  }

  public String toJson(Object obj) {
    StringBuilder sb = new StringBuilder();
    appendJson(sb, obj);
    String json = sb.toString();

    return json;
  }

}
TOP

Related Classes of winterwell.utils.web.SimpleJson

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.