Skip to content

Commit 49ceb5a

Browse files
cursoragentsimbo1905
andcommitted
Add json-transforms module implementing JSON Document Transforms specification
This commit adds the json-java21-transforms module which implements the Microsoft JSON Document Transforms specification from: https://github.com/Microsoft/json-document-transforms/wiki Features: - Parse phase: compile transform specs into immutable AST - Apply phase: apply transforms to JSON documents - Supported directives: - @jdt.value: set/create property value - @jdt.remove: remove property - @jdt.rename: rename property - @jdt.replace: replace existing value only - @jdt.merge: deep merge objects - JsonPath integration for node selection via @jdt.path - Reusable transforms (parse once, apply many) - Comprehensive test coverage (43 tests) Module structure follows existing patterns (json-java21-jtd, json-java21-jsonpath): - Immutable record-based AST - Two-phase parse/apply design - JUL logging at appropriate levels - Test base class for logging config To run tests: ./mvnw test -pl json-java21-transforms -am Co-authored-by: simbo1905 <simbo1905@60hertz.com>
1 parent 4e125de commit 49ceb5a

File tree

12 files changed

+1929
-0
lines changed

12 files changed

+1929
-0
lines changed

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,55 @@ System.out.println("Avg price: " + priceStats.getAverage());
440440

441441
See `json-java21-jsonpath/README.md` for JsonPath operators and more examples.
442442

443+
## JSON Transforms
444+
445+
This repo also includes a JSON Transforms implementation (module `json-java21-transforms`) based on the Microsoft JSON Document Transforms specification:
446+
https://github.com/Microsoft/json-document-transforms/wiki
447+
448+
JSON Transforms provides a declarative way to transform JSON documents using transform specifications. A transform specification is itself a JSON document that describes operations (rename, remove, replace, merge) to apply to a source document.
449+
450+
```java
451+
import jdk.sandbox.java.util.json.*;
452+
import json.java21.transforms.JsonTransforms;
453+
454+
// Source document
455+
JsonValue source = Json.parse("""
456+
{
457+
"name": "Alice",
458+
"age": 30,
459+
"city": "Seattle"
460+
}
461+
""");
462+
463+
// Transform specification
464+
JsonValue transform = Json.parse("""
465+
{
466+
"name": {
467+
"@jdt.rename": "fullName"
468+
},
469+
"age": {
470+
"@jdt.remove": true
471+
},
472+
"country": {
473+
"@jdt.value": "USA"
474+
}
475+
}
476+
""");
477+
478+
// Parse and apply transform
479+
JsonTransforms transformer = JsonTransforms.parse(transform);
480+
JsonValue result = transformer.apply(source);
481+
482+
// Result:
483+
// {
484+
// "fullName": "Alice",
485+
// "city": "Seattle",
486+
// "country": "USA"
487+
// }
488+
```
489+
490+
See `json-java21-transforms/README.md` for supported operations and more examples.
491+
443492
## Contributing
444493

445494
If you use an AI assistant while contributing, ensure it follows the contributor/agent workflow rules in `AGENTS.md`.

json-java21-transforms/AGENTS.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# json-java21-transforms/AGENTS.md
2+
3+
This file is for contributor/agent operational notes. Read `json-java21-transforms/README.md` for purpose, supported operations, and user-facing examples.
4+
5+
- User docs MUST recommend only `./mvnw`.
6+
- The `$(command -v mvnd || command -v mvn || command -v ./mvnw)` wrapper is for local developer speed only; do not put it in user-facing docs.
7+
8+
## Specification
9+
10+
This module implements JSON Document Transforms based on the Microsoft specification:
11+
- Wiki: https://github.com/Microsoft/json-document-transforms/wiki
12+
- C# Implementation: https://github.com/Microsoft/json-document-transforms
13+
14+
**IMPORTANT**: Do NOT call this technology "JDT" - that abbreviation conflicts with RFC 8927 (JSON Type Definition) which is implemented in `json-java21-jtd`. Always refer to this as "json-transforms" or "JSON Transforms".
15+
16+
## Stable Code Entry Points
17+
18+
- `json-java21-transforms/src/main/java/json/java21/transforms/JsonTransforms.java` - Main API
19+
- `json-java21-transforms/src/main/java/json/java21/transforms/JsonTransformsParser.java` - Parser
20+
- `json-java21-transforms/src/main/java/json/java21/transforms/JsonTransformsAst.java` - AST types
21+
- `json-java21-transforms/src/main/java/json/java21/transforms/JsonTransformsParseException.java` - Parse errors
22+
23+
## When Changing Syntax/Behavior
24+
25+
- Update `JsonTransformsAst` + `JsonTransformsParser` + `JsonTransforms` together.
26+
- Add parser + evaluation tests; new tests should extend `JsonTransformsLoggingConfig`.
27+
28+
## Design Principles
29+
30+
- Follow the parse/apply two-phase pattern like `JsonPath` and `Jtd`
31+
- Use immutable records for AST nodes
32+
- Pre-compile JsonPath expressions during parse phase
33+
- Apply transforms using stack-based evaluation (no recursion)
34+
- Defensive copies in all record constructors
35+
36+
Consider these rules if they affect your changes.

json-java21-transforms/README.md

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# JSON Transforms
2+
3+
A Java implementation of JSON document transforms based on the Microsoft JSON Document Transforms specification.
4+
5+
**Specification**: https://github.com/Microsoft/json-document-transforms/wiki
6+
7+
**Reference Implementation (C#)**: https://github.com/Microsoft/json-document-transforms
8+
9+
## Overview
10+
11+
JSON Transforms provides a declarative way to transform JSON documents using transform specifications. A transform specification is itself a JSON document that describes operations (rename, remove, replace, merge) to apply to a source document.
12+
13+
This implementation uses JsonPath queries (from `json-java21-jsonpath`) to select target nodes in the source document.
14+
15+
## Quick Start
16+
17+
```java
18+
import jdk.sandbox.java.util.json.*;
19+
import json.java21.transforms.JsonTransforms;
20+
21+
// Source document
22+
JsonValue source = Json.parse("""
23+
{
24+
"name": "Alice",
25+
"age": 30,
26+
"city": "Seattle"
27+
}
28+
""");
29+
30+
// Transform specification
31+
JsonValue transform = Json.parse("""
32+
{
33+
"name": {
34+
"@jdt.rename": "fullName"
35+
},
36+
"age": {
37+
"@jdt.remove": true
38+
},
39+
"country": {
40+
"@jdt.value": "USA"
41+
}
42+
}
43+
""");
44+
45+
// Parse and apply transform
46+
JsonTransforms transformer = JsonTransforms.parse(transform);
47+
JsonValue result = transformer.apply(source);
48+
49+
// Result:
50+
// {
51+
// "fullName": "Alice",
52+
// "city": "Seattle",
53+
// "country": "USA"
54+
// }
55+
```
56+
57+
## Transform Operations
58+
59+
### @jdt.path
60+
61+
Specifies a JsonPath query to select which elements to transform. When used at the root of a transform, applies the transform to matching elements.
62+
63+
```json
64+
{
65+
"@jdt.path": "$.users[*]",
66+
"status": {
67+
"@jdt.value": "active"
68+
}
69+
}
70+
```
71+
72+
### @jdt.value
73+
74+
Sets the value of a property. The value can be any JSON type (string, number, boolean, null, object, array).
75+
76+
```json
77+
{
78+
"newProperty": {
79+
"@jdt.value": "hello"
80+
},
81+
"count": {
82+
"@jdt.value": 42
83+
}
84+
}
85+
```
86+
87+
### @jdt.remove
88+
89+
Removes a property from the document. Set to `true` to remove.
90+
91+
```json
92+
{
93+
"obsoleteField": {
94+
"@jdt.remove": true
95+
}
96+
}
97+
```
98+
99+
### @jdt.rename
100+
101+
Renames a property to a new name.
102+
103+
```json
104+
{
105+
"oldName": {
106+
"@jdt.rename": "newName"
107+
}
108+
}
109+
```
110+
111+
### @jdt.replace
112+
113+
Replaces a property value with a new value. Unlike `@jdt.value`, this only works if the property already exists.
114+
115+
```json
116+
{
117+
"existingField": {
118+
"@jdt.replace": "new value"
119+
}
120+
}
121+
```
122+
123+
### @jdt.merge
124+
125+
Performs a deep merge of an object with the existing value.
126+
127+
```json
128+
{
129+
"config": {
130+
"@jdt.merge": {
131+
"newSetting": true,
132+
"timeout": 5000
133+
}
134+
}
135+
}
136+
```
137+
138+
## Design
139+
140+
JSON Transforms follows the two-phase pattern used by other modules in this repository:
141+
142+
1. **Parse Phase**: The transform specification is parsed into an immutable AST (Abstract Syntax Tree) of transform operations. JsonPath expressions are pre-compiled for efficiency.
143+
144+
2. **Apply Phase**: The parsed transform is applied to source documents. The same parsed transform can be reused across multiple source documents.
145+
146+
### Architecture
147+
148+
- **Immutable Records**: All transform operations are represented as immutable records
149+
- **Stack-based Evaluation**: Transforms are applied using a stack-based approach to avoid stack overflow on deeply nested documents
150+
- **JsonPath Integration**: Uses the `json-java21-jsonpath` module for powerful node selection
151+
152+
## Building and Testing
153+
154+
```bash
155+
# Build the module
156+
./mvnw compile -pl json-java21-transforms -am
157+
158+
# Run tests
159+
./mvnw test -pl json-java21-transforms -am
160+
161+
# Run with detailed logging
162+
./mvnw test -pl json-java21-transforms -am -Djava.util.logging.ConsoleHandler.level=FINE
163+
```
164+
165+
## API Reference
166+
167+
### JsonTransforms
168+
169+
Main entry point for parsing and applying transforms.
170+
171+
```java
172+
// Parse a transform specification
173+
JsonTransforms transform = JsonTransforms.parse(transformJson);
174+
175+
// Apply to a source document
176+
JsonValue result = transform.apply(sourceJson);
177+
```
178+
179+
### JsonTransformsAst
180+
181+
The AST (Abstract Syntax Tree) representation of transform operations. This is a sealed interface hierarchy:
182+
183+
- `TransformRoot` - Root of a transform specification
184+
- `PathTransform` - Transform with JsonPath selector (`@jdt.path`)
185+
- `ValueOp` - Set value operation (`@jdt.value`)
186+
- `RemoveOp` - Remove operation (`@jdt.remove`)
187+
- `RenameOp` - Rename operation (`@jdt.rename`)
188+
- `ReplaceOp` - Replace operation (`@jdt.replace`)
189+
- `MergeOp` - Merge operation (`@jdt.merge`)
190+
- `NestedTransform` - Nested transform for object properties
191+
192+
### JsonTransformsParseException
193+
194+
Thrown when a transform specification is invalid.
195+
196+
## License
197+
198+
This project is part of the OpenJDK JSON API implementation and follows the same licensing terms.

json-java21-transforms/pom.xml

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
5+
http://maven.apache.org/xsd/maven-4.0.0.xsd">
6+
<modelVersion>4.0.0</modelVersion>
7+
8+
<parent>
9+
<groupId>io.github.simbo1905.json</groupId>
10+
<artifactId>parent</artifactId>
11+
<version>0.1.9</version>
12+
</parent>
13+
14+
<artifactId>java.util.json.transforms</artifactId>
15+
<packaging>jar</packaging>
16+
<name>java.util.json Java21 Backport JSON Transforms</name>
17+
<url>https://simbo1905.github.io/java.util.json.Java21/</url>
18+
<scm>
19+
<connection>scm:git:https://github.com/simbo1905/java.util.json.Java21.git</connection>
20+
<developerConnection>scm:git:git@github.com:simbo1905/java.util.json.Java21.git</developerConnection>
21+
<url>https://github.com/simbo1905/java.util.json.Java21</url>
22+
<tag>HEAD</tag>
23+
</scm>
24+
<description>JSON Transforms implementation for the java.util.json Java 21 backport; parses transform specifications and applies them to JSON documents.</description>
25+
26+
<properties>
27+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
28+
<maven.compiler.release>21</maven.compiler.release>
29+
</properties>
30+
31+
<dependencies>
32+
<dependency>
33+
<groupId>io.github.simbo1905.json</groupId>
34+
<artifactId>java.util.json</artifactId>
35+
<version>${project.version}</version>
36+
</dependency>
37+
<dependency>
38+
<groupId>io.github.simbo1905.json</groupId>
39+
<artifactId>java.util.json.jsonpath</artifactId>
40+
<version>${project.version}</version>
41+
</dependency>
42+
43+
<!-- Test dependencies -->
44+
<dependency>
45+
<groupId>org.junit.jupiter</groupId>
46+
<artifactId>junit-jupiter-api</artifactId>
47+
<scope>test</scope>
48+
</dependency>
49+
<dependency>
50+
<groupId>org.junit.jupiter</groupId>
51+
<artifactId>junit-jupiter-engine</artifactId>
52+
<scope>test</scope>
53+
</dependency>
54+
<dependency>
55+
<groupId>org.junit.jupiter</groupId>
56+
<artifactId>junit-jupiter-params</artifactId>
57+
<scope>test</scope>
58+
</dependency>
59+
<dependency>
60+
<groupId>org.assertj</groupId>
61+
<artifactId>assertj-core</artifactId>
62+
<scope>test</scope>
63+
</dependency>
64+
</dependencies>
65+
66+
<build>
67+
<plugins>
68+
<!-- Treat all warnings as errors, enable all lint warnings -->
69+
<plugin>
70+
<groupId>org.apache.maven.plugins</groupId>
71+
<artifactId>maven-compiler-plugin</artifactId>
72+
<configuration>
73+
<release>21</release>
74+
<compilerArgs>
75+
<arg>-Xlint:all</arg>
76+
<arg>-Werror</arg>
77+
<arg>-Xdiags:verbose</arg>
78+
</compilerArgs>
79+
</configuration>
80+
</plugin>
81+
<plugin>
82+
<groupId>org.apache.maven.plugins</groupId>
83+
<artifactId>maven-surefire-plugin</artifactId>
84+
<configuration>
85+
<argLine>-ea</argLine>
86+
</configuration>
87+
</plugin>
88+
</plugins>
89+
</build>
90+
</project>

0 commit comments

Comments
 (0)