/**
   * Construct a JSONObject from a ResourceBundle.
   *
   * @param baseName The ResourceBundle base name.
   * @param locale The Locale to load the ResourceBundle for.
   * @throws JSONException If any JSONExceptions are detected.
   */
  public JSONObject(String baseName, Locale locale) throws JSONException {
    this();
    ResourceBundle bundle =
        ResourceBundle.getBundle(baseName, locale, Thread.currentThread().getContextClassLoader());

    // Iterate through the keys in the bundle.

    Enumeration keys = bundle.getKeys();
    while (keys.hasMoreElements()) {
      Object key = keys.nextElement();
      if (key instanceof String) {

        // Go through the path, ensuring that there is a nested JSONObject for each
        // segment except the last. Add the value using the last segment's name into
        // the deepest nested JSONObject.

        String[] path = ((String) key).split("\\.");
        int last = path.length - 1;
        JSONObject target = this;
        for (int i = 0; i < last; i += 1) {
          String segment = path[i];
          JSONObject nextTarget = target.optJSONObject(segment);
          if (nextTarget == null) {
            nextTarget = new JSONObject();
            target.put(segment.toLowerCase(), nextTarget);
          }
          target = nextTarget;
        }
        target.put(path[last].toLowerCase(), bundle.getString((String) key));
      }
    }
  }
 /**
  * Append values to the array under a key. If the key does not exist in the JSONObject, then the
  * key is put in the JSONObject with its value being a JSONArray containing the value parameter.
  * If the key was already associated with a JSONArray, then the value parameter is appended to it.
  *
  * @param key A key string.
  * @param value An object to be accumulated under the key.
  * @return this.
  * @throws JSONException If the key is null or if the current value associated with the key is not
  *     a JSONArray.
  */
 public JSONObject append(String key, Object value) throws JSONException {
   testValidity(value);
   Object object = opt(key);
   if (object == null) {
     put(key.toLowerCase(), new JSONArray().put(value));
   } else if (object instanceof JSONArray) {
     put(key.toLowerCase(), ((JSONArray) object).put(value));
   } else {
     throw new JSONException("JSONObject[" + key + "] is not a JSONArray.");
   }
   return this;
 }
 /**
  * Accumulate values under a key. It is similar to the put method except that if there is already
  * an object stored under the key then a JSONArray is stored under the key to hold all of the
  * accumulated values. If there is already a JSONArray, then the new value is appended to it. In
  * contrast, the put method replaces the previous value.
  *
  * <p>If only one value is accumulated that is not a JSONArray, then the result will be the same
  * as using put. But if multiple values are accumulated, then the result will be like append.
  *
  * @param key A key string.
  * @param value An object to be accumulated under the key.
  * @return this.
  * @throws JSONException If the value is an invalid number or if the key is null.
  */
 public JSONObject accumulate(String key, Object value) throws JSONException {
   testValidity(value);
   Object object = opt(key);
   if (object == null) {
     put(key.toLowerCase(), value instanceof JSONArray ? new JSONArray().put(value) : value);
   } else if (object instanceof JSONArray) {
     ((JSONArray) object).put(value);
   } else {
     put(key.toLowerCase(), new JSONArray().put(object).put(value));
   }
   return this;
 }
  /**
   * Serializing means getting every field, and setting the appropriate JSONObject field. Actual
   * serialization is done at the end when the whole JSON object is built
   *
   * @param serializer
   * @param obj
   * @param structObjectInspector
   */
  private JSONObject serializeStruct(
      Object obj, StructObjectInspector soi, List<String> columnNames) {
    // do nothing for null struct
    if (null == obj) {
      return null;
    }

    JSONObject result = new JSONObject();

    List<? extends StructField> fields = soi.getAllStructFieldRefs();

    for (int i = 0; i < fields.size(); i++) {
      StructField sf = fields.get(i);
      Object data = soi.getStructFieldData(obj, sf);

      if (null != data) {
        try {
          // we want to serialize columns with their proper HIVE name,
          // not the _col2 kind of name usually generated upstream
          result.put(
              getSerializedFieldName(columnNames, i, sf),
              serializeField(data, sf.getFieldObjectInspector()));

        } catch (JSONException ex) {
          LOG.warn("Problem serializing", ex);
          throw new RuntimeException(ex);
        }
      }
    }
    return result;
  }
 /**
  * Increment a property of a JSONObject. If there is no such property, create one with a value of
  * 1. If there is such a property, and if it is an Integer, Long, Double, or Float, then add one
  * to it.
  *
  * @param key A key string.
  * @return this.
  * @throws JSONException If there is already a property with this name that is not an Integer,
  *     Long, Double, or Float.
  */
 public JSONObject increment(String key) throws JSONException {
   Object value = opt(key);
   if (value == null) {
     put(key, 1);
   } else if (value instanceof Integer) {
     put(key, ((Integer) value).intValue() + 1);
   } else if (value instanceof Long) {
     put(key, ((Long) value).longValue() + 1);
   } else if (value instanceof Double) {
     put(key, ((Double) value).doubleValue() + 1);
   } else if (value instanceof Float) {
     put(key, ((Float) value).floatValue() + 1);
   } else {
     throw new JSONException("Unable to increment [" + quote(key) + "].");
   }
   return this;
 }
 /**
  * Put a key/value pair in the JSONObject, but only if the key and the value are both non-null,
  * and only if there is not already a member with that name.
  *
  * @param key
  * @param value
  * @return his.
  * @throws JSONException if the key is a duplicate
  */
 public final JSONObject putOnce(String key, Object value) throws JSONException {
   if (key != null && value != null) {
     if (opt(key) != null) {
       throw new JSONException("Duplicate key \"" + key + "\"");
     }
     put(key, value);
   }
   return this;
 }
  /**
   * Serializes a Hive map<> using a JSONObject.
   *
   * @param obj the object to serialize
   * @param moi the object's inspector
   * @return
   */
  private JSONObject serializeMap(Object obj, MapObjectInspector moi) {
    if (obj == null) {
      return null;
    }

    JSONObject jo = new JSONObject();
    Map m = moi.getMap(obj);

    for (Object k : m.keySet()) {
      try {
        jo.put(
            serializeField(k, moi.getMapKeyObjectInspector()).toString(),
            serializeField(m.get(k), moi.getMapValueObjectInspector()));
      } catch (JSONException ex) {
        LOG.warn("Problem serializing map");
      }
    }
    return jo;
  }
 /**
  * Put a key/value pair in the JSONObject, where the value will be a JSONObject which is produced
  * from a Map.
  *
  * @param key A key string.
  * @param value A Map value.
  * @return this.
  * @throws JSONException
  */
 public JSONObject put(String key, Map value) throws JSONException {
   put(key, new JSONObject(value));
   return this;
 }
 /**
  * Put a key/long pair in the JSONObject.
  *
  * @param key A key string.
  * @param value A long which is the value.
  * @return this.
  * @throws JSONException If the key is null.
  */
 public JSONObject put(String key, long value) throws JSONException {
   put(key, new Long(value));
   return this;
 }
 /**
  * Put a key/int pair in the JSONObject.
  *
  * @param key A key string.
  * @param value An int which is the value.
  * @return this.
  * @throws JSONException If the key is null.
  */
 public JSONObject put(String key, int value) throws JSONException {
   put(key, new Integer(value));
   return this;
 }
 /**
  * Put a key/double pair in the JSONObject.
  *
  * @param key A key string.
  * @param value A double which is the value.
  * @return this.
  * @throws JSONException If the key is null or if the number is invalid.
  */
 public JSONObject put(String key, double value) throws JSONException {
   put(key, new Double(value));
   return this;
 }
 /**
  * Put a key/value pair in the JSONObject, where the value will be a JSONArray which is produced
  * from a Collection.
  *
  * @param key A key string.
  * @param value A Collection value.
  * @return this.
  * @throws JSONException
  */
 public JSONObject put(String key, Collection value) throws JSONException {
   put(key, new JSONArray(value));
   return this;
 }
 /**
  * Put a key/boolean pair in the JSONObject.
  *
  * @param key A key string.
  * @param value A boolean which is the value.
  * @return this.
  * @throws JSONException If the key is null.
  */
 public JSONObject put(String key, boolean value) throws JSONException {
   put(key, value ? Boolean.TRUE : Boolean.FALSE);
   return this;
 }
 /**
  * Put a key/value pair in the JSONObject, but only if the key and the value are both non-null.
  *
  * @param key A key string.
  * @param value An object which is the value. It should be of one of these types: Boolean, Double,
  *     Integer, JSONArray, JSONObject, Long, String, or the JSONObject.NULL object.
  * @return this.
  * @throws JSONException If the value is a non-finite number.
  */
 public JSONObject putOpt(String key, Object value) throws JSONException {
   if (key != null && value != null) {
     put(key, value);
   }
   return this;
 }