public class JSONParser

  1. Object
  2. JSONParser

ImplementsJSONParseCallback

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<Map<String, Object>> content = (java.util.List<Map<String, Object>>)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<Map<String, Object>> 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<Map<String, Object>>)response.get("listings");
    } catch(Exception err) {
        Log.e(err);
        return null;
    }
}

Nested types

class JSONParser.RawJsonWrapper that lets a caller embed a pre-built JSON fragment into a Map/List tree being serialized by toJson(Object).

Constructors

public JSONParser()

Methods

public static boolean isUseLongs()Deprecated Checks whether JSONParser instances will use longs to represent numeric values by default.
public static void setUseLongs(boolean aUseLongsDefault)Deprecated Indicates that the parser will generate long objects and not just doubles for numeric values.
public static boolean isIncludeNulls()Deprecated Checks the default setting for #isIncludeNullsInstance().
public static void setIncludeNulls(boolean aIncludeNullsDefault)Deprecated Sets the global default settings for #isIncludeNullsInstance().
public static boolean isUseBoolean()Deprecated Global default setting for #isUseBooleanInstance().
public static void setUseBoolean(boolean aUseBooleanDefault)Deprecated Sets the global default value for #isUseBooleanInstance()
public static void parse(Reader i, JSONParseCallback callback) throws IOExceptionStatic method! Parses the given input stream and fires the data into the given callback.
public static String mapToJson(Map<String, ?> map)Static method to convert the given java.util.Map to a valid JSON representation.
public static Map<String, Object> parseJSON(byte[] bytes) throws IOExceptionConvenience: parse a JSON object from a UTF-8 byte array.
public static Map<String, Object> parseJSON(String json) throws IOExceptionConvenience: parse a JSON object from an in-memory String.
public static JSONParser.RawJson rawJson(String json)Creates a RawJson marker.
public static String toJson(Object value)Serializes a Map/List/String/Number/Boolean/null / RawJson tree to JSON.
public static Map<String, Object> asMap(Object o)Cast helper for the Hashtable/Vector-style return values from parseJSON(java.io.Reader).
public static List<Object> asList(Object o)Cast helper for list-typed values pulled out of a parsed JSON tree.
public static String getString(Map m, String key)Retrieves a String field from a parsed JSON object.
public static int getInt(Map m, String key, int defaultValue)Retrieves an int field from a parsed JSON object, with a fallback when the key is missing, the map is null, or the value cannot be parsed as an integer.
public static double getDouble(Map m, String key, double defaultValue)Retrieves a double field from a parsed JSON object, with a fallback when the key is missing, the map is null, or the value cannot be parsed as a number.
public boolean isUseLongsInstance()Checks to see if this parser generates long objects and not just doubles for numeric values.
public void setUseLongsInstance(boolean longs)Sets the current JSONParser instance to use longs instead of doubles for numeric values.
public boolean isIncludeNullsInstance()Checks whether this parser will include null values in parsed content.
public void setIncludeNullsInstance(boolean include)Sets whether to include null values in parsed content.
public boolean isUseBooleanInstance()Indicates that the parser will generate Boolean objects and not just Strings for boolean values
public void setUseBooleanInstance(boolean useBoolean)Indicates that the parser will generate Boolean objects and not just Strings for boolean values
public Map<String, Object> parseJSON(Reader i) throws IOExceptionParses the given input stream into this object and returns the parse tree.
public Hashtable<String, Object> parse(Reader i) throws IOExceptionDeprecated Parses the given input stream into this object and returns the parse tree
public void startBlock(String blockName)Indicates that the parser ran into an opening bracket event {
public void endBlock(String blockName)Indicates that the parser ran into an ending bracket event }
public boolean isStrict()Checks if this JSON parser is in strict mode.
public void setStrict(boolean strict)Enables or disables strict mode.
public void startArray(String arrayName)Indicates that the parser ran into an opening bracket event [
public void endArray(String arrayName)Indicates that the parser ran into an ending bracket event ]
public void stringToken(String tok)Submits a token from the JSON data as a java string, this token is always a string value
public void numericToken(double tok)Submits a numeric token from the JSON data
public void longToken(long tok)Submits a numeric token from the JSON data
public void booleanToken(boolean tok)Submits a boolean token from the JSON data
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.
public boolean isAlive()This method indicates to the Parser if this Callback is still alive

Inherited methods

Constructor details

JSONParser

public JSONParser()

Method details

isUseLongs

public static boolean isUseLongs()
Deprecated. Use #isUseLongsInstance() to check whether the current JSONParser uses longs.
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

setUseLongs

public static void setUseLongs(boolean aUseLongsDefault)
Deprecated. Use #setUseLongsInstance(boolean)

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 boolean
the useLongsDefault to set

isIncludeNulls

public static boolean isIncludeNulls()
Deprecated. Use #isIncludeNullsInstance() instead.
Checks the default setting for #isIncludeNullsInstance().

Returns

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

setIncludeNulls

public static void setIncludeNulls(boolean aIncludeNullsDefault)
Deprecated. Use #setIncludeNullsInstance(boolean) instead.
Sets the global default settings for #isIncludeNullsInstance().

Parameters

aIncludeNullsDefault boolean
the includeNullsDefault to set

isUseBoolean

public static boolean isUseBoolean()
Deprecated. Use #isUseBooleanInstance() instead.
Global default setting for #isUseBooleanInstance().

Returns

the useBooleanDefault

setUseBoolean

public static void setUseBoolean(boolean aUseBooleanDefault)
Deprecated. Use #setUseBooleanInstance(boolean) instead.
Sets the global default value for #isUseBooleanInstance()

Parameters

aUseBooleanDefault boolean
the useBooleanDefault to set

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 Reader
the reader
callback JSONParseCallback
a generic callback to receive the parse events

Throws

IOException
if thrown by the stream

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 Map<String, ?>
The map to be converted to a JSON string

Returns

The JSON string

parseJSON

public static Map<String, Object> parseJSON(byte[] bytes) throws IOException
Convenience: parse a JSON object from a UTF-8 byte array. The parseJSON(Reader) overload is the canonical entry point but callers that already have bytes in hand don’t need to wire up a ByteArrayInputStream + InputStreamReader themselves.

parseJSON

public static Map<String, Object> parseJSON(String json) throws IOException
Convenience: parse a JSON object from an in-memory String.

rawJson

public static JSONParser.RawJson rawJson(String json)
Creates a RawJson marker. See the class javadoc for usage.

toJson

public static String toJson(Object value)

Serializes a Map/List/String/Number/Boolean/null / RawJson tree to JSON. Differs from mapToJson(Map) in three ways: it takes any root type (not just Map); it omits null-valued Map entries (rather than emitting "key":null, which many REST APIs reject); and it understands the RawJson sentinel so callers can splice pre-built fragments into the tree without re-escaping them.

Map keys must be String. Floats and doubles serialize using Double.toString (no scientific notation for typical values); integral types (Integer, Long, etc.) serialize as integers.

asMap

public static Map<String, Object> asMap(Object o)
Cast helper for the Hashtable/Vector-style return values from parseJSON(java.io.Reader). Returns null when the input is null; callers wishing to walk a JSON object tree without sprinkling (Map) casts everywhere can pass each nested value through this.

asList

public static List<Object> asList(Object o)
Cast helper for list-typed values pulled out of a parsed JSON tree. Same null behavior as asMap.

getString

public static String getString(Map m, String key)
Retrieves a String field from a parsed JSON object. Returns null if the key is missing or the map is null; calls toString() on non-String values for resilience.

getInt

public static int getInt(Map m, String key, int defaultValue)
Retrieves an int field from a parsed JSON object, with a fallback when the key is missing, the map is null, or the value cannot be parsed as an integer.

getDouble

public static double getDouble(Map m, String key, double defaultValue)
Retrieves a double field from a parsed JSON object, with a fallback when the key is missing, the map is null, or the value cannot be parsed as a number.

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 boolean
True to use

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.

setIncludeNullsInstance

public void setIncludeNullsInstance(boolean include)
Sets whether to include null values in parsed content.

Parameters

include boolean
True to include null values in parsed content.

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.

setUseBooleanInstance

public void setUseBooleanInstance(boolean useBoolean)
Indicates that the parser will generate Boolean objects and not just Strings for boolean values

Parameters

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

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<Map<String, Object>> content = (java.util.List<Map<String, Object>>)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 Reader
the reader

Returns

the parse tree as a hashtable

Throws

IOException
if thrown by the stream

parse

public Hashtable<String, Object> parse(Reader i) throws IOException
Deprecated. use the new parseJSON instead
Parses the given input stream into this object and returns the parse tree

Parameters

i Reader
the reader

Returns

the parse tree as a hashtable

Throws

IOException
if thrown by the stream

startBlock

public void startBlock(String blockName)
Indicates that the parser ran into an opening bracket event {

endBlock

public void endBlock(String blockName)
Indicates that the parser ran into an ending bracket event }

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.

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 boolean
True to enable strict mode, false to disable it.

See also

startArray

public void startArray(String arrayName)
Indicates that the parser ran into an opening bracket event [

endArray

public void endArray(String arrayName)
Indicates that the parser ran into an ending bracket event ]

stringToken

public void stringToken(String tok)
Submits a token from the JSON data as a java string, this token is always a string value

numericToken

public void numericToken(double tok)
Submits a numeric token from the JSON data

Parameters

tok double
the token value

longToken

public void longToken(long tok)
Submits a numeric token from the JSON data

booleanToken

public void booleanToken(boolean tok)
Submits a boolean token from the JSON data

Parameters

tok boolean
the token value

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 String
the key
value String
a string value

isAlive

public boolean isAlive()
This method indicates to the Parser if this Callback is still alive

Returns

true if the Callback is still interested to get the JSON parse events from the JSONParser