JSON Utilities

JSON Utilities for Java

License

License

Categories

Categories

Net JSON Data
GroupId

GroupId

net.pwall.json
ArtifactId

ArtifactId

jsonutil
Last Version

Last Version

5.0
Release Date

Release Date

Type

Type

jar
Description

Description

JSON Utilities
JSON Utilities for Java
Project URL

Project URL

https://github.com/pwall567/jsonutil
Source Code Management

Source Code Management

https://github.com/pwall567/jsonutil.git

Download jsonutil

How to add to project

<!-- https://jarcasting.com/artifacts/net.pwall.json/jsonutil/ -->
<dependency>
    <groupId>net.pwall.json</groupId>
    <artifactId>jsonutil</artifactId>
    <version>5.0</version>
</dependency>
// https://jarcasting.com/artifacts/net.pwall.json/jsonutil/
implementation 'net.pwall.json:jsonutil:5.0'
// https://jarcasting.com/artifacts/net.pwall.json/jsonutil/
implementation ("net.pwall.json:jsonutil:5.0")
'net.pwall.json:jsonutil:jar:5.0'
<dependency org="net.pwall.json" name="jsonutil" rev="5.0">
  <artifact name="jsonutil" type="jar" />
</dependency>
@Grapes(
@Grab(group='net.pwall.json', module='jsonutil', version='5.0')
)
libraryDependencies += "net.pwall.json" % "jsonutil" % "5.0"
[net.pwall.json/jsonutil "5.0"]

Dependencies

compile (1)

Group / Artifact Type Version
net.pwall.util : javautil jar 2.4

test (1)

Group / Artifact Type Version
org.junit.jupiter : junit-jupiter-api jar 5.6.0

Project Modules

There are no modules declared in this project.

jsonutil

Build Status License: MIT Maven Central

JSON encode/decode classes for Java

Background

Does the world need another Java JSON library? Perhaps not, but let me explain.

This work was started before any of the currently-popular libraries had achieved any sort of prominence. I had a requirement for classes to parse incoming JSON data, to hold the JSON representation in an internal form that was easy to access, and to output syntactically-correct JSON results. It seemed a reasonably simple task, and a good test of the ParseText class, part of my javautil library.

When I later encountered the more widely used libraries I was struck by how complicated they seemed. And how large. And one of them described itself as "fastJSON" which I saw as a challenge.

There is a place for software that does a limited range of operations, and does them very well. With that in mind, I decided to continue development of my JSON library.

Guiding Principles

Keep It Simple --- don't add complications that will rarely be used; keep your software easy to understand and easy to use.

Follow Standards --- where there is an existing standard that could be used, adopt that standard rather than creating a new one.

Make It Fast --- one of the main reasons for using a limited-functionality library is performance.

Design

In the light of those principles, the following design decisions were adopted:

  1. Have a single interface JSONValue implemented by each of the five types of JSON data: number, string, boolean, array and object.
  2. Ensure that the array class JSONArray implements List<JSONValue>, so that anyone familiar with that interface could easily access the contents of the array.
  3. Ensure that the object class JSONObject implements Map<String, JSONValue>, for similar reasons.
  4. Limit the implementation to the current requirements.

Implementation

The implementation follows a conventional Java pattern. There is a main class JSON which contains a set of static methods to parse a string (in memory, or in a file or stream) into the internal form. That internal form is a classic tree structure, where each node is either a leaf node (string, number or boolean), or a composite (array or object) which contains more nodes.

The nodes all implement the JSONValue interface, which specifies two methods:

  • String toJSON(); --- convert to the JSON external representation
  • void appendJSON(Appendable a) --- append the JSON form to an Appendable (for example, a StringBuilder or a Writer).

The second method is an optimisation, which avoids the need to create an individual String for each node when outputting a composite.

There is extensive JavaDoc which should assist in the use of the library.

Performance

On most benchmarks, the library significantly out-performs its competitors. For example:

Diagram

Maven

The library is in the Maven Central Repository; the co-ordinates are listed in the Dependency Specification section below.

Note that the groupId has changed from previous versions, which used net.pwall.util. From version 2.0 onwards, jsonutil requires Java 8. Those seeking a version compatible with Java 7 should use:

<dependency>
  <groupId>net.pwall.util</groupId>
  <artifactId>jsonutil</artifactId>
  <version>1.6</version>
</dependency>

Usage

There are several static methods of the JSON class to parse a string, file or input stream into a JSONValue. The result may be null if the input consists simply of the token null, or one of the seven simple JSON forms:

  • JSONString
  • JSONInteger
  • JSONLong
  • JSONDouble
  • JSONFloat
  • JSONZero (an optimisation to improve handling of zero values)
  • JSONBoolean

or one of the two composite forms:

  • JSONArray
  • JSONObject

All of the simple classes have a getValue() method to retrieve the value (this is not specified by the interface because the return type differs in each case). Also, the numeric classes all extend the Number class, so the accessors intValue(), doubleValue() etc. may be used to retrieve the value in a particular form. And the toString() methods on these classes all return the string representation of the value, not the JSON.

The simplest way to use the JSONArray and JSONObject classes is to treat them as List<JSONValue> and Map<String, JSONValue> respectively. In addition, there are several convenience methods (getString(), getObject() etc.) for use when the type of the value is known in advance. Also, several overloaded forms of addValue() (for JSONArray) and putValue() (for JSONObject) exist, to simplify adding values to arrays and objects.

The two static methods JSONArray.create() and JSONObject.create() exist to facilitate the "fluent" style of coding (see example below).

To create the JSON string value of an object, the toJSON() method may be called; this will serialize the value, recursively calling toJSON() on any member items as necessary. To avoid the unnecessary creation of a large number of intermediate string objects, the appendJSON() method may be used to append to an existing Stringbuilder etc. It should be noted that this is also useful for serializing directly to an output stream, e.g. a PrintStream or Writer.

Examples

To parse and process an incoming JSON object, assuming the JSON is of the form:

  {
    "id": "A23456",
    "qty": 12,
    "value": 60.00
  }

The following code will process that JSON:

JSONObject jsonObject = (JSONObject)JSON.parse(str);
String accountId = jsonObject.getString("id");
int quantity = jsonObject.getInt("qty");
double value = jsonObject.getDouble("value");

(The cast is required because JSON.parse(str) returns JSONValue; the developer has the option of testing the type of the returned value or allowing the system to throw a ClassCastException.)

Note: from version 1.6 onwards, additional convenience methods have been provided to cast the result to JSONArray or JSONObject. The first line of the above example may now be written:

JSONObject jsonObject = JSON.parseObject(str);

To create an object of that form and then output it:

JSONObject jsonObject = JSONObject.create().putValue("id", "A23456").putValue("qty", 12).
        putValue("value", 60.00);
System.out.println(jsonObject.toJSON()); 

And if that JSON object was an item in an array of objects, the array could be processed by:

JSONArray jsonArray = (JSONArray)JSON.parse(str);
for (JSONObject jsonObject : jsonArray.objects()) {
    String accountId = jsonObject.getString("id");
    // etc...
}

This is just a taste of what is available; see the JavaDoc for more information.

New Decimal Handling - Version 3.0 (and above)

JSON uses base 10 to represent numbers. This works perfectly well for integer values, e.g. 12345, but it can cause problems when representing fractions.

Most people are familiar with the fact that the value 1/3 (one third) can not be represented in a finite number of decimal places - the last digit is recurring. What is less well-known is that the value 1/10 (one tenth) can not be represented as a finite binary fraction, and this means that all binary representations of decimal fractions are potentially incorrect. As a result, Java double and float variables are potentially problematic as representations of parsed fractional numeric values.

To eliminate this problem the JSONDecimal class has been created, storing its value in the form of a BigDecimal. From version 3.0 of this library, all parsing operations will create JSONDecimal objects for non-integer number values instead of JSONDouble. Also, all numeric values (classes that derive from JSONNumberValue) now include toBigDecimal() and toBigInteger() methods to allow the value to be retrieved without intermediate conversion to binary floating point.

From version 3.1 of this library, the JSONDecimal class is also used for integer values that are too large for the Long class.

Breaking Change - Version 5.0

From version 5.0 onwards, the method get() on each of the JSONValue objects for the primitive types has been renamed getValue(). As well as being more idiomatically consistent with other forms of Java usage, this also allows Kotlin code to access values using the value property.

Dependency Specification

The latest version of the library is 5.0, and it may be obtained from the Maven Central repository.

Maven

    <dependency>
      <groupId>net.pwall.json</groupId>
      <artifactId>jsonutil</artifactId>
      <version>5.0</version>
    </dependency>

Gradle

    implementation "net.pwall.json:jsonutil:5.0"

Gradle (kts)

    implementation("net.pwall.json:jsonutil:5.0")

Peter Wall

2021-04-19

Versions

Version
5.0
4.2
4.1
4.0
3.1
3.0
2.2
2.1
2.0