@@ -41,72 +41,77 @@ JsonValue value = Json.parse(json);
4141
4242// Access as map-like structure
4343JsonObject obj = (JsonObject ) value;
44- String name = ((JsonString ) obj. members(). get(" name" )). value ();
45- int age = ((JsonNumber ) obj. members(). get(" age" )). intValue ();
46- boolean active = ((JsonBoolean ) obj. members(). get(" active" )). value ();
44+ String name = ((JsonString ) obj. members(). get(" name" )). string ();
45+ long age = ((JsonNumber ) obj. members(). get(" age" )). toLong ();
46+ boolean active = ((JsonBoolean ) obj. members(). get(" active" )). bool ();
4747```
4848
4949### Simple Record Mapping
5050
5151``` java
5252// Define records for structured data
53- record User(String name, int age, boolean active) {}
53+ record User(String name, long age, boolean active) {}
5454
5555// Parse JSON directly to records
5656String userJson = " {\" name\" :\" Bob\" ,\" age\" :25,\" active\" :false}" ;
5757JsonObject jsonObj = (JsonObject ) Json . parse(userJson);
5858
5959// Map to record
6060User user = new User (
61- ((JsonString ) jsonObj. members(). get(" name" )). value (),
62- ((JsonNumber ) jsonObj. members(). get(" age" )). intValue (),
63- ((JsonBoolean ) jsonObj. members(). get(" active" )). value ()
61+ ((JsonString ) jsonObj. members(). get(" name" )). string (),
62+ ((JsonNumber ) jsonObj. members(). get(" age" )). toLong (),
63+ ((JsonBoolean ) jsonObj. members(). get(" active" )). bool ()
6464);
6565
66- // Convert records back to JSON
67- JsonValue backToJson = Json . fromUntyped (Map . of(
68- " name" , user. name(),
69- " age" , user. age(),
70- " active" , user. active()
66+ // Convert records back to JSON using typed factories
67+ JsonValue backToJson = JsonObject . of (Map . of(
68+ " name" , JsonString . of( user. name() ),
69+ " age" , JsonNumber . of( user. age() ),
70+ " active" , JsonBoolean . of( user. active() )
7171));
7272
73- // Covert back to a JSON string
73+ // Convert back to a JSON string
7474String jsonString = backToJson. toString();
7575```
7676
77- ### Converting from Java Objects to JSON ( ` fromUntyped ` )
77+ ### Building JSON Programmatically
7878
7979``` java
80- // Convert standard Java collections to JsonValue
81- Map<String , Object > data = Map . of(
82- " name" , " John" ,
83- " age" , 30 ,
84- " scores" , List . of(85 , 92 , 78 )
85- );
86- JsonValue json = Json . fromUntyped(data);
80+ // Build JSON using typed factory methods
81+ JsonObject data = JsonObject . of(Map . of(
82+ " name" , JsonString . of(" John" ),
83+ " age" , JsonNumber . of(30 ),
84+ " scores" , JsonArray . of(List . of(
85+ JsonNumber . of(85 ),
86+ JsonNumber . of(92 ),
87+ JsonNumber . of(78 )
88+ ))
89+ ));
90+ String json = data. toString();
8791```
8892
89- ### Converting from JSON to Java Objects ( ` toUntyped ` )
93+ ### Extracting Values from JSON
9094
9195``` java
92- // Convert JsonValue back to standard Java types
96+ // Extract values from parsed JSON
9397JsonValue parsed = Json . parse(" {\" name\" :\" John\" ,\" age\" :30}" );
94- Object data = Json . toUntyped(parsed);
95- // Returns a Map<String, Object> with standard Java types
96- ```
98+ JsonObject obj = (JsonObject ) parsed;
9799
98- The conversion mappings are:
99- - ` JsonObject ` ↔ ` Map<String, Object> `
100- - ` JsonArray ` ↔ ` List<Object> `
101- - ` JsonString ` ↔ ` String `
102- - ` JsonNumber ` ↔ ` Number ` (Long, Double, BigInteger, or BigDecimal)
103- - ` JsonBoolean ` ↔ ` Boolean `
104- - ` JsonNull ` ↔ ` null `
100+ // Use the new type-safe accessor methods
101+ String name = obj. get(" name" ). string(); // Returns "John"
102+ long age = obj. get(" age" ). toLong(); // Returns 30L
103+ double ageDouble = obj. get(" age" ). toDouble(); // Returns 30.0
104+ ```
105105
106- This is useful for:
107- - Integrating with existing code that uses standard collections
108- - Serializing/deserializing to formats that expect Java types
109- - Working with frameworks that use reflection on standard types
106+ The accessor methods on ` JsonValue ` :
107+ - ` string() ` - Returns the String value (for JsonString)
108+ - ` toLong() ` - Returns the long value (for JsonNumber, if representable)
109+ - ` toDouble() ` - Returns the double value (for JsonNumber, if representable)
110+ - ` bool() ` - Returns the boolean value (for JsonBoolean)
111+ - ` elements() ` - Returns List<JsonValue > (for JsonArray)
112+ - ` members() ` - Returns Map<String, JsonValue> (for JsonObject)
113+ - ` get(String name) ` - Access JsonObject member by name
114+ - ` element(int index) ` - Access JsonArray element by index
110115
111116### Realistic Record Mapping
112117
@@ -123,29 +128,29 @@ Team team = new Team("Engineering", List.of(
123128 new User (" Bob" , " bob@example.com" , false )
124129));
125130
126- // Convert records to JSON
127- JsonValue teamJson = Json . fromUntyped (Map . of(
128- " teamName" , team. teamName(),
129- " members" , team. members(). stream()
130- .map(u - > Map . of(
131- " name" , u. name(),
132- " email" , u. email(),
133- " active" , u. active()
134- ))
135- .toList()
131+ // Convert records to JSON using typed factories
132+ JsonValue teamJson = JsonObject . of (Map . of(
133+ " teamName" , JsonString . of( team. teamName() ),
134+ " members" , JsonArray . of( team. members(). stream()
135+ .map(u - > JsonObject . of( Map . of(
136+ " name" , JsonString . of( u. name() ),
137+ " email" , JsonString . of( u. email() ),
138+ " active" , JsonBoolean . of( u. active() )
139+ )))
140+ .toList())
136141));
137142
138143// Parse JSON back to records
139144JsonObject parsed = (JsonObject ) Json . parse(teamJson. toString());
140145Team reconstructed = new Team (
141- ((JsonString ) parsed. members(). get(" teamName" )). value (),
142- ((JsonArray ) parsed. members(). get(" members" )). values (). stream()
146+ ((JsonString ) parsed. members(). get(" teamName" )). string (),
147+ ((JsonArray ) parsed. members(). get(" members" )). elements (). stream()
143148 .map(v - > {
144149 JsonObject member = (JsonObject ) v;
145150 return new User (
146- ((JsonString ) member. members(). get(" name" )). value (),
147- ((JsonString ) member. members(). get(" email" )). value (),
148- ((JsonBoolean ) member. members(). get(" active" )). value ()
151+ ((JsonString ) member. members(). get(" name" )). string (),
152+ ((JsonString ) member. members(). get(" email" )). string (),
153+ ((JsonBoolean ) member. members(). get(" active" )). bool ()
149154 );
150155 })
151156 .toList()
@@ -182,10 +187,10 @@ Process JSON arrays efficiently with Java streams:
182187``` java
183188// Filter active users from a JSON array
184189JsonArray users = (JsonArray ) Json . parse(jsonArrayString);
185- List<String > activeUserEmails = users. values (). stream()
190+ List<String > activeUserEmails = users. elements (). stream()
186191 .map(v - > (JsonObject ) v)
187- .filter(obj - > ((JsonBoolean ) obj. members(). get(" active" )). value ())
188- .map(obj - > ((JsonString ) obj. members(). get(" email" )). value ())
192+ .filter(obj - > ((JsonBoolean ) obj. members(). get(" active" )). bool ())
193+ .map(obj - > ((JsonString ) obj. members(). get(" email" )). string ())
189194 .toList();
190195```
191196
@@ -263,7 +268,14 @@ mvn exec:java -pl json-compatibility-suite -Dexec.args="--json"
263268
264269## Current Status
265270
266- This code (as of 2025-09-04) is derived from the OpenJDK jdk-sandbox repository “json” branch at commit [ a8e7de8b49e4e4178eb53c94ead2fa2846c30635] ( https://github.com/openjdk/jdk-sandbox/commit/a8e7de8b49e4e4178eb53c94ead2fa2846c30635 ) ("Produce path/col during path building", 2025-08-14 UTC).
271+ This code (as of 2026-01-25) is derived from the OpenJDK jdk-sandbox repository "json" branch. Key API changes from the previous version include:
272+ - ` JsonString.value() ` → ` JsonString.string() `
273+ - ` JsonNumber.toNumber() ` → ` JsonNumber.toLong() ` / ` JsonNumber.toDouble() `
274+ - ` JsonBoolean.value() ` → ` JsonBoolean.bool() `
275+ - ` JsonArray.values() ` → ` JsonArray.elements() `
276+ - ` Json.fromUntyped() ` and ` Json.toUntyped() ` have been removed
277+ - New accessor methods on ` JsonValue ` : ` get(String) ` , ` element(int) ` , ` getOrAbsent(String) ` , ` valueOrNull() `
278+ - Internal implementation changed from ` StableValue ` to ` LazyConstant `
267279
268280The original proposal and design rationale can be found in the included PDF: [ Towards a JSON API for the JDK.pdf] ( Towards%20a%20JSON%20API%20for%20the%20JDK.pdf )
269281
@@ -276,8 +288,11 @@ A daily workflow runs an API comparison against the OpenJDK sandbox and prints a
276288## Modifications
277289
278290This is a simplified backport with the following changes from the original:
279- - Replaced ` StableValue.of() ` with double-checked locking pattern.
291+ - Replaced ` LazyConstant ` with a package-local polyfill using double-checked locking pattern.
292+ - Added ` Utils.powExact() ` polyfill for ` Math.powExact(long, int) ` which is not available in Java 21.
293+ - Replaced unnamed variables ` _ ` with ` ignored ` for Java 21 compatibility.
280294- Removed ` @ValueBased ` annotations.
295+ - Removed ` @PreviewFeature ` annotations.
281296- Compatible with JDK 21.
282297
283298## Security Considerations
0 commit comments