JSON Getter
and Setter
language inspired by GJSON. It provides a fast and simple way to get values from JSON documents with powerful path syntax and built-in modifiers.
Install using Maven or Gradle. Replace LATEST_VERSION
with the actual latest version.
Maven:
<dependency>
<groupId>com.transportial</groupId>
<artifactId>gsjson</artifactId>
<version>LATEST_VERSION</version>
</dependency>
Gradle:
dependencies {
implementation 'com.transportial:gsjson:LATEST_VERSION'
}
- Multiple Data Type Support: Works with
String
,org.json.JSONObject
,org.json.JSONArray
, and JacksonJsonNode
- Dot Notation Paths: Select JSON values using intuitive dot notation syntax
- Wildcard Support: Use
*
and?
wildcards for key matching - Array Operations: Access array elements, get length, and extract child paths
- Advanced Filtering: Support for
==
,!=
,<
,<=
,>
,>=
,%
(like),!%
(not like) operators - Nested Array Queries: Complex filtering with nested conditions
- Built-in Modifiers: Transform data with modifiers like
@reverse
,@sort
,@sum
,@avg
,@join
, etc. - Path Chaining: Chain operations using the pipe
|
character - JSON Lines Support: Process newline-delimited JSON with
..
prefix - Enhanced Result Type: Rich result objects with utility methods
- Reducer Functions: Aggregate array data with mathematical and string operations
A path is a series of keys separated by dots. GSJSON supports the following path features:
- Basic Access:
name.first
- Access nested properties - Array Index:
developers.[0]
- Access array elements by index - Array Length:
developers.[#]
- Get array length - All Elements:
developers.[#.firstName]
- Get all firstName values from array - Wildcards:
*.name
ortest?
- Match keys with wildcards - Filtering:
developers.[age > "25"]
- Filter arrays by conditions - Escaping:
fav\.movie
- Escape special characters
For the following examples, consider this JSON:
{
"name": {"first": "Tom", "last": "Anderson"},
"age": 37,
"children": ["Sara", "Alex", "Jack"],
"fav.movie": "Deer Hunter",
"friends": [
{"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]},
{"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]},
{"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]},
{"first": "David", "last": "Smith", "age": 25, "nets": ["fb"]}
]
}
// Basic property access
GSJson.get(json, "age") // Returns: 37
GSJson.get(json, "name.last") // Returns: "Anderson"
GSJson.get(json, "children") // Returns: ["Sara","Alex","Jack"]
// Escaped property names
GSJson.get(json, "fav\\.movie") // Returns: "Deer Hunter"
// Array indexing
GSJson.get(json, "children.[0]") // Returns: "Sara"
GSJson.get(json, "children.[1]") // Returns: "Alex"
// Array length
GSJson.get(json, "children.[#]") // Returns: 3
GSJson.get(json, "friends.[#]") // Returns: 4
// All child elements
GSJson.get(json, "friends.[#.first]") // Returns: ["Dale","Roger","Jane","David"]
GSJson.get(json, "friends.[#.age]") // Returns: [44,68,47,25]
// Wildcard matching
GSJson.get(json, "name.*") // Returns: ["Tom","Anderson"]
GSJson.get(json, "name.fir?t") // Returns: "Tom"
// Basic filtering
GSJson.get(json, "friends.[last == \"Murphy\"].first") // Returns: "Dale"
GSJson.get(json, "friends.[age > \"45\"].[0].first") // Returns: "Roger"
GSJson.get(json, "friends.[age <= \"30\"].[0].first") // Returns: "David"
// Pattern matching
GSJson.get(json, "friends.[first % \"D*\"].last") // Returns: "Murphy" (Dale)
GSJson.get(json, "friends.[first !% \"D*\"].[0].first") // Returns: "Roger"
// Nested array filtering
GSJson.get(json, "friends.[nets.[# == \"fb\"]].[#.first]") // Returns: ["Dale","Roger","David"]
// Array manipulation
GSJson.get(json, "children|@reverse") // Returns: ["Jack","Alex","Sara"]
GSJson.get(json, "children|@count") // Returns: 3
// Object operations
GSJson.get(json, "name|@keys") // Returns: ["first","last"]
GSJson.get(json, "name|@values") // Returns: ["Tom","Anderson"]
// JSON formatting
GSJson.get(json, "name|@pretty") // Returns: prettified JSON
GSJson.get(json, "name|@ugly") // Returns: minified JSON
// Basic array sorting
GSJson.get(json, "children|@sort") // Returns: ["Alex","Jack","Sara"]
GSJson.get(json, "children|@sort:desc") // Returns: ["Sara","Jack","Alex"]
// Sort arrays by object property
GSJson.get(json, "friends|@sortBy:age") // Sort by age ascending
GSJson.get(json, "friends|@sortBy:age:desc") // Sort by age descending
GSJson.get(json, "friends|@sortBy:first") // Sort by first name
GSJson.get(json, "friends|@sortBy:last:desc") // Sort by last name descending
// Chain sorting with other operations
GSJson.get(json, "friends.[age > \"40\"]|@sortBy:age|[#.first]") // Filter, sort, then extract names
GSJson.get(json, "friends.[#.age]|@sort:desc|[0]") // Get highest age
// Mathematical operations
GSJson.get(json, "friends.[#.age]|@sum") // Returns: 184.0
GSJson.get(json, "friends.[#.age]|@avg") // Returns: 46.0
GSJson.get(json, "friends.[#.age]|@min") // Returns: 25.0
GSJson.get(json, "friends.[#.age]|@max") // Returns: 68.0
// String operations
GSJson.get(json, "friends.[#.first]|@join") // Returns: "Dale,Roger,Jane,David"
GSJson.get(json, "friends.[#.first]|@join: | ") // Returns: "Dale | Roger | Jane | David"
GSJson.get(json, "children|@join:-") // Returns: "Sara-Alex-Jack"
val numbers = "[10, 20, 30, 40, 50]"
// Basic math operations on arrays
GSJson.get(numbers, ".|@multiply:2") // Returns: [20.0, 40.0, 60.0, 80.0, 100.0]
GSJson.get(numbers, ".|@add:5") // Returns: [15.0, 25.0, 35.0, 45.0, 55.0]
GSJson.get(numbers, ".|@subtract:10") // Returns: [0.0, 10.0, 20.0, 30.0, 40.0]
GSJson.get(numbers, ".|@divide:2") // Returns: [5.0, 10.0, 15.0, 20.0, 25.0]
// Advanced math operations
GSJson.get(numbers, ".|@abs") // Returns: absolute values
GSJson.get(numbers, ".|@round:1") // Returns: rounded to 1 decimal place
GSJson.get(numbers, ".|@power:2") // Returns: squared values
// Chain mathematical operations with aggregation
GSJson.get(json, "friends.[#.age]|@add:5|@sum") // Add 5 to each age, then sum
Mathematical operations now support both static values and JSON selectors as arguments:
val dynamicMathJson = """
{
"numbers": [10, 20, 30],
"multiplier": 3,
"divisor": 2,
"addend": 5,
"config": {
"factor": 4,
"precision": 1
}
}
"""
// Dynamic operations using JSON selectors
GSJson.get(dynamicMathJson, "numbers|@multiply:multiplier") // Returns: [30.0, 60.0, 90.0]
GSJson.get(dynamicMathJson, "numbers|@divide:divisor") // Returns: [5.0, 10.0, 15.0]
GSJson.get(dynamicMathJson, "numbers|@add:addend") // Returns: [15.0, 25.0, 35.0]
GSJson.get(dynamicMathJson, "numbers|@subtract:addend") // Returns: [5.0, 15.0, 25.0]
GSJson.get(dynamicMathJson, "numbers|@power:divisor") // Returns: [100.0, 400.0, 900.0]
// Nested path selectors
GSJson.get(dynamicMathJson, "numbers|@multiply:config.factor") // Returns: [40.0, 80.0, 120.0]
GSJson.get(dynamicMathJson, "numbers|@round:config.precision") // Returns: rounded values
// Chain dynamic and static operations
GSJson.get(dynamicMathJson, "numbers|@add:addend|@multiply:2") // Add dynamic value, then multiply by 2
GSJson.get(dynamicMathJson, "numbers|@multiply:config.factor|@divide:divisor") // Dynamic multiply then dynamic divide
Supported dynamic math operations:
@multiply:selector
/@mul:selector
- Multiply by value from JSON selector@divide:selector
/@div:selector
- Divide by value from JSON selector@add:selector
/@plus:selector
- Add value from JSON selector@subtract:selector
/@sub:selector
- Subtract value from JSON selector@power:selector
/@pow:selector
- Raise to power from JSON selector@round:selector
- Round to precision from JSON selector
// Provide defaults for missing or null values
GSJson.get(json, "name.middle", "J") // Returns: "J" (field doesn't exist)
GSJson.get(json, "age", 0) // Returns: 37 (field exists)
GSJson.get(json, "missing.field", "default") // Returns: "default"
GSJson.get(json, "friends.[99].name", "Unknown") // Returns: "Unknown" (index out of bounds)
// Works with all data types
GSJson.get(json, "missing.number", 42) // Numeric default
GSJson.get(json, "missing.boolean", true) // Boolean default
GSJson.get(json, "missing.list", listOf("a", "b")) // List default
// Chain multiple operations
GSJson.get(json, "friends.[age > \"40\"].[#.first]|@join") // Returns: "Dale,Roger,Jane"
GSJson.get(json, "children|@reverse|@join") // Returns: "Jack,Alex,Sara"
GSJson.get(json, "friends.[#.age]|@reverse|@max") // Returns: 68.0
Process newline-delimited JSON:
val jsonLines = """
{"name": "Alice", "age": 30}
{"name": "Bob", "age": 25}
{"name": "Charlie", "age": 35}
"""
GSJson.get(jsonLines, "..#") // Returns: 3
GSJson.get(jsonLines, "..[1].name") // Returns: "Bob"
GSJson.get(jsonLines, "..[#.name]|@join") // Returns: "Alice,Bob,Charlie"
GSJson.get(jsonLines, "..[age > \"30\"].[0].name") // Returns: "Charlie"
val result = GSJson.getResult(json, "age")
result.int() // Returns: 37
result.string() // Returns: "37"
result.exists // Returns: true
result.type // Returns: ResultType.NUMBER
// Array results
val arrayResult = GSJson.getResult(json, "friends.[#.first]")
arrayResult.array().forEach { name ->
println(name.string())
}
// Basic setting
GSJson.set(json, "age", 38)
GSJson.set(json, "name.middle", "J")
GSJson.set(json, "friends.[0].age", 45)
// Array operations
GSJson.set(json, "hobbies.[0]", "reading")
GSJson.set(json, "scores", listOf(85, 90, 78))
// Check existence
GSJson.exists(json, "name.first") // Returns: true
GSJson.exists(json, "name.middle") // Returns: false
// Process JSON Lines
GSJson.forEachLine(jsonLines) { line ->
println("Name: ${line.get("name").string()}")
true // continue iteration
}
GSJSON maintains the same powerful querying capabilities as GJSON while using slightly different syntax:
Feature | GJSON | GSJSON |
---|---|---|
Array filtering | friends.#(age>40) |
friends.[age > "40"] |
Array access | friends.0.name |
friends.[0].name |
All elements | friends.#.name |
friends.[#.name] |
Modifiers | children|@reverse |
children|@reverse |
GSJSON is built on Jackson for JSON parsing, providing excellent performance for JSON operations while maintaining the intuitive path syntax inspired by GJSON.