JSON

Goal

Concepts

Library

Dependencies

Lesson

For well over a decade, the most popular text format for storing arbitrarily structured information has been the Extensible Markup Language (XML). Recently more and more Internet applications are switching to a newer format named JavaScript Object Notation (JSON). Taking some of the syntax of JavaScript for declaring values, JSON results in a leaner and simpler format that it easier to easier to generate, parse, and be read by humans.

JavaScript and Its Object Notation

The JavaScript language was created in 1995 and was originally intended for scripting in browsers. It is now standardized as ECMAScript. Although its common name contains the word Java, it has little relation to the Java language other than its syntax (such as its use of the curly brace { and } characters). Unlike Java, JavaScript waits until a value is used to decide what type it is.

Douglas Crockford took the declarative syntax (that is, without any procedural logic) of the basic JavaScript types and defined them as a storage format, naming it the JavaScript Object Notation. Because JSON data is essentially the declarative part of JavaScript , it can be evaluated by a JavaScript interpreter as if it were JavaScript code. This made it easy to be parsed in browsers when and helped JSON become popular.

JSON is defined both by RFC 7159 and by ECMA-404 from Ecma International. JSON data contains one of JavaScript's value types, but that single value may recursively contain other values.

JSON value
JSON value

Numbers

JSON number
JSON number

JavaScript numbers as used by JSON is similar to basic Java number literals, with optional numbers after a decimal point. Hexadecimal and octal are not allowed. Here are some examples.

Strings

Strings in JavaScript are also very similar to string literals, including the use of the backslash \ character for escaping. Here are some examples:

JSON string
JSON string

Other Values

JavaScript and JSON also allow these special values. As with all JavaScript values, you don't have to indicate their type.

Arrays

Representing an array in JavaScript syntax is simpler than in Java. Simply place values inside bracket [ ] characters, separated by commas. The types can be mixed, as they are not specified at declaration time in JavaScript. Here are some examples:

JSON array
JSON array

Objects

JSON object
JSON object

The central construct for encapsulating data in JavaScript is an "object". In JavaScript an object is essentially a collection of name/value associations; it is technically referred to as an associative array. It conceptually performs the same function as the Map<K, V> interface.

The "keys" of a JavaScript object are strings; the values can be any values, including other objects. Each named key and its value are separated by a colon : character, while each name/value pair is separated by the comma , character. Here are some examples of objects.

Parsing JSON Using Jackson

There are several libraries available for parsing JSON using Java. Besides one of the early implementations org.json, two of the most popular packages are gson (from Google) and Jackson. In this lesson we will use Jackson, which is well established and is widely used as a plugin in certain Internet-based frameworks.

Jackson offers three different approaches to choose from when parsing JSON:

tree model
Parses the entire JSON document and provides it as a tree structure.
streaming API
Provides events to your code as sections of the JSON document is parsed.
data binding
Automatically converts objects to and from JSON based on some mapping.

Tree Model

In future lessons you'll learn how to use Jackson data binding in Internet-based services. For now you will use the tree model. Although it is not as memory efficient as the streaming API, it is simpler in that it mostly closely resembles the JSON structure as viewed in a formatted text file.

To parse JSON into a tree using Jackson, create a com.fasterxml.jackson.databind.ObjectMapper instance. The ObjectMapper.readTree(Reader r) method will return a tree structure with the root node an instance of com.fasterxml.jackson.databind.JsonNode representing the main JSON object. The JsonNode provides access to the entire tree of JSON values, each represented as another JsonNode. Because JSON allows many different types of values, you'll need to check the type of the node's type using JsonNode.getNodeType(). The returned com.fasterxml.jackson.databind.node.JsonNodeType enum instance indicates whether the node is a JsonNodeType.OBJECT, a JsonNodeType.ARRAY, or one of the other enum instances representing JSON value types.

Once you know the value type the node represents, you can retrieve a primitive value using a method such as JsonNode.booleanValue() for type JsonNodeType.BOOLEAN; or JsonNode.textValue() for JsonNodeType.STRING. You can access array elements using JsonNode.get(int index) or JsonNode.elements(); and access object values associated with keys using JsonNode.get(String fieldName).

There are many other methods for accessing JSON data from the parsed tree, and you should read the API documentation before using Jackson and keep it handy as a reference later. The following example code shows how to parse a sample JSON document from a string using ObjectMapper.readTree(String content):

Parsing JSON text using the Jackson tree model.
final ObjectMapper mapper = new ObjectMapper();
final JsonNode rootNode = mapper.readTree("{\"foo\":\"bar\"}");
if(rootNode.isObject()) {
  final JsonNode fooValueNode = rootNode.get("foo");
  if(fooValueNode!=null && fooValueNode.isTextual()) {
    final String string = fooValueNode.textValue(); //retrieves "bar"
  }
}

Review

Gotchas

In the Real World

Self Evaluation

Task

Improve the Booker ISBN lookup so that instead of printing out the literal response from the Google Books API lookup request, it parses the JSON response using Jackson and creates a Book instance and stores it in the repository. In other words, when Booker is started with the list command and the --lookup option:

  1. Booker will retrieve the JSON information for the book using the Google Books API.
  2. Booker will find the relevant information from the JSON object tree and create an instance of Book.
  3. Booker will store this new book in the current repository.
  4. Booker will then display the book information from the repository as it normally would for the list command.

Include at least the following information from the JSON object tree in the new book instance:

See Also

References

Resources

Acknowledgments