# Class JSONParser

java.lang.Object
com.codename1.io.JSONParser

All Implemented Interfaces:
  `JSONParseCallback`

public class JSONParser extends Object implements JSONParseCallback

Fast and dirty parser for JSON content on the web, it essentially returns a `java.util.Map` object containing the object fields mapped to their values. If the value is a nested object a nested `java.util.Map`/`java.util.List` is returned.

The `JSONParser` returns a `Map` which is great if the root object is a `Map` but in some cases its a list of elements (as is the case above). In this case a special case `"root"` element is created to contain the actual list of elements. See the sample below for exact usage of this.

The sample below includes JSON from https://anapioficeandfire.com/ generated by the query http://www.anapioficeandfire.com/api/characters?page=5&pageSize=3:

    // File: JSONParsingSample.java
    Form hi = new Form("JSON Parsing", new BoxLayout(BoxLayout.Y_AXIS));
    JSONParser json = new JSONParser();
    try(Reader r = new InputStreamReader(Display.getInstance().getResourceAsStream(getClass(), "/anapioficeandfire.json"), "UTF-8")) {
        Map data = json.parseJSON(r);
        java.util.List> content = (java.util.List>)data.get("root");
        for(Map obj : content) {
            String url = (String)obj.get("url");
            String name = (String)obj.get("name");
            java.util.List titles = (java.util.List)obj.get("titles");
            if(name == null || name.length() == 0) {
                java.util.List aliases = (java.util.List)obj.get("aliases");
                if(aliases != null && aliases.size() > 0) {
                    name = aliases.get(0);
                }
            }
            MultiButton mb = new MultiButton(name);
            if(titles != null && titles.size() > 0) {
                mb.setTextLine2(titles.get(0));
            }
            mb.addActionListener((e) -> Display.getInstance().execute(url));
            hi.add(mb);
        }
    } catch(IOException err) {
        Log.e(err);
    }
    hi.show();

    // File: anapioficeandfire.json
    [
      {
        "url": "http://www.anapioficeandfire.com/api/characters/13",
        "name": "Chayle",
        "culture": "",
        "born": "",
        "died": "In 299 AC, at Winterfell",
        "titles": [
          "Septon"
        ],
        "aliases": [],
        "father": "",
        "mother": "",
        "spouse": "",
        "allegiances": [],
        "books": [
          "http://www.anapioficeandfire.com/api/books/1",
          "http://www.anapioficeandfire.com/api/books/2",
          "http://www.anapioficeandfire.com/api/books/3"
        ],
        "povBooks": [],
        "tvSeries": [],
        "playedBy": []
      },
      {
        "url": "http://www.anapioficeandfire.com/api/characters/14",
        "name": "Gillam",
        "culture": "",
        "born": "",
        "died": "",
        "titles": [
          "Brother"
        ],
        "aliases": [],
        "father": "",
        "mother": "",
        "spouse": "",
        "allegiances": [],
        "books": [
          "http://www.anapioficeandfire.com/api/books/5"
        ],
        "povBooks": [],
        "tvSeries": [],
        "playedBy": []
      },
      {
        "url": "http://www.anapioficeandfire.com/api/characters/15",
        "name": "High Septon",
        "culture": "",
        "born": "",
        "died": "",
        "titles": [
          "High Septon",
          "His High Holiness",
          "Father of the Faithful",
          "Voice of the Seven on Earth"
        ],
        "aliases": [
          "The High Sparrow"
        ],
        "father": "",
        "mother": "",
        "spouse": "",
        "allegiances": [],
        "books": [
          "http://www.anapioficeandfire.com/api/books/5",
          "http://www.anapioficeandfire.com/api/books/8"
        ],
        "povBooks": [],
        "tvSeries": [
          "Season 5"
        ],
        "playedBy": [
          "Jonathan Pryce"
        ]
      }
    ]

The sample code below fetches a page of data from the nestoria housing listing API as a list of Map elements. You can see instructions on how to display the data in the `com.codename1.components.InfiniteScrollAdapter` class.

    int pageNumber = 1;
    java.util.List> fetchPropertyData(String text) {
        try {
            ConnectionRequest r = new ConnectionRequest();
            r.setPost(false);
            r.setUrl("http://api.nestoria.co.uk/api");
            r.addArgument("pretty", "0");
            r.addArgument("action", "search_listings");
            r.addArgument("encoding", "json");
            r.addArgument("listing_type", "buy");
            r.addArgument("page", "" + pageNumber);
            pageNumber++;
            r.addArgument("country", "uk");
            r.addArgument("place_name", text);
            NetworkManager.getInstance().addToQueueAndWait(r);
            Map result = new JSONParser().parseJSON(new InputStreamReader(new ByteArrayInputStream(r.getResponseData()), "UTF-8"));
            Map response = (Map)result.get("response");
            return (java.util.List>)response.get("listings");
        } catch(Exception err) {
            Log.e(err);
            return null;
        }
    }

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `JSONParser()`

- ## Method Summary

  Modifier and Type
  Method
  Description
  `void`
  `booleanToken(boolean tok)`
  Submits a boolean token from the JSON data
  `void`
  `endArray(String arrayName)`
  Indicates that the parser ran into an ending bracket event ]
  `void`
  `endBlock(String blockName)`
  Indicates that the parser ran into an ending bracket event }
  `boolean`
  `isAlive()`
  This method indicates to the Parser if this Callback is still alive
  `static boolean`
  `isIncludeNulls()`
  Checks the default setting for `#isIncludeNullsInstance()`.
  `boolean`
  `isIncludeNullsInstance()`
  Checks whether this parser will include null values in parsed content.
  `boolean`
  `isStrict()`
  Checks if this JSON parser is in strict mode.
  `static boolean`
  `isUseBoolean()`
  Global default setting for `#isUseBooleanInstance()`.
  `boolean`
  `isUseBooleanInstance()`
  Indicates that the parser will generate Boolean objects and not just Strings for boolean values
  `static boolean`
  `isUseLongs()`
  Checks whether JSONParser instances will use longs to represent numeric values by default.
  `boolean`
  `isUseLongsInstance()`
  Checks to see if this parser generates long objects and not just doubles for numeric values.
  `void`
  `keyValue(String key, String value)`
  This method is called when a string key/value pair is detected within the json it is essentially redundant when following string/numeric token.
  `void`
  `longToken(long tok)`
  Submits a numeric token from the JSON data
  `static String`
  `mapToJson(Map<String,?> map)`
  Static method to convert the given `java.util.Map` to a valid JSON representation.
  `void`
  `numericToken(double tok)`
  Submits a numeric token from the JSON data
  `Hashtable<String,Object>`
  `parse(Reader i)`
  Parses the given input stream into this object and returns the parse tree
  `static void`
  `parse(Reader i, JSONParseCallback callback)`
  Static method! Parses the given input stream and fires the data into the given callback.
  `Map<String,Object>`
  `parseJSON(Reader i)`
  Parses the given input stream into this object and returns the parse tree.
  `static void`
  `setIncludeNulls(boolean aIncludeNullsDefault)`
  Sets the global default settings for `#isIncludeNullsInstance()`.
  `void`
  `setIncludeNullsInstance(boolean include)`
  Sets whether to include null values in parsed content.
  `void`
  `setStrict(boolean strict)`
  Enables or disables strict mode.
  `static void`
  `setUseBoolean(boolean aUseBooleanDefault)`
  Sets the global default value for `#isUseBooleanInstance()`
  `void`
  `setUseBooleanInstance(boolean useBoolean)`
  Indicates that the parser will generate Boolean objects and not just Strings for boolean values
  `static void`
  `setUseLongs(boolean aUseLongsDefault)`
  Indicates that the parser will generate long objects and not just doubles for numeric values.
  `void`
  `setUseLongsInstance(boolean longs)`
  Sets the current JSONParser instance to use longs instead of doubles for numeric values.
  `void`
  `startArray(String arrayName)`
  Indicates that the parser ran into an opening bracket event [
  `void`
  `startBlock(String blockName)`
  Indicates that the parser ran into an opening bracket event {
  `void`
  `stringToken(String tok)`
  Submits a token from the JSON data as a java string, this token is always a string value

  ### Methods inherited from class Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Constructor Details

  - ### JSONParser

    public JSONParser()

- ## Method Details

  - ### isUseLongs

    public static boolean isUseLongs()

    Checks whether JSONParser instances will use longs to represent numeric values by default. This is just a global default setting. You should use `#isUseLongsInstance()` to check the status for a particular JSONParser object.

    ###### Returns

    the useLongsDefault

    ###### Deprecated

    Use `#isUseLongsInstance()` to check whether the current JSONParser uses longs.

  - ### setUseLongs

    public static void setUseLongs(boolean aUseLongsDefault)

    Indicates that the parser will generate long objects and not just doubles for numeric values.

    Warning: This method will affect ALL JSONParser instances in the application. Prefer to use `#setUseLongsInstance(boolean)` to only affect the behaviour of the particular JSONParser instance.

    ###### Parameters

    - `aUseLongsDefault`: the useLongsDefault to set

    ###### Deprecated

    Use `#setUseLongsInstance(boolean)`

  - ### isIncludeNulls

    public static boolean isIncludeNulls()

    Checks the default setting for `#isIncludeNullsInstance()`.

    ###### Returns

    the includeNullsDefault The global default setting for `#isIncludeNullsInstance()`.

    ###### Deprecated

    Use `#isIncludeNullsInstance()` instead.

  - ### setIncludeNulls

    public static void setIncludeNulls(boolean aIncludeNullsDefault)

    Sets the global default settings for `#isIncludeNullsInstance()`.

    ###### Parameters

    - `aIncludeNullsDefault`: the includeNullsDefault to set

    ###### Deprecated

    Use `#setIncludeNullsInstance(boolean)` instead.

  - ### isUseBoolean

    public static boolean isUseBoolean()

    Global default setting for `#isUseBooleanInstance()`.

    ###### Returns

    the useBooleanDefault

    ###### Deprecated

    Use `#isUseBooleanInstance()` instead.

  - ### setUseBoolean

    public static void setUseBoolean(boolean aUseBooleanDefault)

    Sets the global default value for `#isUseBooleanInstance()`

    ###### Parameters

    - `aUseBooleanDefault`: the useBooleanDefault to set

    ###### Deprecated

    Use `#setUseBooleanInstance(boolean)` instead.

  - ### parse

    public static void parse(Reader i, JSONParseCallback callback) throws IOException

    Static method! Parses the given input stream and fires the data into the given callback.

    ###### Parameters

    - `i`: the reader

    - `callback`: a generic callback to receive the parse events

    ###### Throws

    - `IOException`: if thrown by the stream
    Throws:
      `IOException`

  - ### mapToJson

    public static String mapToJson(Map<String,?> map)

    Static method to convert the given `java.util.Map` to a valid JSON representation. The values allowed types are: `java.lang.Number`, `java.lang.String`, `java.lang.Boolean`, `java.util.List`, `java.util.Map` or null.

    Limited whitespace is inserted be make the resulting JSON string more readable.

    Simple example of usage:

        `Map person = new LinkedHashMap<>();
        person.put("firstName", "Paco");
        person.put("lastName", "Bellz");
        person.put("isAlive", true);
        person.put("age", 35);
        person.put("weight (kg)", 70.7);

        Log.p("--- mapToJson() test");
        Log.p("\n" + mapToJson(person));`

    The output will be:

        `{
         "firstName": "Paco",
         "lastName": "Bellz",
         "isAlive": true,
         "age": 35,
         "weight (kg)": 70.7`
        }

    More complex example of usage:

        `Map phoneNumber1 = new LinkedHashMap<>();
        phoneNumber1.put("home", "212 555-1234");
        Map phoneNumber2 = new LinkedHashMap<>();
        phoneNumber2.put("office", "646 555-4567");
        Map phoneNumber3 = new LinkedHashMap<>();
        phoneNumber3.put("mobile", "123 456-7890");
        Map phoneNumber4 = new LinkedHashMap<>();
        phoneNumber4.put("mobile", "06124578965");
        ArrayList phoneNumbers = new ArrayList();
        ArrayList phoneNumbers2 = new ArrayList();
        phoneNumbers.add(phoneNumber1);
        phoneNumbers.add(phoneNumber2);
        phoneNumbers.add(phoneNumber3);
        phoneNumbers2.add(phoneNumber4);
        Map address1 = new LinkedHashMap<>();
        address1.put("streetAddress", "53, London Street");
        address1.put("city", "Paris");
        address1.put("state", "FR");
        address1.put("postalCode", "54856");
        Map address2 = new LinkedHashMap<>();
        address2.put("streetAddress", "21 2nd Street");
        address2.put("city", "New York");
        address2.put("state", "NY");
        address2.put("postalCode", "10021-3100");
        Map secondPerson = new LinkedHashMap<>();
        secondPerson.put("firstName", "Gioia");
        secondPerson.put("lastName", "Mia");
        secondPerson.put("isAlive", true);
        secondPerson.put("age", 34);
        secondPerson.put("weight (kg)", 60.2);
        secondPerson.put("address", address2);
        address2.put("phoneNumbers", phoneNumbers2);
        Map firstPerson = new LinkedHashMap<>();
        firstPerson.put("firstName", "Paco");
        firstPerson.put("lastName", "Bellz");
        firstPerson.put("isAlive", true);
        firstPerson.put("age", 35);
        firstPerson.put("weight (kg)", 70.7);
        firstPerson.put("address", address1);
        firstPerson.put("partner", secondPerson);
        firstPerson.put("children", new ArrayList());
        firstPerson.put("extraInfo", null);
        firstPerson.put("phoneNumbers", phoneNumbers);
        List friends = new ArrayList();
        friends.add("Paul");
        friends.add("Karl");
        friends.add("Mary");
        firstPerson.put("onVacation", false);
        firstPerson.put("friends", friends);

        Log.p("--- mapToJson() test");
        Log.p("\n" + mapToJson(firstPerson));`

    The output will be:

        `{
         "firstName": "Paco",
         "lastName": "Bellz",
         "isAlive": true,
         "age": 35,
         "weight (kg)": 70.7,
         "address": {
           "streetAddress": "53, London Street",
           "city": "Paris",
           "state": "FR",
           "postalCode": "54856"`,
         "partner": {
           "firstName": "Gioia",
           "lastName": "Mia",
           "isAlive": true,
           "age": 34,
           "weight (kg)": 60.2,
           "address": {
             "streetAddress": "21 2nd Street",
             "city": "New York",
             "state": "NY",
             "postalCode": "10021-3100",
             "phoneNumbers": [{"mobile": "06124578965"}]
           }
         },
         "children": [],
         "extraInfo": null,
         "phoneNumbers": [
           {"home": "212 555-1234"},
           {"office": "646 555-4567"},
           {"mobile": "123 456-7890"}
         ],
         "onVacation": false,
         "friends": [
           "Paul",
           "Karl",
           "Mary"
         ]
        }
        }

    ###### Parameters

    - `map`: The map to be converted to a JSON string

    ###### Returns

    The JSON string

  - ### isUseLongsInstance

    public boolean isUseLongsInstance()
    Checks to see if this parser generates long objects and not just doubles for numeric values.

  - ### setUseLongsInstance

    public void setUseLongsInstance(boolean longs)

    Sets the current JSONParser instance to use longs instead of doubles for numeric values. Prefer this to the static `#setUseLongs(boolean)` so that it doesn't disrupt libraries that may depend on JSONParser.

    ###### Parameters

    - `longs`: True to use

    ###### Since

    7.0

  - ### isIncludeNullsInstance

    public boolean isIncludeNullsInstance()

    Checks whether this parser will include null values in parsed content.

    ###### Returns

    True if null values are included in parsed content.

    ###### Since

    7.0

  - ### setIncludeNullsInstance

    public void setIncludeNullsInstance(boolean include)

    Sets whether to include null values in parsed content.

    ###### Parameters

    - `include`: True to include null values in parsed content.

    ###### Since

    7.0

  - ### isUseBooleanInstance

    public boolean isUseBooleanInstance()

    Indicates that the parser will generate Boolean objects and not just Strings for boolean values

    ###### Returns

    True if the parser will generate Boolean objects and not just Strings for boolean values.

    ###### Since

    7.0

  - ### setUseBooleanInstance

    public void setUseBooleanInstance(boolean useBoolean)

    Indicates that the parser will generate Boolean objects and not just Strings for boolean values

    ###### Parameters

    - `useBoolean`: True to generate Boolean objects and not just Strings for boolean values.

    ###### Since

    7.0

  - ### parseJSON

    public Map<String,Object> parseJSON(Reader i) throws IOException

    Parses the given input stream into this object and returns the parse tree.

    The `JSONParser` returns a `Map` which is great if the root object is a `Map` but in some cases its a list of elements (as is the case above). In this case a special case `"root"` element is created to contain the actual list of elements. See the sample below for exact usage of this.

    The sample below includes JSON from https://anapioficeandfire.com/ generated by the query http://www.anapioficeandfire.com/api/characters?page=5&pageSize=3:

        // File: JSONParsingSample.java
        Form hi = new Form("JSON Parsing", new BoxLayout(BoxLayout.Y_AXIS));
        JSONParser json = new JSONParser();
        try(Reader r = new InputStreamReader(Display.getInstance().getResourceAsStream(getClass(), "/anapioficeandfire.json"), "UTF-8")) {
            Map data = json.parseJSON(r);
            java.util.List> content = (java.util.List>)data.get("root");
            for(Map obj : content) {
                String url = (String)obj.get("url");
                String name = (String)obj.get("name");
                java.util.List titles = (java.util.List)obj.get("titles");
                if(name == null || name.length() == 0) {
                    java.util.List aliases = (java.util.List)obj.get("aliases");
                    if(aliases != null && aliases.size() > 0) {
                        name = aliases.get(0);
                    }
                }
                MultiButton mb = new MultiButton(name);
                if(titles != null && titles.size() > 0) {
                    mb.setTextLine2(titles.get(0));
                }
                mb.addActionListener((e) -> Display.getInstance().execute(url));
                hi.add(mb);
            }
        } catch(IOException err) {
            Log.e(err);
        }
        hi.show();

        // File: anapioficeandfire.json
        [
          {
            "url": "http://www.anapioficeandfire.com/api/characters/13",
            "name": "Chayle",
            "culture": "",
            "born": "",
            "died": "In 299 AC, at Winterfell",
            "titles": [
              "Septon"
            ],
            "aliases": [],
            "father": "",
            "mother": "",
            "spouse": "",
            "allegiances": [],
            "books": [
              "http://www.anapioficeandfire.com/api/books/1",
              "http://www.anapioficeandfire.com/api/books/2",
              "http://www.anapioficeandfire.com/api/books/3"
            ],
            "povBooks": [],
            "tvSeries": [],
            "playedBy": []
          },
          {
            "url": "http://www.anapioficeandfire.com/api/characters/14",
            "name": "Gillam",
            "culture": "",
            "born": "",
            "died": "",
            "titles": [
              "Brother"
            ],
            "aliases": [],
            "father": "",
            "mother": "",
            "spouse": "",
            "allegiances": [],
            "books": [
              "http://www.anapioficeandfire.com/api/books/5"
            ],
            "povBooks": [],
            "tvSeries": [],
            "playedBy": []
          },
          {
            "url": "http://www.anapioficeandfire.com/api/characters/15",
            "name": "High Septon",
            "culture": "",
            "born": "",
            "died": "",
            "titles": [
              "High Septon",
              "His High Holiness",
              "Father of the Faithful",
              "Voice of the Seven on Earth"
            ],
            "aliases": [
              "The High Sparrow"
            ],
            "father": "",
            "mother": "",
            "spouse": "",
            "allegiances": [],
            "books": [
              "http://www.anapioficeandfire.com/api/books/5",
              "http://www.anapioficeandfire.com/api/books/8"
            ],
            "povBooks": [],
            "tvSeries": [
              "Season 5"
            ],
            "playedBy": [
              "Jonathan Pryce"
            ]
          }
        ]

    ###### Parameters

    - `i`: the reader

    ###### Returns

    the parse tree as a hashtable

    ###### Throws

    - `IOException`: if thrown by the stream
    Throws:
      `IOException`

  - ### parse

    public Hashtable<String,Object> parse(Reader i) throws IOException

    Parses the given input stream into this object and returns the parse tree

    ###### Parameters

    - `i`: the reader

    ###### Returns

    the parse tree as a hashtable

    ###### Throws

    - `IOException`: if thrown by the stream

    ###### Deprecated

    use the new parseJSON instead

    Throws:
      `IOException`

  - ### startBlock

    public void startBlock(String blockName)
    Indicates that the parser ran into an opening bracket event {
    Specified by:
      `startBlock` in interface `JSONParseCallback`

  - ### endBlock

    public void endBlock(String blockName)
    Indicates that the parser ran into an ending bracket event }
    Specified by:
      `endBlock` in interface `JSONParseCallback`

  - ### isStrict

    public boolean isStrict()

    Checks if this JSON parser is in strict mode. When in strict mode, which is the default, only valid JSON will be parsed. If strict mode is disabled, then it will attempt to sanitize the JSON input before parsing. This can be handy if you want to parse structures that are almost JSON. E.g. non-quoted keys, single-quotes on strings, unquoted strings. Etc.

    ###### Returns

    True if strict mode is enabled.

    ###### Since

    7.0

    ###### See also

    - #setStrict(boolean)

  - ### setStrict

    public void setStrict(boolean strict)

    Enables or disables strict mode. Default is true.

    When strict mode is disabled, the parser will sanitize the JSON input before parsing. The effect is that it will be able to parse input that is json-ish.

    Non-Strict Input The sanitizer takes JSON like content, and interprets it as JS eval would. Specifically, it deals with these non-standard constructs.

    - `'...'` Single quoted strings are converted to JSON strings.

    - `\xAB` Hex escapes are converted to JSON unicode escapes.

    - `\012` Octal escapes are converted to JSON unicode escapes.

    - `0xAB` Hex integer literals are converted to JSON decimal numbers.

    - `012` Octal integer literals are converted to JSON decimal numbers.

    - `+.5` Decimal numbers are coerced to JSON's stricter format.

    - `[0,,2]` Elisions in arrays are filled with `null`.

    - `[1,2,3,]` Trailing commas are removed.

    - `{foo:"bar"}` Unquoted property names are quoted.

    - `//comments` JS style line and block comments are removed.

    - `(...)` Grouping parentheses are removed.

    ###### Parameters

    - `strict`: True to enable strict mode, false to disable it.

    ###### See also

    - #isStrict()

  - ### startArray

    public void startArray(String arrayName)
    Indicates that the parser ran into an opening bracket event [
    Specified by:
      `startArray` in interface `JSONParseCallback`

  - ### endArray

    public void endArray(String arrayName)
    Indicates that the parser ran into an ending bracket event ]
    Specified by:
      `endArray` in interface `JSONParseCallback`

  - ### stringToken

    public void stringToken(String tok)
    Submits a token from the JSON data as a java string, this token is always a string value
    Specified by:
      `stringToken` in interface `JSONParseCallback`

  - ### numericToken

    public void numericToken(double tok)

    Submits a numeric token from the JSON data

    ###### Parameters

    - `tok`: the token value
    Specified by:
      `numericToken` in interface `JSONParseCallback`

  - ### longToken

    public void longToken(long tok)
    Submits a numeric token from the JSON data
    Specified by:
      `longToken` in interface `JSONParseCallback`

  - ### booleanToken

    public void booleanToken(boolean tok)

    Submits a boolean token from the JSON data

    ###### Parameters

    - `tok`: the token value
    Specified by:
      `booleanToken` in interface `JSONParseCallback`

  - ### keyValue

    public void keyValue(String key, String value)

    This method is called when a string key/value pair is detected within the json it is essentially redundant when following string/numeric token.

    ###### Parameters

    - `key`: the key

    - `value`: a string value

    Specified by:
      `keyValue` in interface `JSONParseCallback`

  - ### isAlive

    public boolean isAlive()

    This method indicates to the Parser if this Callback is still alive

    ###### Returns

    Specified by:
      `isAlive` in interface `JSONParseCallback`
    Returns:
      true if the Callback is still interested to get the JSON parse events from the JSONParser