PostgreSQL Tutorial: Processing JSON & JSONB data in Java

September 6, 2024

Summary: in this tutorial, you will learn how to process PostgreSQL JSON & JSONB data in Java.

Table of Contents

Introduction

Starting v9.2, PostgreSQL is providing native data type support for JSON objects. Subsequent releases introduced JSONB (binary formatted JSON objects) and many data manipulation functions for JSONs, making it a very powerful tool for NoSQL operations.

String manipulation and parsing are very expensive operations in a database, so although you could have potentially stored JSON objects in strings in PostgreSQL before, introduction of the native data type has taken away overheads and made throughput a lot faster for JSON manipulation.

JSON & JSONB

JSONB was introduced as a native data type in v9.4 of PostgreSQL and it stores JSON objects in binary format. Major differences between JSON & JSONB are highlighted in the table below:

JSON JSONB
Stores data in text format Stores data in decomposed binary format
Input is fast, as no conversion are required Input is slightly slower, as there is an overhead related to binary conversion
Processing functions must re-parse the data on each execution Re-parsing is not needed, making data processing significantly faster
All white space and line feeds in the input are preserved as-is Extra white space and line feeds are stripped
Indexing is not supported Indexing is supported
Duplicate keys are retained, processing functions only consider the last value Duplicate keys are purged at input, only the last value is stored
Order of the keys is preserved Order is not preserved

JSON data definition

A JSON column is created just like any other data type. We create a table ‘sales’ below (which we will use in subsequent examples) containing 2 columns, ‘id’ and ‘sale’, with the latter being a JSON:

CREATE TABLE sales (id INT, sale JSON);

JSON data insertion

The JSON data type checks for a valid JSON format, so insert statements should be mindful of that. The simple Java program below inserts 4 records into the table we just created.

String[] json = {
  "{\"customer_name\": \"John\", \"items\": { \"description\": \"milk\", \"quantity\": 4 } }",
  "{\"customer_name\": \"Susan\", \"items\": { \"description\": \"bread\", \"quantity\": 2 } }",
  "{\"customer_name\": \"Mark\", \"items\": { \"description\": \"bananas\", \"quantity\": 12 } }",
  "{\"customer_name\": \"Jane\", \"items\": { \"description\": \"cereal\", \"quantity\": 1 } }"};

try {
  String sql = "INSERT INTO sales VALUES (?, ?::JSON)";
  PreparedStatement ps = conn.prepareStatement(sql);

  for (int i=0; i<4; i++) {
    ps.setInt(1, i+1);
    ps.setObject(2, json[i]);
    ps.executeUpdate();
  }
  conn.commit();
} catch (Exception e) {
   System.out.println(e.getMessage());
   e.printStackTrace();
}

Notice how the string is being cast to JSON within the prepared statement.

This is how the data shows up in psql after the insert above:

select * from sales;
 id | sale
----+-----------------------------------------------------------------------------------
 1  | {"customer_name": "John", "items": { "description": "milk", "quantity": 4 } }
 2  | {"customer_name": "Susan", "items": { "description": "bread", "quantity": 2 } }
 3  | {"customer_name": "Mark", "items": { "description": "bananas", "quantity": 12 } }
 4  | {"customer_name": "Jane", "items": { "description": "cereal", "quantity": 1 } }
(4 rows)

JSON data retrieval

While retrieving JSON data, you can use either PostgreSQL native operators to access individual elements or you can use the JSONObject Java library to process the objects within Java. Examples of both cases are given below.

Using PostgreSQL operator

PostgreSQL provides the ‘->’ operator to retrieve values of the various keys in a JSON object. The sample program below retrieves a list of ‘customer_name’ and then a list of ‘description’ of ‘items’ of the sale. The latter is an embedded JSON.

try {
  /* Retrieving customer_name */
  String sql = "select sale->'customer_name' from sales";
  PreparedStatement ps = conn.prepareStatement(sql);
  ResultSet rs = ps.executeQuery();

  while(rs.next()) {
    System.out.println(rs.getString(1));
  }

  System.out.println("******************************************");

  /* Retrieving description, which is an embedded JSON */
  sql = "select sale->'items'->'description' from sales";
  ps = conn.prepareStatement(sql);
  rs = ps.executeQuery();

  while(rs.next()) {
    System.out.println(rs.getString(1));
  }
} catch (Exception e) {
  System.out.println(e.getMessage());
  e.printStackTrace();
}

Output of the program above is:

"John"
"Susan"
"Mark"
"Jane"
******************************************
"milk"
"bread"
"bananas"
"cereal"

Using JSONObject

In order to use JSONObject with your Java program, you need to have its library jar file in your CLASSPATH. The jar file is freely available from many locations including this one. Basic JSON manipulation will be described below, but you can get more API details here.

Following Java code achieves the same result as demonstrated above:

try {
  /* Retrieving customer_name */
  String sql = "select sale from sales";
  Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
  ResultSet rs = stmt.executeQuery(sql);

  JSONObject json;
  JSONObject json2;

  while(rs.next()) {
    json = new JSONObject(rs.getString(1));
    System.out.println(json.get("customer_name"));
  }

  System.out.println("******************************************");

  /* Retrieving description, which is an embedded JSON */
  rs.first();

  do {
    json = new JSONObject(rs.getString(1));
    json2 = (JSONObject)json.get("items");
    System.out.println(json2.get("description"));
  } while(rs.next());
} catch (Exception e) {
  System.out.println(e.getMessage());
  e.printStackTrace();
}

Output from this program is:

John
Susan
Mark
Jane
******************************************
milk
bread
bananas
cereal