Manipulate Any Complex JSON with a Single JSONata Expression in Spring Boot

This article introduces JSONata4Java, shows how to add the library to a Spring Boot 3.5.0 project, and demonstrates a wide range of JSONata expressions—including property access, predicates, functions, object construction, grouping, aggregation, and sorting—through concrete code examples and expected outputs.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Manipulate Any Complex JSON with a Single JSONata Expression in Spring Boot

Introduction

In micro‑service architectures, heterogeneous JSON payloads are exchanged frequently. Hard‑coded conversion logic incurs high maintenance cost and long release cycles. JSONata4Java provides a declarative JSONata expression engine that can be configured at runtime, enabling dynamic data mapping without restarting services.

Adding the Dependency

<dependency>
  <groupId>com.ibm.jsonata4java</groupId>
  <artifactId>JSONata4Java</artifactId>
  <version>2.6.3</version>
</dependency>

The example assumes a Spring Boot 3.5.0 environment, which already includes Jackson; otherwise Jackson dependencies must be added.

Sample JSON Documents

{
  "FirstName": "王强",
  "Surname": "明辉",
  "Age": 28,
  "Address": {
    "Street": "科技园路88号",
    "City": "深圳市",
    "Postcode": "518057"
  },
  "Sno": [2,4,6,8,10],
  "Phone": [
    {"type":"home","number":"0755-8888 1234"},
    {"type":"office","number":"0755-6666 1234"},
    {"type":"office","number":"0755-6666 1235"},
    {"type":"mobile","number":"138 0000 1234"}
  ],
  "Email": [
    {"type":"work","address":["[email protected]","[email protected]"]},
    {"type":"home","address":["[email protected]","[email protected]"]}
  ],
  "Other": {
    "Over 18 ?": true,
    "Misc": null,
    "Alternative.Address": {
      "Street": "中山路168号",
      "City": "上海市",
      "Postcode": "200001"
    }
  }
}
{
  "Account": {
    "Order": [
      {
        "Product": [
          {"Product Name":"Bowler Hat","Price":34.45,"Quantity":2},
          {"Product Name":"Trilby hat","Price":21.67,"Quantity":1}
        ]
      },
      {
        "Product": [
          {"Product Name":"Bowler Hat","Price":34.45,"Quantity":4},
          {"Product Name":"Cloak","Price":107.99,"Quantity":1}
        ]
      }
    ]
  }
}

Basic Operations

Evaluating simple path expressions:

expression = "FirstName";
result = expressions.evaluate(jsonNode);
// Output: "王强"

expression = "Address.City";
// Output: "深圳市"

expression = "Phone[0]";
// Output: {"type":"home","number":"0755-8888 1234"}

expression = "Phone[0].number";
// Output: "0755-8888 1234"

expression = "Phone.number[0]";
// Output: ["0755-8888 1234","0755-6666 1234","0755-6666 1235","138 0000 1234"]

expression = "Phone[[0..1]]";
// Output: [{"type":"home","number":"0755-8888 1234"},{"type":"office","number":"0755-6666 1234"}]

Predicate Queries

Filtering with boolean predicates:

expression = "Phone[type='mobile']";
// Output: {"type":"mobile","number":"138 0000 1234"}

expression = "Phone[type='office'].number";
// Output: ["0755-6666 1234","0755-6666 1235"]

expression = "Address.*";
// Output: ["科技园路88号","深圳市","518057"]

expression = "*.Postcode";
// Output: "518057"

Functions & Expressions

String concatenation uses &. Numeric operators follow standard arithmetic.

expression = "FirstName & ' ' & Surname";
// Output: "王强 明辉"

expression = "Address.(Street & ', ' & City)";
// Output: "科技园路88号, 深圳市"

expression = "Sno[0] + Sno[1]";
// Output: 6

expression = "Sno[0] > Sno[1]";
// Output: FALSE

expression = "(Sno[2] != 4) and (Sno[3] != Sno[4])";
// Output: TRUE

Object Construction

expression = "Email.[address]";
// Output: [["[email protected]","[email protected]"],["[email protected]","[email protected]"]]

expression = "[Address, Other.`Alternative.Address`].City";
// Output: ["深圳市","上海市"]

expression = "Phone.{type: number}";
// Output: [{"home":"0755-8888 1234"},{"office":"0755-6666 1234"},{"office":"0755-6666 1235"},{"mobile":"138 0000 1234"}]

Grouping & Aggregation

expression = "Account.Order.Product{`Product Name`: Price}";
// Output: {"Bowler Hat":[34.45,34.45],"Trilby hat":21.67,"Cloak":107.99}

expression = """
        Account.Order.Product {
          `Product Name`: {"Price": Price, "Qty": Quantity}
        }
      """;
// Output: {"Bowler Hat":{"Price":[34.45,34.45],"Qty":[2,4]},"Trilby hat":{"Price":21.67,"Qty":1},"Cloak":{"Price":107.99,"Qty":1}}

expression = "Account.Order.Product{`Product Name`: $.(Price*Quantity)}";
// Output: {"Bowler Hat":[68.9,137.8],"Trilby hat":21.67,"Cloak":107.99}

expression = "$sum(Account.Order.Product.Price)";
// Output: 198.56

Array Functions

expression = "$count([1,2,3,1])";
// Output: 4

expression = "$append([1,2,3],[4,5,6])";
// Output: [1,2,3,4,5,6]

Sorting Example

expression = """
        $sort(Account.Order.Product, function($l, $r) {
          $l.Price * $l.Quantity > $r.Price * $r.Quantity
        })
      """;
// Result: [{"Product Name":"衬衣","Price":88,"Quantity":2},{"Product Name":"西裤","Price":230,"Quantity":1},{"Product Name":"内衣","Price":121,"Quantity":3}]

Reference

Complete list of JSONata functions and syntax: https://docs.jsonata.org/

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Spring BootJSON transformationJSONataJava data mappingJSONata4Java
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.