@Override
  public boolean next(LongWritable key, Text value) throws IOException {
    /*
     * NOTE : we are not using a JSONParser, so this will not validate JSON structure aside from correct counts of '{' and '}'
     * The fact that it may handle some invalid JSON, does not imply that we support invalid JSON;
     * rather, updates to the code may require valid JSON in order to locate record boundaries.
     *
     * We will count '{' and '}' to find the beginning and end of each record, while ignoring braces in string literals.
     */

    int chr = 0;
    int brace_depth = 0;
    char lit_char = 0;
    boolean first_brace_found = false;

    // The case of split point exactly at whitespace between records,
    // is handled by forcing the record following to the split following,
    // in the interest of better balancing the splits, by consuming the
    // whitespace before checking the end of the split.
    if (!firstBraceConsumed) {  // That should only ever be true on the very first read in the split
      chr = getNonWhite();
      firstBraceConsumed = (chr == '{');
    }

    if (readerPosition + (firstBraceConsumed ? 0 : 1) > end) {
      return false;
    }

    StringBuilder sb = new StringBuilder(2000);

    if (firstBraceConsumed) {
      // first open brace was consumed already;
      // update initial state accordingly
      brace_depth = 1;
      sb.append("{");
      first_brace_found = true;
      firstBraceConsumed = false;
      key.set(readerPosition - 1);
    }

    boolean inEscape = false;
    while (brace_depth > 0 || !first_brace_found) {
      chr = getChar();

      if (chr < 0) {
        if (first_brace_found) {
          // last record was invalid
          LOG.error("Parsing error : EOF occurred before record ended");
        }
        return false;
      }

      switch (chr) {
      case '\\':
        inEscape = (lit_char != 0 && !inEscape);
        break;
      case '"':
      case '\'':
        if (lit_char == 0) {
          lit_char = (char) chr;  // mark start literal (double/single quote)
        } else if (inEscape) {
          inEscape = false;
        } else if (lit_char == chr) {
          lit_char = 0;   // mark end literal (double/single-quote)
        }
        // ignored because we found a ' inside a " " block quote (or vice versa)
        break;
      case '{':
        if (inEscape) {
          inEscape = false;
        } else if (lit_char == 0) {  // not in string literal,
          brace_depth++;         // so increase brace depth
          if (!first_brace_found) {
            first_brace_found = true;
            key.set(readerPosition - 1); // set record key to the char offset of the first '{'
          }
        }
        break;
      case '}':
        if (inEscape) {
          inEscape = false;
        } else if (lit_char == 0) { // not in string literal,
          brace_depth--;  //  so decrease brace depth
        }
        break;
      default:
        inEscape = false;
        break;
      }

      if (brace_depth < 0) {
        // found more '}'s than we did '{'s
        LOG.error("Parsing error : no '{' - unmatched '}' in record");
        return false;
      }

      if (first_brace_found) {
        sb.append((char) chr);
      }
    }

    // no '{' found before EOF.  Not an error as this could mean that there is extra white-space at the end
    if (!first_brace_found) {
      return false;
    }

    value.set(sb.toString());
    return true;
  }
Enumerates records from an Unenclosed JSON file - use either Esri JSON or GeoJSON subclass
ql/src/java/org/apache/hadoop/hive/ql/io/esriJson/UnenclosedBaseJsonRecordReader.java