Skip to content

Commit 64e9962

Browse files
author
Simon Massey
authored
Add documentation and tests for typed/untyped conversion utilities (#2)
* Document type conversion utilities (fromUntyped/toUntyped) Added comprehensive documentation for the Json.fromUntyped() and Json.toUntyped() methods that provide bidirectional conversion between JsonValue objects and standard Java collections/types. Includes usage examples and type mappings. * Add comprehensive tests for typed/untyped conversion utilities - Created JsonTypedUntypedTests with full coverage of Json.fromUntyped() and Json.toUntyped() - Tests simple types, collections, nested structures, edge cases, and round-trip conversion - Added .mvn directory to fix mvnd warning about root directory * Fix JsonTypedUntypedTests compilation and test failures - Fixed generic type issues with List<?> by using @SuppressWarnings and proper casting - Corrected numeric type expectations (Integer boxed to Long in JsonNumber) - All 14 tests now pass successfully * Update GitHub Actions to trigger on PR events - Added explicit PR event types: opened, synchronize, reopened - Ensures checks run when PRs are created or updated
1 parent 717abf4 commit 64e9962

File tree

8 files changed

+304
-48
lines changed

8 files changed

+304
-48
lines changed

README.md

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,40 @@ The API provides immutable JSON value types:
4343
Parsing is done via the `Json` class:
4444
```java
4545
JsonValue value = Json.parse(jsonString);
46-
```
46+
```
47+
48+
## Type Conversion Utilities
49+
50+
The `Json` class provides bidirectional conversion between `JsonValue` objects and standard Java types:
51+
52+
### Converting from Java Objects to JSON (`fromUntyped`)
53+
```java
54+
// Convert standard Java collections to JsonValue
55+
Map<String, Object> data = Map.of(
56+
"name", "John",
57+
"age", 30,
58+
"scores", List.of(85, 92, 78)
59+
);
60+
JsonValue json = Json.fromUntyped(data);
61+
```
62+
63+
### Converting from JSON to Java Objects (`toUntyped`)
64+
```java
65+
// Convert JsonValue back to standard Java types
66+
JsonValue parsed = Json.parse("{\"name\":\"John\",\"age\":30}");
67+
Object data = Json.toUntyped(parsed);
68+
// Returns a Map<String, Object> with standard Java types
69+
```
70+
71+
The conversion mappings are:
72+
- `JsonObject``Map<String, Object>`
73+
- `JsonArray``List<Object>`
74+
- `JsonString``String`
75+
- `JsonNumber``Number` (Long, Double, BigInteger, or BigDecimal)
76+
- `JsonBoolean``Boolean`
77+
- `JsonNull``null`
78+
79+
This is useful for:
80+
- Integrating with existing code that uses standard collections
81+
- Serializing/deserializing to formats that expect Java types
82+
- Working with frameworks that use reflection on standard types

src/main/java/jdk/sandbox/demo/JsonDemo.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ public static void main(String[] args) {
1414
"age", JsonNumber.of(30)
1515
));
1616

17-
System.out.println(jsonObject.toString());
18-
17+
System.out.println(jsonObject);
18+
1919
// Parse JSON string
2020
String jsonStr = "{\"name\":\"Jane\",\"age\":25}";
2121
var parsed = Json.parse(jsonStr);

src/main/java/jdk/sandbox/internal/util/json/JsonNumberImpl.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ public final class JsonNumberImpl implements JsonNumber {
4040
private final int startOffset;
4141
private final int endOffset;
4242
private final boolean isFp;
43-
private final jdk.sandbox.StableValue<Number> theNumber = jdk.sandbox.StableValue.of();
44-
private final jdk.sandbox.StableValue<String> numString = jdk.sandbox.StableValue.of();
45-
private final jdk.sandbox.StableValue<BigDecimal> cachedBD = jdk.sandbox.StableValue.of();
43+
private final StableValue<Number> theNumber = StableValue.of();
44+
private final StableValue<String> numString = StableValue.of();
45+
private final StableValue<BigDecimal> cachedBD = StableValue.of();
4646

4747
public JsonNumberImpl(Number num) {
4848
// Called by factories. Input is Double, Long, BI, or BD.

src/main/java/jdk/sandbox/internal/util/json/JsonParser.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public final class JsonParser {
4848
// Access to the underlying JSON contents
4949
private final char[] doc;
5050
// Lazily initialized for member names with escape sequences
51-
private final Supplier<StringBuilder> sb = jdk.sandbox.StableValue.supplier(this::initSb);
51+
private final Supplier<StringBuilder> sb = StableValue.supplier(this::initSb);
5252
// Current offset during parsing
5353
private int offset;
5454
// For exception message on failure

src/main/java/jdk/sandbox/internal/util/json/JsonStringImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ public final class JsonStringImpl implements JsonString {
4242
// It always conforms to JSON syntax. If created by parsing a JSON document,
4343
// it matches the original text exactly. If created via the factory method,
4444
// non-conformant characters are properly escaped.
45-
private final jdk.sandbox.StableValue<String> jsonStr = jdk.sandbox.StableValue.of();
45+
private final StableValue<String> jsonStr = StableValue.of();
4646

4747
// The String instance returned by `value()`.
4848
// If created by parsing a JSON document, escaped characters are unescaped.
4949
// If created via the factory method, the input String is used as-is.
50-
private final jdk.sandbox.StableValue<String> value = jdk.sandbox.StableValue.of();
50+
private final StableValue<String> value = StableValue.of();
5151

5252
// Called by JsonString.of() factory. The passed String represents the
5353
// unescaped value.
Lines changed: 23 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,26 @@
1-
package jdk.sandbox;
1+
package jdk.sandbox.internal.util.json;
22

33
import java.util.function.Supplier;
44

55
/**
66
* Mimics JDK's StableValue using double-checked locking pattern
77
* for thread-safe lazy initialization.
88
*/
9-
public class StableValue<T> {
9+
class StableValue<T> {
1010
private volatile T value;
1111
private final Object lock = new Object();
12-
12+
1313
private StableValue() {}
14-
14+
1515
public static <T> StableValue<T> of() {
1616
return new StableValue<>();
1717
}
18-
19-
public T get() {
20-
return value;
21-
}
22-
23-
public void set(T value) {
24-
if (this.value == null) {
25-
synchronized (lock) {
26-
if (this.value == null) {
27-
this.value = value;
28-
}
29-
}
30-
}
31-
}
32-
33-
public T orElse(T defaultValue) {
18+
19+
public T orElse(T defaultValue) {
3420
T result = value;
3521
return result != null ? result : defaultValue;
3622
}
37-
23+
3824
public T orElseSet(Supplier<T> supplier) {
3925
T result = value;
4026
if (result == null) {
@@ -47,7 +33,7 @@ public T orElseSet(Supplier<T> supplier) {
4733
}
4834
return result;
4935
}
50-
36+
5137
public void setOrThrow(T newValue) {
5238
if (value != null) {
5339
throw new IllegalStateException("Value already set");
@@ -59,25 +45,25 @@ public void setOrThrow(T newValue) {
5945
value = newValue;
6046
}
6147
}
62-
48+
6349
public static <T> Supplier<T> supplier(Supplier<T> supplier) {
64-
return new Supplier<T>() {
65-
private volatile T cached;
66-
private final Object supplierLock = new Object();
67-
68-
@Override
69-
public T get() {
70-
T result = cached;
50+
return new Supplier<>() {
51+
private volatile T cached;
52+
private final Object supplierLock = new Object();
53+
54+
@Override
55+
public T get() {
56+
T result = cached;
57+
if (result == null) {
58+
synchronized (supplierLock) {
59+
result = cached;
7160
if (result == null) {
72-
synchronized (supplierLock) {
73-
result = cached;
74-
if (result == null) {
75-
cached = result = supplier.get();
76-
}
77-
}
61+
cached = result = supplier.get();
7862
}
79-
return result;
63+
}
8064
}
65+
return result;
66+
}
8167
};
8268
}
8369
}

src/main/java/jdk/sandbox/java/util/json/Json.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@
4848
* <p>
4949
* {@link #fromUntyped(Object)} and {@link #toUntyped(JsonValue)} provide a conversion
5050
* between {@code JsonValue} and an untyped object.
51-
*
52-
* @spec https://datatracker.ietf.org/doc/html/rfc8259 RFC 8259: The JavaScript
51+
* <p>
52+
* {@code @spec} <a href="https://datatracker.ietf.org/doc/html/rfc8259">...</a> RFC 8259: The JavaScript
5353
* Object Notation (JSON) Data Interchange Format
5454
* @since 99
5555
*/

0 commit comments

Comments
 (0)