The LoadJsonExample Program Source

The following LoadJsonExample java program creates and populates an Oracle NoSQL Database table with rows whose elements are JSON documents read from a text file.

package es.table;

import java.nio.file.Path;
import java.nio.file.Files;
import java.nio.file.FileSystems;

import java.io.FileNotFoundException;
import java.io.IOException;

import java.util.List;
import java.util.ArrayList;

import oracle.kv.FaultException;
import oracle.kv.KVStore;
import oracle.kv.KVStoreConfig;
import oracle.kv.KVStoreFactory;
import oracle.kv.StatementResult;

import oracle.kv.table.PrimaryKey;
import oracle.kv.table.Row;
import oracle.kv.table.Table;
import oracle.kv.table.TableAPI;
import oracle.kv.table.TableIterator;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

import oracle.kv.impl.tif.esclient.jsonContent.ESJsonUtil;

/**
 * Class that creates an example table in a given Oracle NoSQL Database store and
 * then uses the Oracle NoSQL Database Table API to populate the table with
 * sample records consisting of JSON documents retrieved from a file. The
 * table that is created consists of only two Oracle NoSQL Database data types: an
 * INTEGER type and a JSON type.
 *
 * The file from which the desired JSON documents are retrieved must be of
 * form:
 * <pre>
 {
    "meta": {
        "limit": n,
        "offset": 0,
        "total_count": n
    },
    "objects": [
        {
            JSON DOCUMENT 1
        },
        {
            JSON DOCUMENT 2
        },
        ....
        {
            JSON DOCUMENT n
        },
    ]
 }
 * </pre>
 */
public final class LoadJsonExample {

    final boolean debugWithNoStore = false;
    final boolean debugAll = false;
    final boolean debugTopLevelJsonArrayObject = false;
    final boolean debugAddDoc = false;
    final boolean debugJsonToStringTop = false;
    final boolean debugJsonToStringArray = false;
    final boolean debugDocByDoc = false;

    private final KVStore store;
    private final TableAPI tableAPI;
    private final Table table;

    private Path jsonPath;

    private boolean deleteExisting = false;

    private static final String TABLE_NAME_DEFAULT = "jsonTable";
    private static final String ID_FIELD_NAME = "id";
    private static final String JSON_FIELD_NAME = "jsonField";

    public static void main(final String[] args) {
        try {
            final LoadJsonExample loadData = new LoadJsonExample(args);
            loadData.run();
        } catch (FaultException e) {
            e.printStackTrace();
            System.out.println("Please make sure a store is running.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Parses command line args and opens the KVStore.
     */
    private LoadJsonExample(final String[] argv) {

        String storeName = "";
        String hostName = "";
        String hostPort = "";

        final int nArgs = argv.length;
        int argc = 0;
        String tableName = null;

        if (nArgs == 0) {
            usage(null);
        }

        while (argc < nArgs) {
            final String thisArg = argv[argc++];

            if ("-store".equals(thisArg)) {
                if (argc < nArgs) {
                    storeName = argv[argc++];
                } else {
                    usage("-store requires an argument");
                }
            } else if ("-host".equals(thisArg)) {
                if (argc < nArgs) {
                    hostName = argv[argc++];
                } else {
                    usage("-host requires an argument");
                }
            } else if ("-port".equals(thisArg)) {
                if (argc < nArgs) {
                    hostPort = argv[argc++];
                } else {
                    usage("-port requires an argument");
                }
            } else if ("-file".equals(thisArg)) {
                if (argc < nArgs) {
                    jsonPath = FileSystems.getDefault().getPath(argv[argc++]);
                } else {
                    usage("-file requires an argument");
                }
            } else if ("-table".equals(thisArg)) {
                if (argc < nArgs) {
                    tableName = argv[argc++];
                }
            } else if ("-security".equals(thisArg)) {
                if (argc < nArgs) {
                    System.setProperty(
                        KVSecurityConstants.SECURITY_FILE_PROPERTY,
                        argv[argc++]);
                } else {
                    usage(“-security requires an argument”);
                }

            } else if ("-delete".equals(thisArg)) {
                deleteExisting = true;
            } else {
                usage("Unknown argument: " + thisArg);
            }
        }

        if (storeName == null) {
            usage("Missing argument: -store <store-name>");
        }

        if (hostName == null) {
            usage("Missing argument: -host <host>");
        }

        if (hostPort == null) {
            usage("Missing argument: -port <port>");
        }

        if (jsonPath == null) {
            usage("Missing argument: -file <path-to-file>");
        }

        /* When the table name is not specified, construct the name of
         * the table from the file name, minus the suffix. That is strip
         * off the path and the suffix and use file name's 'base' as
         * the name of the table.
         */
        if (tableName == null) {
            final Path flnmElement = jsonPath.getFileName();
            if (flnmElement == null) {
                tableName = TABLE_NAME_DEFAULT;
            } else {
                final String tmpTblName = flnmElement.toString();
                final String suffixDelim = ".";
                if (tmpTblName.contains(suffixDelim)) {
                    final int suffixIndx = tmpTblName.indexOf(suffixDelim);
                    if (suffixIndx > 0) {
                        tableName = tmpTblName.substring(0, suffixIndx);
                    } else {
                        tableName = tmpTblName;
                    }
                } else {
                    tableName = tmpTblName;
                }
            }
        }

        System.out.println("\n--------------------------------------------");
        System.out.println("Table to create and load = " + tableName);
        System.out.println("--------------------------------------------\n");

        if (debugWithNoStore) {
            store = null;
            tableAPI = null;
            table = null;
        } else {
            store = KVStoreFactory.getStore
                (new KVStoreConfig(storeName, hostName + ":" + hostPort));

            tableAPI = store.getTableAPI();
            createTable(tableName);
            table = tableAPI.getTable(tableName);
            if (table == null) {
                final String msg =
                    "Store does not contain table [name=" + tableName + "]";
                throw new RuntimeException(msg);
            }
        }
    }

    private void usage(final String message) {
        if (message != null) {
            System.out.println("\n" + message + "\n");
        }

        System.out.println("usage: " + getClass().getName());
        System.out.println
            ("\t-store <instance name>\n" +
             "\t-host <host name>\n" +
             "\t-port <port number>\n" +
             "\t[-file <path to file with json objects to add to table> |\n" +
             "\t[-table <name of table to create and load>]\n" +
             "\t-delete (default: false) [delete all existing data first]\n");
        System.exit(1);
    }

    private void run() throws FileNotFoundException, IOException {
        if (deleteExisting) {
            deleteExistingData();
        }
        doLoad(jsonPath);
    }

    private void createTable(final String tableName) {

        final String statement =
            "CREATE TABLE IF NOT EXISTS " + tableName +
            " (" +
               ID_FIELD_NAME + " INTEGER," +
               JSON_FIELD_NAME + " JSON," +
            "PRIMARY KEY (" + ID_FIELD_NAME + "))";

        try {
            final StatementResult result = store.executeSync(statement);
            if (result.isSuccessful()) {
                System.out.println("table created [" + tableName + "]");
            } else if (result.isCancelled()) {
                System.out.println("table creation CANCELLED [" +
                                   tableName + "]");
            } else {
                if (result.isDone()) {
                    System.out.println("table creation FAILED:\n\t" +
                                       statement);
                    System.out.println("ERROR:\n\t" +
                                       result.getErrorMessage());
                } else {
                    System.out.println("table creation IN PROGRESS:\n\t" +
                                       statement);
                    System.out.println("STATUS:\n\t" + result.getInfo());
                }
            }
        } catch (IllegalArgumentException e) {
            System.out.println("Invalid statement:");
            e.printStackTrace();
        } catch (FaultException e) {
            System.out.println("Failure on statement execution:");
            e.printStackTrace();
        }
    }

    private void doLoad(final Path filePath)
                     throws FileNotFoundException, IOException {

        try {
            loadJsonDocs(filePath);
        } finally {
            if (store != null) {
                store.close();
            }
        }
    }

    private void loadJsonDocs(final Path filePath)
                     throws FileNotFoundException, IOException {

        try {
	    final byte[] jsonBytes = Files.readAllBytes(filePath);
            final int nDocsToAdd = getIntFieldValue(
                "meta", "total_count", ESJsonUtil.createParser(jsonBytes));

            if (debugAll || debugTopLevelJsonArrayObject) {

                System.out.println("BEGIN Top Level Array Object: 'objects'");

                final String objectsJsonStr =
                    getTopLevelJsonArrayObject(
                        "objects", ESJsonUtil.createParser(jsonBytes));

                System.out.println(objectsJsonStr);
                System.out.println("END Top Level Array Object: 'objects'");
                System.out.println("\nBEGIN Top Level Array Object: 'meta'");

                final String metaJsonStr =
                    getTopLevelJsonArrayObject(
                        "meta", ESJsonUtil.createParser(jsonBytes));

                System.out.println(metaJsonStr);
                System.out.println("END Top Level Array Object: 'meta'");

            } /* endif (debugAll || debugTopLevelJsonArrayObject) */

            final String[] jsonArray =
                getJsonArrayElements(
                    "objects", ESJsonUtil.createParser(jsonBytes), nDocsToAdd);

            for (int i = 0; i < nDocsToAdd; i++) {

                if (debugAll || debugAddDoc) {
                    System.out.println("Adding JSON Row[" + i +
                                       "] to table:\n" + jsonArray[i]);
                }
                addDoc(i, jsonArray[i]);
            }
        } catch (FileNotFoundException e) {
            System.out.println("File not found [" +
                               filePath.getFileName() + "]: " + e);
            throw e;
        } catch (IOException e) {
            System.out.println("IOException [file=" +
                               filePath.getFileName() + "]: " + e);
            throw e;
        }
    }

    private void addDoc(final Integer id, final String jsonDoc) {

        final Row row = table.createRow();

        row.put(ID_FIELD_NAME, id);
        row.putJson(JSON_FIELD_NAME, jsonDoc);

        tableAPI.putIfAbsent(row, null, null);
    }

    private void deleteExistingData() {

        /* Get an iterator over all the primary keys in the table. */
        final TableIterator<PrimaryKey> itr =
            tableAPI.tableKeysIterator(table.createPrimaryKey(), null, null);

        /* Delete each row from the table. */
        long cnt = 0;
        while (itr.hasNext()) {
            tableAPI.delete(itr.next(), null, null);
            cnt++;
        }
        itr.close();
        System.out.println(cnt + " records deleted");
    }

    /*
     * Convenience method for displaying output when debugging.
     */
    private void displayRow(Table tbl) {
        final TableIterator<Row> itr =
            tableAPI.tableIterator(tbl.createPrimaryKey(), null, null);
        while (itr.hasNext()) {
            System.out.println(itr.next());
        }
        itr.close();
    }


    /*
     * Supporting methods for parsing the various attributes in the given file.
     */

    private String[] getJsonArrayElements(final String arrayName,
                                          final JsonParser parser,
                                          final int nElements)
                                              throws IOException {

        final List<String> arrayList = new ArrayList<String>();

        JsonToken token = parser.nextToken();
        while (token != null) {
            final String curFieldName = parser.getCurrentName();

            if (!arrayName.equals(curFieldName)) {
                token = parser.nextToken();
                continue;
            }
            break;
        }

        if (debugAll || debugDocByDoc) {
            System.out.println(
                "getJsonArrayElements loop: curToken = " + token +
                ", curFieldName = " + parser.getCurrentName());
        }

        token = parser.nextToken();

        if (debugAll || debugDocByDoc) {
            System.out.println(
                "getJsonArrayElements loop: nextToken = " + token +
                ", nextFieldName = " + parser.getCurrentName());
        }

        if (token == null) {
            System.out.println("getJsonArrayElements loop: " +
                               "*** WARNING - null first token from parser");

            return arrayList.toArray(new String[nElements]);
        }

        if (token != JsonToken.START_ARRAY) {
            System.out.println("getJsonArrayElements loop: *** WARNING - " +
                "first token from parser != " + "START_ARRAY [" + token + "]");

            return arrayList.toArray(new String[nElements]);
        }

        for (int i = 0; i < nElements; i++) {
            final StringBuilder strBldr = new StringBuilder();
            if (i > 0) {
                strBldr.append("{\n");
            }
            final String arrayElement =
                jsonToString(arrayName, null, parser, strBldr, false);
            arrayList.add(arrayElement);

            if (debugAll || debugDocByDoc) {
                System.out.println(
                    "getJsonArrayElements loop: arrayElement[" + i + "] =\n" +
                    arrayElement);
            }

        }/* end loop */

        return arrayList.toArray(new String[nElements]);
    }

    private String getTopLevelJsonArrayObject(
                       final String fieldName,
                       final JsonParser parser) throws IOException {

        final StringBuilder strBldr = new StringBuilder();
        JsonToken token = parser.nextToken();
        while (token != null) {
            final String curFieldName = parser.getCurrentName();

            if (!fieldName.equals(curFieldName)) {
                token = parser.nextToken();
                continue;
            }
            break;
        }
        final String jsonStr =
            jsonToString(fieldName, null, parser, strBldr, false);
        return strBldr.toString();
    }

    private String jsonToString(final String stopField,
                                final JsonToken prevToken,
                                final JsonParser parser,
                                final StringBuilder strBldr,
                                final boolean fromObjectArray)
                                                  throws IOException {

        JsonToken token = parser.nextToken();

        if (token == null) {

            if (debugAll || debugJsonToStringTop) {
                System.out.println("TOP of jsonToString: prevToken = " +
                                   prevToken + ", curToken = " + token +
                                   ", RETURNING because input token == null");
            }
            return strBldr.toString();
        }

        final String curFieldName = parser.getCurrentName();

        if (debugAll || debugJsonToStringTop) {

            System.out.println("\nTOP of jsonToString");
            System.out.println("prevToken = " + prevToken +
                               ", curToken = " + token +
                               ", curFieldName = " + curFieldName +
                               ", stopField = " + stopField + ", isScalar = " +
                               token.isScalarValue() + ", fromObjectArray = " +
                               fromObjectArray);
        }

        if (prevToken != null) {

            if (prevToken == JsonToken.END_ARRAY ||
                prevToken == JsonToken.END_OBJECT) {

                if (debugAll || debugJsonToStringTop) {
                    System.out.println(
                        "*** TOP of jsonToString: prevToken != null [" +
                        prevToken + "] && " + "[END_ARRAY || END_OBJECT]");
                }

                if (stopField != null && stopField.equals(curFieldName)) {

                    if (token == JsonToken.END_ARRAY) {

                        if (debugAll || debugJsonToStringTop) {
                            System.out.println(
                                "*** STOP-BY-FIELD_NAME [END_ARRAY]: " +
                                "prevToken = " + prevToken + ", curToken = " +
                                token + ", curFieldName = " + curFieldName +
                                ", stopField = " + stopField +
                                " ... RETURN string, do not recurse, " +
                                "do not terminate outer array with ']' ..." +
                                " RETURN STR =\n" + strBldr.toString());
                        }
                        return strBldr.toString();
                    }

                    if (token == JsonToken.END_OBJECT) {

                        if (debugAll || debugJsonToStringTop) {
                            System.out.println(
                                "*** STOP-BY-FIELD_NAME [END_OBJECT]: " +
                                "prevToken = " + prevToken + ", curToken = " +
                                token + ", curFieldName = " + curFieldName +
                                ", stopField = " + stopField +
                                " ... RETURN string, do not recurse, " +
                                "but DO terminate outer array with '}' ..." +
                                " RETURN STR =\n" + strBldr.toString());
                        }
                        strBldr.append("\n}");
                        return strBldr.toString();
                    }
                } /* endif (STOP-BY-FIELD) */

                if (prevToken == JsonToken.END_OBJECT &&
                    token == JsonToken.START_OBJECT &&
                    curFieldName == null) {

                    if (fromObjectArray) {
                        if (debugAll || debugJsonToStringTop) {
                            System.out.println(
                                "*** END_OBJECT && START_OBJECT && " +
                                "curFieldName=null && is OBJECT_ARRAY: " +
                                "prevToken = " + prevToken + ", curToken = " +
                                token + ", curFieldName = " + curFieldName +
                                ", stopField = " + stopField +
                                ", fromObjectArray = " + fromObjectArray +
                                " ... add ',{' and RECURSE");
                        }
                        strBldr.append(",\n{\n");
                        return jsonToString(
                          stopField, token, parser, strBldr, fromObjectArray);
                    }

                    if (debugAll || debugJsonToStringTop) {
                        System.out.println(
                            "*** END_OBJECT && START_OBJECT && " +
                            "curFieldName=null && not OBJECT_ARRAY: " +
                            "prevToken = " + prevToken + ", curToken = " +
                            token + ", curFieldName = " + curFieldName +
                            ", stopField = " + stopField +
                            ", fromObjectArray = " + fromObjectArray +
                            " ... simply return string, do not recurse");
                    }
                    return strBldr.toString();

                } else if (prevToken == JsonToken.END_OBJECT &&
                           token == JsonToken.END_ARRAY &&
                           curFieldName != null) {

                    if (fromObjectArray) {

                        strBldr.append("\n]\n");

                        if (debugAll || debugJsonToStringTop) {
                            System.out.println(
                                "*** END_OBJECT && END_ARRAY && " +
                                "curFieldName != null && is OBJECT_ARRAY: " +
                                "prevToken = " + prevToken + ", curToken = " +
                                token + ", curFieldName = " + curFieldName +
                                ", stopField = " + stopField +
                                " terminate OBJECT_ARRAY with ']' ... " +
                                "do NOT RECURSE ... RETURN subString =\n" +
                                strBldr.toString());
                        }

                    } else { /* NOT fromObjectArray */

                        if (debugAll || debugJsonToStringTop) {
                            System.out.println(
                                "*** END_OBJECT && END_ARRAY && " +
                                "curFieldName != null && NOT OBJECT_ARRAY: " +
                                "prevToken = " + prevToken + ", curToken = " +
                                token + ", curFieldName = " + curFieldName +
                                ", stopField = " + stopField +
                                " do NOT terminate OBJECT_ARRAY ... " +
                                "do NOT RECURSE ... RETURN subString =\n" +
                                strBldr.toString());
                        }

                    } /* endif (fromObjectArray) */

                    return strBldr.toString();

                } else if (prevToken == JsonToken.END_OBJECT &&
                           token == JsonToken.END_OBJECT &&
                           (curFieldName != null || fromObjectArray)) {

                    strBldr.append("}\n");

                    if (debugAll || debugJsonToStringTop) {
                        System.out.println(
                            "*** END_OBJECT && END_ARRAY && " +
                            "curFieldName != null OR is OBJECT_ARRAY: " +
                            "prevToken = " + prevToken + ", curToken = " +
                            token + ", curFieldName = " + curFieldName +
                            ", stopField = " + stopField +
                            " , fromObjectArray = " + fromObjectArray +
                            " terminate object in OBJECT_ARRAY with '}' and " +
                            "RECURSE ...");
                    }
                    return jsonToString(
                          stopField, token, parser, strBldr, fromObjectArray);

                } else if (prevToken == JsonToken.END_ARRAY &&
                           token == JsonToken.END_OBJECT &&
                           curFieldName != null) {

                    strBldr.append("}\n");

                    if (debugAll || debugJsonToStringTop) {
                        System.out.println(
                            "*** END_ARRAY then END_OBJECT && " +
                            "curFieldName != null: " +
                            "prevToken = " + prevToken + ", curToken = " +
                            token + ", curFieldName = " + curFieldName +
                            ", stopField = " + stopField +
                            " , fromObjectArray = " + fromObjectArray +
                            " terminate object with '}' and RECURSE ...");
                    }
                    return jsonToString(
                          stopField, token, parser, strBldr, fromObjectArray);

                } else { /* DEFAULT: all other cases */

                    strBldr.append(",\n");

                    if (debugAll || debugJsonToStringTop) {
                        System.out.println(
                            "*** ELSE BLOCK *** prevToken = " + prevToken +
                            ", curToken = " + token + ", curFieldName = " +
                            curFieldName + ", stopField = " + stopField +
                            " , fromObjectArray = " + fromObjectArray +
                            " add COMMA and RECURSE ...\n" +
                            strBldr.toString());
                    }
                    return jsonToString(
                          stopField, token, parser, strBldr, fromObjectArray);

                } /* endif (prevToken, inputToken, curFieldName */

            } /* endif (prevToken == END_ARRAY || END_OBJECT) */

            if (prevToken.isScalarValue()) {

                if (token != JsonToken.END_ARRAY &&
                    token != JsonToken.END_OBJECT) {

                    strBldr.append(",\n");
                    return jsonToString(
                          stopField, token, parser, strBldr, fromObjectArray);
                }

                if (stopField != null && stopField.equals(curFieldName)) {

                    if (token == JsonToken.END_ARRAY) {

                        strBldr.append("\n]");

                        if (debugAll || debugJsonToStringTop) {
                            System.out.println(
                                "*** prev SCALAR && STOP-BY-FIELD_NAME " +
                                "[END_ARRAY]: prevToken = " + prevToken +
                                ", curToken = " + token + ", curFieldName = " +
                                curFieldName + ", stopField = " + stopField +
                                " ... terminate with ']' and RETURN string");
                        }
                        return strBldr.toString();
                    }

                    if (token == JsonToken.END_OBJECT) {

                        strBldr.append("\n}");

                        if (debugAll || debugJsonToStringTop) {
                            System.out.println(
                                "*** prev SCALAR && STOP-BY-FIELD_NAME " +
                                "[END_ARRAY]: prevToken = " + prevToken +
                                ", curToken = " + token + ", curFieldName = " +
                                curFieldName + ", stopField = " + stopField +
                                " ... terminate with '}' and RETURN string");
                        }
                        return strBldr.toString();
                    }

                } /* endif (prevToken isScalar && STOP-BY-FIELD) */

            } /* endif (prevToken isScalar) */

        } /* endif (prevToken != null) */

        /* Done with prevToken, process current input token next */

        if (token.isScalarValue()) { /* current token is SCALAR */

            strBldr.append("\"" + curFieldName + "\": " + objectValue(parser));
            return jsonToString(
                       stopField, token, parser, strBldr, fromObjectArray);
        }

        if (JsonToken.START_OBJECT == token) { /* input token is OBJECT */

            if (curFieldName != null) {
                strBldr.append("\"" + curFieldName + "\": {\n");
            } else {
                strBldr.append("{\n");
            }
            return jsonToString(
                       stopField, token, parser, strBldr, fromObjectArray);

        } else if (JsonToken.START_ARRAY == token) { /* input Token is ARRAY */

            if (debugAll || debugJsonToStringArray) {
                System.out.println(
                    "--- START_ARRAY --- prevToken = " + prevToken +
                    ", curToken = " + token + ", curFieldName = " +
                    curFieldName + ", stopField = " + stopField +
                    ", isScalar = " + token.isScalarValue() +
                    ", fromObjectArray = " + fromObjectArray +
                    " ... get NEXT TOKEN");
            }

            token = parser.nextToken();

            if (debugAll || debugJsonToStringArray) {
                System.out.println(
                    "--- START_ARRAY --- nextToken = " + token +
                    ", curFieldName = " + curFieldName + ", stopField = " +
                    stopField + ", isScalar = " + token.isScalarValue() +
                    ", fromObjectArray = " + fromObjectArray);
            }

            if (token == null) {
                System.out.println(
                    "*** WARNING: null next token after START_ARRAY. " +
                    "Invalid json document?");
                return strBldr.toString();
            }

            /* START_ARRAY then START_OBJECT: Handle ARRAY OF OBJECTS */

            if (JsonToken.START_OBJECT == token) {

                if (debugAll || debugJsonToStringArray) {
                    System.out.println("--- START_ARRAY then START_OBJECT: " +
                                       "Handle ARRAY_OF_OBJECTS ---");
                }

                final StringBuilder tmpBldr = new StringBuilder();
                final String curArrayName = curFieldName;

                if (curArrayName != null) {
                    if (!curArrayName.equals(stopField)) {
                        tmpBldr.append("\"" + curFieldName + "\": [\n");
                    }
                }
                tmpBldr.append("{\n");


                while (token != null && JsonToken.END_ARRAY != token) {

                    /*
                     * When at the top of this loop, we know we're handling an
                     * array of objects. We know that we're done with that
                     * array of objects (has already been terminated with ']')
                     * and so should terminate the object containing the
                     * array (with '}') if the following conditions are met:
                     *
                     * 1. The previous token is a FIELD_NAME.
                     * 2. The current field name corresponding to the current
                     *    token is the same as the name of the current array.
                     * 3. The current token is END_OBJECT (meaning we're at
                     *    the end of the object containing the array).
                     */
                    if (JsonToken.FIELD_NAME == prevToken &&
                        JsonToken.END_OBJECT == token &&
                        curFieldName != null &&
                        curFieldName.equals(curArrayName)) {

                        tmpBldr.append("}\n");

                        if (debugAll || debugJsonToStringArray) {
                            System.out.println(
                                "--- TOP ARRAY_OF_OBJECTS LOOP: " +
                                "array element END_OBJECT - " +
                                "terminate with '}' - prevToken = " +
                                prevToken + ", curToken = " + token +
                                ", curFieldName = " + curFieldName +
                                ", stopField = " + stopField +
                                " , fromObjectArray = " + fromObjectArray +
                                " ... loop to continue or end of DOC");
                        }

                        String nextFieldName = curFieldName;
                        while(token != null) {

                            token = parser.nextToken();
                            nextFieldName = parser.getCurrentName();

                            if (debugAll || debugJsonToStringArray) {
                                System.out.println(
                                    "--- TOP ARRAY_OF_OBJECTS LOOP: " +
                                    "array termination inner loop - " +
                                    "nextToken = " + token +
                                    ", nextFieldName = " + nextFieldName);
                            }

                            if (token.isScalarValue()) {

                                tmpBldr.append(",\n");
                                tmpBldr.append("\"" + nextFieldName +
                                               "\": " + objectValue(parser));
                                break;
                            }

                            if (JsonToken.START_OBJECT == token) {

                                tmpBldr.append(",\n");
                                if (nextFieldName != null) {
                                    tmpBldr.append("\"" + nextFieldName +
                                                   "\": { kkkk\n");
                                } else {
                                    tmpBldr.append("{ kkkk\n");
                                }
                                break;
                            }

                            if (JsonToken.START_ARRAY == token) {

                                tmpBldr.append(",\n");
                                if (nextFieldName != null) {
                                    tmpBldr.append("\"" + nextFieldName +
                                                   "\": [ kkkk\n");
                                } else {
                                    tmpBldr.append("[ kkkk\n");
                                }
                                break;
                            }

                            if ((nextFieldName != null &&
				 nextFieldName.equals(stopField)) ||
                                (nextFieldName == null &&
                                 JsonToken.END_OBJECT == token)) {

                                final String finalRetStr =
                                strBldr.append(tmpBldr.toString()).toString();

                                if (debugAll || debugJsonToStringArray) {
                                    System.out.println(
                                        "--- TOP ARRAY_OF_OBJECTS LOOP: " +
                                        "DONE - RETURN FINAL STRING =\n" +
                                        finalRetStr);
                                }
                                return finalRetStr;
                            }


                        } /* end loop */

                        /* More tokens to process. Recurse. */

                        if (debugAll || debugJsonToStringArray) {
                            System.out.println(
                                "--- TOP ARRAY_OF_OBJECTS LOOP: " +
                                "curToken = " + token + ", curFieldName = " +
                                nextFieldName + ", stopField = " + stopField +
                                " , fromObjectArray = " + fromObjectArray +
                                "-  more tokens to process ... RECURSE");
                        }
                        jsonToString(stopField, token, parser, tmpBldr, false);

                    } else { /* Not end of outer object containing objArray */

                        if (debugAll || debugJsonToStringArray) {
                            System.out.println(
                                "--- TOP ARRAY_OF_OBJECTS LOOP: " +
                                "prevToken = " + prevToken + ", curToken = " +
                                token + ", curFieldName = " +
                                curFieldName + ", stopField = " + stopField +
                                " , fromObjectArray = " + fromObjectArray +
                                "-  NOT END OF ARRAY ... RECURSE");
                        }
                        jsonToString(stopField, token, parser, tmpBldr, true);

                    } /* endif (FIELD_NAME then END_OBJECT && array name) */


                    if (debugAll || debugJsonToStringArray) {
                        System.out.println(
                            "--- TOP ARRAY_OF_OBJECTS LOOP: " +
                            "EXIT jsonToString() - prevToken = " +
                            prevToken + ", curToken = " + token +
                            ", curFieldName = " + curFieldName +
                            ", stopField = " + stopField +
                            " , fromObjectArray = " + fromObjectArray +
                            " ... loop to continue or end of DOC");
                    }


                    if (JsonToken.FIELD_NAME == prevToken &&
                        JsonToken.FIELD_NAME == token &&
                        curFieldName != null) {

                        if (debugAll || debugJsonToStringArray) {
                            System.out.println(
                                "--- IN ARRAY_OF_OBJECTS LOOP: " +
                                "FIELD_NAME then FIELD_NAME - " +
                                "curToken = " + token +
                                ", curFieldName = " + curFieldName +
                                " ... get NEXT TOKEN");
                        }

                        token = parser.nextToken();

                        if (debugAll || debugJsonToStringArray) {
                            System.out.println(
                                "--- IN ARRAY_OF_OBJECTS LOOP: " +
                                "FIELD_NAME then FIELD_NAME - " +
                                "nextToken = " + token + ", nextFieldName = " +
                                parser.getCurrentName());
                        }

                        if (JsonToken.END_OBJECT == token) {

                            if (debugAll || debugJsonToStringArray) {
                                 System.out.println(
                                   "--- IN ARRAY_OF_OBJECTS LOOP: " +
                                   "FIELD_NAME then FIELD_NAME - " +
                                   "nextToken = END_OBJECT ... BREAK " +
                                   "out of loop ... subString =\n" +
                                   tmpBldr.toString());
                            }
                            break;

                        } else { /* nextToken NOT END_OBJECT */

                            final String finalRetStr = strBldr.append(
                                tmpBldr.toString()).toString();

                            if (debugAll || debugJsonToStringArray) {
                                 System.out.println(
                                   "--- IN ARRAY_OF_OBJECTS LOOP: " +
                                   "FIELD_NAME then FIELD_NAME - " +
                                   "nextToken = " + token +
                                   "(NOT END_OBJECT) ... DONE - " +
                                   "RETURN FINAL STRING = \n" + finalRetStr);
                            }
                            return finalRetStr;

                        } /* endif (nextToken END_OBJECT or NOT) */

                    } else if (JsonToken.FIELD_NAME == prevToken &&
                               JsonToken.START_OBJECT == token &&
                               curFieldName != null) {

                        if (debugAll || debugJsonToStringArray) {
                             System.out.println(
                               "--- IN ARRAY_OF_OBJECTS LOOP: " +
                               "FIELD_NAME then START_OBJECT - " +
                               "curToken = " + token + ", curFieldName = " +
                               parser.getCurrentName());
                        }

                        token = parser.nextToken();
                        final String nextFieldName = parser.getCurrentName();

                        if (JsonToken.FIELD_NAME == token &&
                            nextFieldName != null) {
                            tmpBldr.append(",\n");

                        } else if (JsonToken.END_OBJECT == token &&
                                   nextFieldName != null) {
                            tmpBldr.append("}\n");
                        }

                        if (debugAll || debugJsonToStringArray) {
                             System.out.println(
                               "--- IN ARRAY_OF_OBJECTS LOOP: " +
                               "FIELD_NAME then START_OBJECT - " +
                               "nextToken = " + token + ", nextFieldName = " +
                               nextFieldName + " ... current subString =\n" +
                               tmpBldr.toString());
                        }

                    } else {

                        token = parser.nextToken();

                        if (debugAll || debugJsonToStringArray) {
                             System.out.println(
                               "--- IN ARRAY_OF_OBJECTS LOOP: " +
                               "*** ELSE *** nextToken = " + token +
                               ", nextFieldName = " +
                               parser.getCurrentName() +
                               " ... current subString =\n" +
                               tmpBldr.toString());
                        }

                    }/* endif FIELD_NAME && FIELD_NAME && fieldName != null */

                    if (debugAll || debugJsonToStringArray) {
                         System.out.println(
                           "--- IN ARRAY_OF_OBJECTS LOOP: " +
                           "END OF LOOP - CONTINUE TO TOP OF LOOP" );
                    }

                } /* end ARRAY_OF_OBJECTS loop */ 

                if (debugAll || debugJsonToStringArray) {
                     System.out.println(
                       "--- OUT ARRAY_OF_OBJECTS LOOP:  " +
                       "current subString = \n" + tmpBldr.toString());
                }

                final String tmpStr = tmpBldr.toString();
                final String retStr = strBldr.append(tmpStr).toString();

                if (debugAll || debugJsonToStringArray) {
                     System.out.println(
                       "--- OUT ARRAY_OF_OBJECTS LOOP:  " +
                       "ENTER jsonToString() - BEGIN FINAL RETURN string ...");
                }

                final String finalRetStr =
                    jsonToString(stopField, token, parser, strBldr, false);

                if (debugAll || debugJsonToStringArray) {
                     System.out.println(
                       "--- OUT ARRAY_OF_OBJECTS LOOP:  EXIT " +
                       "jsonToString() - RETURN FINAL RETURN string = \n" +
                       finalRetStr);
                }
                return finalRetStr;

            } /* endif START_OBJECT after START_ARRAY & ARRAY OF OBJECTS */


            /* -- START_ARRAY then NOT START_OBJECT: ARRAY OF SCALARS -- */

            if (debugAll || debugJsonToStringArray) {
                System.out.println("--- START_ARRAY then SCALAR: " +
                                   "Enter ARRAY_OF_SCALARS loop ---");
            }

            strBldr.append("\"" + curFieldName + "\": [\n");
            while (token != null && JsonToken.END_ARRAY != token) {
                strBldr.append(objectValue(parser));
                token = parser.nextToken();
                if (JsonToken.END_ARRAY == token) {
                    strBldr.append("\n]");
                } else {
                    strBldr.append(",\n");
                }
            }/* end loop: ARRAY_OF_SCALARS */

            return jsonToString(stopField, token, parser, strBldr, false);

        } else if(JsonToken.END_OBJECT == token) {

            strBldr.append("\n}");
            return jsonToString(
                       stopField, token, parser, strBldr, fromObjectArray);

        } else  { /* DEFAULT: all other values of current input token */

            return jsonToString(
                       stopField, token, parser, strBldr, fromObjectArray);

        } /* endif (START_OBJECT else START_ARRAY else END_OBJECT) */
    }

    private Object objectValue(JsonParser parser) throws IOException {
        final JsonToken currentToken = parser.getCurrentToken();
        if (currentToken == JsonToken.VALUE_STRING) {
            return "\"" + parser.getText() + "\"";
        } else if (currentToken == JsonToken.VALUE_NUMBER_INT ||
                currentToken == JsonToken.VALUE_NUMBER_FLOAT) {
            return parser.getNumberValue();
        } else if (currentToken == JsonToken.VALUE_TRUE) {
            return Boolean.TRUE;
        } else if (currentToken == JsonToken.VALUE_FALSE) {
            return Boolean.FALSE;
        } else if (currentToken == JsonToken.VALUE_NULL) {
            return null;
        } else {
            return "\"" + parser.getText() + "\"";
        }
    }

    private int getIntFieldValue(final String objectName,
                                 final String fieldName,
                                 final JsonParser parser) throws IOException {
        int nObjects = 0;
        JsonToken token = parser.nextToken();
        while (token != null) {
            String curFieldName = parser.getCurrentName();
            if (objectName.equals(curFieldName)) {
                token = parser.nextToken();
                while (token != null) {
                    curFieldName = parser.getCurrentName();
                    if (fieldName.equals(curFieldName)) {
                        token = parser.nextToken();
                        if (token != JsonToken.VALUE_NUMBER_INT) {
                            System.out.println("getIntFieldValue: WARNING - " +
                                "for object " + objectName + ", value of " +
                                "field " + fieldName + " is NOT an integer [" +
                                parser.getText() + "]");
                            return nObjects;
                        }
                        nObjects = parser.getNumberValue().intValue();
                        return nObjects;
                    }
                    token = parser.nextToken();
                }
            }
            token = parser.nextToken();
        }
        System.out.println("getIntFieldValue: WARNING - could not find " +
                           "field in given object [object=" + objectName +
                           ", field=" + fieldName + "]");
        return nObjects;
    }
}