Skip to content

Commit 0903da3

Browse files
cursoragentsimbo1905
andcommitted
Issue #119 Add counterexamples and native mapping demo
Co-authored-by: simbo1905 <simbo1905@60hertz.com>
1 parent 3f62ed2 commit 0903da3

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

json-java21/src/test/java/jdk/sandbox/java/util/json/DesignChoicesNumberExamplesTest.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44

55
import java.math.BigDecimal;
66
import java.math.BigInteger;
7+
import java.util.Map;
78
import java.util.logging.Logger;
89

910
import static org.assertj.core.api.Assertions.assertThat;
11+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1012

1113
public class DesignChoicesNumberExamplesTest {
1214
private static final Logger LOGGER = Logger.getLogger(DesignChoicesNumberExamplesTest.class.getName());
@@ -35,6 +37,24 @@ void convertingToDoubleIsPotentiallyLossy() {
3537
assertThat(lossy).isNotEqualByComparingTo(lossless);
3638
}
3739

40+
@Test
41+
void convertingNonIntegralNumberToLongThrows() {
42+
LOGGER.info("Executing convertingNonIntegralNumberToLongThrows");
43+
44+
var n = (JsonNumber) Json.parse("5.5");
45+
assertThatThrownBy(n::toLong)
46+
.isInstanceOf(JsonAssertionException.class);
47+
}
48+
49+
@Test
50+
void convertingOutOfRangeNumberToDoubleThrows() {
51+
LOGGER.info("Executing convertingOutOfRangeNumberToDoubleThrows");
52+
53+
var n = (JsonNumber) Json.parse("1e309");
54+
assertThatThrownBy(n::toDouble)
55+
.isInstanceOf(JsonAssertionException.class);
56+
}
57+
3858
@Test
3959
void parseExponentFormToBigIntegerExactWorks() {
4060
LOGGER.info("Executing parseExponentFormToBigIntegerExactWorks");
@@ -75,5 +95,27 @@ void lexicalPreservationDiffersFromNumericNormalization() {
7595
// but numeric values compare equal when canonicalized explicitly
7696
assertThat(new BigDecimal(a.toString())).isEqualByComparingTo(new BigDecimal(b.toString()));
7797
}
98+
99+
@Test
100+
void mappingToNativeTypesUsesPatternMatchingAndExplicitNumberPolicy() {
101+
LOGGER.info("Executing mappingToNativeTypesUsesPatternMatchingAndExplicitNumberPolicy");
102+
103+
JsonValue json = Json.parse("""
104+
{
105+
"smallInt": 42,
106+
"decimal": 5.5
107+
}
108+
""");
109+
110+
Object nativeValue = jdk.sandbox.java.util.json.examples.DesignChoicesExamples.toNative(json);
111+
assertThat(nativeValue).isInstanceOf(Map.class);
112+
113+
@SuppressWarnings("unchecked")
114+
var map = (Map<String, Object>) nativeValue;
115+
116+
assertThat(map.get("smallInt")).isEqualTo(42L);
117+
assertThat(map.get("decimal")).isInstanceOf(BigDecimal.class);
118+
assertThat((BigDecimal) map.get("decimal")).isEqualByComparingTo(new BigDecimal("5.5"));
119+
}
78120
}
79121

json-java21/src/test/java/jdk/sandbox/java/util/json/examples/DesignChoicesExamples.java

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
package jdk.sandbox.java.util.json.examples;
22

33
import jdk.sandbox.java.util.json.Json;
4+
import jdk.sandbox.java.util.json.JsonAssertionException;
5+
import jdk.sandbox.java.util.json.JsonArray;
6+
import jdk.sandbox.java.util.json.JsonBoolean;
47
import jdk.sandbox.java.util.json.JsonNumber;
8+
import jdk.sandbox.java.util.json.JsonNull;
9+
import jdk.sandbox.java.util.json.JsonObject;
10+
import jdk.sandbox.java.util.json.JsonString;
11+
import jdk.sandbox.java.util.json.JsonValue;
512

613
import java.math.BigDecimal;
714
import java.math.BigInteger;
15+
import java.util.Map;
16+
import java.util.stream.Collectors;
817

918
/**
1019
* Standalone examples demonstrating numeric design choices.
@@ -21,6 +30,8 @@ public static void main(String[] args) {
2130
parseToBigIntegerExact();
2231
bigDecimalToJsonNumberChooseTextPolicy();
2332
lexicalPreservationNotNormalization();
33+
counterExamples();
34+
mappingToNativeTypesWithPatternMatching();
2435

2536
System.out.println("\n=== All examples completed successfully! ===");
2637
}
@@ -65,6 +76,78 @@ public static boolean lexicalPreservationNotNormalization() {
6576
return a.toString().equals(b.toString());
6677
}
6778

79+
public static void counterExamples() {
80+
System.out.println("Counter-examples");
81+
System.out.println("----------------");
82+
83+
// 1) Converting a non-integral JSON number to long throws.
84+
try {
85+
var nonIntegral = (JsonNumber) Json.parse("5.5");
86+
System.out.println("nonIntegral.toString(): " + nonIntegral);
87+
System.out.println("nonIntegral.toLong(): " + nonIntegral.toLong());
88+
} catch (JsonAssertionException e) {
89+
System.out.println("Expected toLong() failure: " + e.getMessage());
90+
}
91+
92+
// 2) Converting an out-of-range JSON number to double throws.
93+
try {
94+
var tooBig = (JsonNumber) Json.parse("1e309");
95+
System.out.println("tooBig.toString(): " + tooBig);
96+
System.out.println("tooBig.toDouble(): " + tooBig.toDouble());
97+
} catch (JsonAssertionException e) {
98+
System.out.println("Expected toDouble() failure: " + e.getMessage());
99+
}
100+
101+
// 3) Converting to double can be lossy even when it does not throw.
102+
var highPrecision = (JsonNumber) Json.parse("3.141592653589793238462643383279");
103+
var lossless = new BigDecimal(highPrecision.toString());
104+
var lossy = new BigDecimal(Double.toString(highPrecision.toDouble()));
105+
System.out.println("lossless (BigDecimal): " + lossless.toPlainString());
106+
System.out.println("lossy (double->BD): " + lossy.toPlainString());
107+
System.out.println("lossless equals lossy? " + (lossless.compareTo(lossy) == 0));
108+
System.out.println();
109+
}
110+
111+
public static Object toNative(JsonValue v) {
112+
return switch (v) {
113+
case JsonNull ignored -> null;
114+
case JsonBoolean b -> b.bool();
115+
case JsonString s -> s.string();
116+
case JsonNumber n -> {
117+
try {
118+
yield n.toLong();
119+
} catch (JsonAssertionException ignored) {
120+
yield new BigDecimal(n.toString());
121+
}
122+
}
123+
case JsonArray a -> a.elements().stream().map(DesignChoicesExamples::toNative).toList();
124+
case JsonObject o -> o.members().entrySet().stream()
125+
.collect(Collectors.toMap(Map.Entry::getKey, e -> toNative(e.getValue())));
126+
};
127+
}
128+
129+
public static Object mappingToNativeTypesWithPatternMatching() {
130+
System.out.println("Mapping to native types (pattern matching)");
131+
System.out.println("------------------------------------------");
132+
133+
JsonValue json = Json.parse("""
134+
{
135+
"smallInt": 42,
136+
"decimal": 5.5,
137+
"huge": 3.141592653589793238462643383279,
138+
"flag": true,
139+
"name": "Ada",
140+
"items": [1, 2, 3]
141+
}
142+
""");
143+
144+
Object nativeValue = toNative(json);
145+
System.out.println("native class: " + nativeValue.getClass().getName());
146+
System.out.println("native value: " + nativeValue);
147+
System.out.println();
148+
return nativeValue;
149+
}
150+
68151
private DesignChoicesExamples() {}
69152
}
70153

0 commit comments

Comments
 (0)