From 3d20c79256ab9da4a0cea0b2d6ef48ffdd6f767f Mon Sep 17 00:00:00 2001 From: Ethan McCue Date: Mon, 18 Dec 2023 21:24:05 -0500 Subject: [PATCH] Bump to java 21 --- README.md | 6 +- pom.xml | 13 +- src/main/java/dev/mccue/json/Json.java | 20 +-- src/main/java/dev/mccue/json/JsonDecimal.java | 8 ++ src/main/java/dev/mccue/json/JsonInteger.java | 8 ++ src/main/java/dev/mccue/json/JsonNumber.java | 45 ++++--- .../java/dev/mccue/json/JsonReadOptions.java | 12 +- .../mccue/json/internal/BigDecimalImpl.java | 102 --------------- .../dev/mccue/json/internal/DoubleImpl.java | 116 ------------------ .../mccue/json/internal/JsonDecimalImpl.java | 82 +++++++++++++ ...gIntegerImpl.java => JsonIntegerImpl.java} | 45 +++---- .../json/internal/JsonReaderMethods.java | 34 ++--- .../dev/mccue/json/internal/JsonWriter.java | 30 ++--- .../dev/mccue/json/internal/LongImpl.java | 103 ---------------- .../json/stream/JsonStreamReadOptions.java | 9 +- .../java/dev/mccue/json/JsonParsingTest.java | 43 ++++++- 16 files changed, 223 insertions(+), 453 deletions(-) create mode 100644 src/main/java/dev/mccue/json/JsonDecimal.java create mode 100644 src/main/java/dev/mccue/json/JsonInteger.java delete mode 100644 src/main/java/dev/mccue/json/internal/BigDecimalImpl.java delete mode 100644 src/main/java/dev/mccue/json/internal/DoubleImpl.java create mode 100644 src/main/java/dev/mccue/json/internal/JsonDecimalImpl.java rename src/main/java/dev/mccue/json/internal/{BigIntegerImpl.java => JsonIntegerImpl.java} (51%) delete mode 100644 src/main/java/dev/mccue/json/internal/LongImpl.java diff --git a/README.md b/README.md index 3118281..8096300 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A Java JSON Library intended to be easy to learn and simple to teach. -Requires Java 17+. +Requires Java 21+. ## Dependency Information @@ -16,7 +16,7 @@ Requires Java 17+. dev.mccue json - 0.2.4 + 0.3.0 ``` @@ -24,7 +24,7 @@ Requires Java 17+. ``` dependencies { - implementation("dev.mccue:json:0.2.4") + implementation("dev.mccue:json:0.3.0") } ``` diff --git a/pom.xml b/pom.xml index e157783..096c655 100644 --- a/pom.xml +++ b/pom.xml @@ -6,17 +6,17 @@ dev.mccue json - 0.2.4 + 0.3.0 jar UTF-8 - 17 - 17 + 21 + 21 json - Dead simple Java JSON API based on sealed interfaces. + A Java JSON Library intended to be easy to learn and simple to teach. https://github.com/bowbahdoe/json @@ -63,10 +63,9 @@ maven-compiler-plugin 3.8.1 - 17 - 17 + 21 + 21 - -Xlint:all -Werror diff --git a/src/main/java/dev/mccue/json/Json.java b/src/main/java/dev/mccue/json/Json.java index 0c595aa..486f421 100644 --- a/src/main/java/dev/mccue/json/Json.java +++ b/src/main/java/dev/mccue/json/Json.java @@ -79,7 +79,7 @@ static Json of(@Nullable JsonEncodable value) { * @return An instance of {@link Json}. */ static Json of(@Nullable BigDecimal value) { - return value == null ? JsonNull.instance() : new BigDecimalImpl(value); + return value == null ? JsonNull.instance() : JsonNumber.of(value); } /** @@ -89,7 +89,7 @@ static Json of(@Nullable BigDecimal value) { * @return An instance of {@link Json}. */ static Json of(double value) { - return new DoubleImpl(value); + return JsonNumber.of(value); } /** @@ -99,7 +99,7 @@ static Json of(double value) { * @return An instance of {@link Json}. */ static Json of(long value) { - return new LongImpl(value); + return JsonNumber.of(value); } /** @@ -109,7 +109,7 @@ static Json of(long value) { * @return An instance of {@link Json}. */ static Json of(float value) { - return new DoubleImpl(value); + return JsonNumber.of(value); } /** @@ -119,7 +119,7 @@ static Json of(float value) { * @return An instance of {@link Json}. */ static Json of(int value) { - return new LongImpl(value); + return JsonNumber.of(value); } /** @@ -129,7 +129,7 @@ static Json of(int value) { * @return An instance of {@link Json}. */ static Json of(@Nullable Double value) { - return value == null ? JsonNull.instance() : new DoubleImpl(value); + return value == null ? JsonNull.instance() : of((double) value); } /** @@ -139,7 +139,7 @@ static Json of(@Nullable Double value) { * @return An instance of {@link Json}. */ static Json of(@Nullable Long value) { - return value == null ? JsonNull.instance() : new LongImpl(value); + return value == null ? JsonNull.instance() : of((long) value); } /** @@ -149,7 +149,7 @@ static Json of(@Nullable Long value) { * @return An instance of {@link Json}. */ static Json of(@Nullable Float value) { - return value == null ? JsonNull.instance() : new DoubleImpl(value); + return value == null ? JsonNull.instance() : of((float) value); } /** @@ -159,7 +159,7 @@ static Json of(@Nullable Float value) { * @return An instance of {@link Json}. */ static Json of(@Nullable Integer value) { - return value == null ? JsonNull.instance() : new LongImpl(value); + return value == null ? JsonNull.instance() : of((int) value); } /** @@ -169,7 +169,7 @@ static Json of(@Nullable Integer value) { * @return An instance of {@link Json}. */ static Json of(@Nullable BigInteger value) { - return value == null ? JsonNull.instance() : new BigIntegerImpl(value); + return value == null ? JsonNull.instance() : JsonNumber.of(value); } /** diff --git a/src/main/java/dev/mccue/json/JsonDecimal.java b/src/main/java/dev/mccue/json/JsonDecimal.java new file mode 100644 index 0000000..73d7098 --- /dev/null +++ b/src/main/java/dev/mccue/json/JsonDecimal.java @@ -0,0 +1,8 @@ +package dev.mccue.json; + +import dev.mccue.json.internal.JsonDecimalImpl; + +public sealed abstract class JsonDecimal + extends JsonNumber + permits JsonDecimalImpl { +} diff --git a/src/main/java/dev/mccue/json/JsonInteger.java b/src/main/java/dev/mccue/json/JsonInteger.java new file mode 100644 index 0000000..6561689 --- /dev/null +++ b/src/main/java/dev/mccue/json/JsonInteger.java @@ -0,0 +1,8 @@ +package dev.mccue.json; + +import dev.mccue.json.internal.JsonIntegerImpl; + +public sealed abstract class JsonInteger + extends JsonNumber + permits JsonIntegerImpl { +} diff --git a/src/main/java/dev/mccue/json/JsonNumber.java b/src/main/java/dev/mccue/json/JsonNumber.java index 216587a..12e02a7 100644 --- a/src/main/java/dev/mccue/json/JsonNumber.java +++ b/src/main/java/dev/mccue/json/JsonNumber.java @@ -1,9 +1,7 @@ package dev.mccue.json; -import dev.mccue.json.internal.BigDecimalImpl; -import dev.mccue.json.internal.BigIntegerImpl; -import dev.mccue.json.internal.DoubleImpl; -import dev.mccue.json.internal.LongImpl; +import dev.mccue.json.internal.JsonDecimalImpl; +import dev.mccue.json.internal.JsonIntegerImpl; import dev.mccue.json.stream.JsonGenerator; import java.io.Serial; @@ -16,8 +14,7 @@ */ public sealed abstract class JsonNumber extends Number - implements Json - permits BigDecimalImpl, DoubleImpl, LongImpl, BigIntegerImpl { + implements Json permits JsonDecimal, JsonInteger { @Serial private static final long serialVersionUID = 1L; @@ -35,28 +32,40 @@ protected JsonNumber() {} public abstract boolean isIntegral(); - public static JsonNumber of(BigDecimal value) { - return new BigDecimalImpl(value); + public static JsonDecimal of(BigDecimal value) { + return new JsonDecimalImpl(value.toString()); } - public static JsonNumber of(double value) { - return new DoubleImpl(value); + public static JsonDecimal of(double value) { + if (Double.isInfinite(value)) { + throw new IllegalArgumentException("JSON cannot encode an infinite value"); + } + if (Double.isNaN(value)) { + throw new IllegalArgumentException("JSON cannot encode a NaN"); + } + return new JsonDecimalImpl(BigDecimal.valueOf(value).toString()); } - public static JsonNumber of(long value) { - return new LongImpl(value); + public static JsonInteger of(long value) { + return new JsonIntegerImpl(BigDecimal.valueOf(value).toString()); } - public static JsonNumber of(float value) { - return new DoubleImpl(value); + public static JsonDecimal of(float value) { + if (Float.isInfinite(value)) { + throw new IllegalArgumentException("JSON cannot encode an infinite value"); + } + if (Float.isNaN(value)) { + throw new IllegalArgumentException("JSON cannot encode a NaN"); + } + return new JsonDecimalImpl(BigDecimal.valueOf(value).toString()); } - public static JsonNumber of(int value) { - return new LongImpl(value); + public static JsonInteger of(int value) { + return new JsonIntegerImpl(BigDecimal.valueOf(value).toString()); } - public static JsonNumber of(java.math.BigInteger value) { - return new BigIntegerImpl(value); + public static JsonInteger of(java.math.BigInteger value) { + return new JsonIntegerImpl(new BigDecimal(value).toString()); } @Override diff --git a/src/main/java/dev/mccue/json/JsonReadOptions.java b/src/main/java/dev/mccue/json/JsonReadOptions.java index 46613ca..7aebc18 100644 --- a/src/main/java/dev/mccue/json/JsonReadOptions.java +++ b/src/main/java/dev/mccue/json/JsonReadOptions.java @@ -6,28 +6,22 @@ * Options for customizing the process of reading Json. * * @param eofBehavior What to do if an attempted read reaches an EOF without any Json being read. - * @param useBigDecimals Whether to use BigDecimals when reading decimal numbers. * * @author Ethan McCue */ public record JsonReadOptions( - EOFBehavior eofBehavior, - boolean useBigDecimals + EOFBehavior eofBehavior ) { public JsonReadOptions { Objects.requireNonNull(eofBehavior, "eofBehavior must not be null"); } public JsonReadOptions() { - this(EOFBehavior.THROW_EXCEPTION, false); + this(EOFBehavior.THROW_EXCEPTION); } public JsonReadOptions withEOFBehavior(EOFBehavior eofBehavior) { - return new JsonReadOptions(eofBehavior, useBigDecimals); - } - - public JsonReadOptions withUseBigDecimals(boolean useBigDecimals) { - return new JsonReadOptions(eofBehavior, useBigDecimals); + return new JsonReadOptions(eofBehavior); } /** diff --git a/src/main/java/dev/mccue/json/internal/BigDecimalImpl.java b/src/main/java/dev/mccue/json/internal/BigDecimalImpl.java deleted file mode 100644 index dcba5f2..0000000 --- a/src/main/java/dev/mccue/json/internal/BigDecimalImpl.java +++ /dev/null @@ -1,102 +0,0 @@ -package dev.mccue.json.internal; - -import dev.mccue.json.Json; -import dev.mccue.json.JsonNumber; -import dev.mccue.json.serialization.JsonSerializationProxy; - -import java.io.Serial; -import java.math.BigInteger; -import java.util.Objects; - -@ValueCandidate -public final class BigDecimalImpl extends JsonNumber { - @Serial - private static final long serialVersionUID = 1L; - private final java.math.BigDecimal bigDecimalValue; - - public BigDecimalImpl(java.math.BigDecimal bigDecimalValue) { - this.bigDecimalValue = Objects.requireNonNull( - bigDecimalValue, - "bigDecimalValue must not be null." - ); - } - - @Override - public int intValue() { - return bigDecimalValue.intValue(); - } - - @Override - public long longValue() { - return bigDecimalValue.longValue(); - } - - @Override - public float floatValue() { - return bigDecimalValue.floatValue(); - } - - @Override - public double doubleValue() { - return bigDecimalValue.doubleValue(); - } - - @Override - public java.math.BigDecimal bigDecimalValue() { - return bigDecimalValue; - } - - @Override - public java.math.BigInteger bigIntegerValue() { - return bigDecimalValue.toBigInteger(); - } - - @Override - public int intValueExact() { - return bigDecimalValue.intValueExact(); - } - - @Override - public long longValueExact() { - return bigDecimalValue.longValueExact(); - } - - @Override - public BigInteger bigIntegerValueExact() { - return bigDecimalValue.toBigIntegerExact(); - } - - @Override - public boolean isIntegral() { - return bigDecimalValue.scale() == 0; - } - - @Override - public boolean equals(Object o) { - return (this == o) || ( - o instanceof BigDecimalImpl otherBigDecimal && - this.bigDecimalValue.equals(otherBigDecimal.bigDecimalValue) - ); - } - - @Override - public int hashCode() { - return this.bigDecimalValue.hashCode(); - } - - @Override - public java.lang.String toString() { - return this.bigDecimalValue.toString(); - } - - @Serial - private Object writeReplace() { - return new JsonSerializationProxy(Json.writeString(this)); - } - - @Serial - private Object readResolve() { - throw new IllegalStateException(); - } -} - diff --git a/src/main/java/dev/mccue/json/internal/DoubleImpl.java b/src/main/java/dev/mccue/json/internal/DoubleImpl.java deleted file mode 100644 index 85fea88..0000000 --- a/src/main/java/dev/mccue/json/internal/DoubleImpl.java +++ /dev/null @@ -1,116 +0,0 @@ -package dev.mccue.json.internal; - -import dev.mccue.json.Json; -import dev.mccue.json.JsonNumber; -import dev.mccue.json.serialization.JsonSerializationProxy; - -import java.io.Serial; -import java.math.BigDecimal; -import java.math.BigInteger; - -@ValueCandidate -public final class DoubleImpl extends JsonNumber { - @Serial - private static final long serialVersionUID = 1L; - - private final double doubleValue; - - public DoubleImpl(double doubleValue) { - if (Double.isInfinite(doubleValue)) { - throw new IllegalArgumentException("JSON cannot encode an infinite double"); - } - if (Double.isNaN(doubleValue)) { - throw new IllegalArgumentException("JSON cannot encode a NaN double"); - } - - this.doubleValue = doubleValue; - } - - @Override - public java.math.BigDecimal bigDecimalValue() { - return java.math.BigDecimal.valueOf(doubleValue); - } - - @Override - public java.math.BigInteger bigIntegerValue() { - return java.math.BigInteger.valueOf((long) doubleValue); - } - - @Override - public int intValueExact() { - if (((int) doubleValue) == doubleValue) { - return (int) doubleValue; - } - else { - throw new ArithmeticException(doubleValue + " cannot fit into an int"); - } - } - - @Override - public long longValueExact() { - if (((long) doubleValue) == doubleValue) { - return (int) doubleValue; - } - else { - throw new ArithmeticException(doubleValue + " cannot fit into an int"); - } - } - - @Override - public BigInteger bigIntegerValueExact() { - return BigDecimal.valueOf(doubleValue).toBigIntegerExact(); - } - - @Override - public boolean isIntegral() { - return (((int) doubleValue) == doubleValue); - } - - @Override - public int intValue() { - return (int) doubleValue; - } - - @Override - public long longValue() { - return (long) doubleValue; - } - - @Override - public float floatValue() { - return (float) doubleValue; - } - - @Override - public double doubleValue() { - return doubleValue; - } - - @Override - public boolean equals(Object o) { - return (this == o) || ( - o instanceof DoubleImpl otherDouble && - this.doubleValue == otherDouble.doubleValue - ); - } - - @Override - public int hashCode() { - return java.lang.Double.hashCode(this.doubleValue); - } - - @Override - public java.lang.String toString() { - return java.lang.Double.toString(this.doubleValue); - } - - @Serial - private Object writeReplace() { - return new JsonSerializationProxy(Json.writeString(this)); - } - - @Serial - private Object readResolve() { - throw new IllegalStateException(); - } -} diff --git a/src/main/java/dev/mccue/json/internal/JsonDecimalImpl.java b/src/main/java/dev/mccue/json/internal/JsonDecimalImpl.java new file mode 100644 index 0000000..e318295 --- /dev/null +++ b/src/main/java/dev/mccue/json/internal/JsonDecimalImpl.java @@ -0,0 +1,82 @@ +package dev.mccue.json.internal; + +import dev.mccue.json.Json; +import dev.mccue.json.JsonDecimal; +import dev.mccue.json.serialization.JsonSerializationProxy; + +import java.io.Serial; +import java.math.BigDecimal; +import java.math.BigInteger; + +public final class JsonDecimalImpl extends JsonDecimal { + private final String value; + + public JsonDecimalImpl(String value) { + this.value = value; + } + + @Override + public BigDecimal bigDecimalValue() { + return new BigDecimal(value); + } + + @Override + public int intValue() { + return bigDecimalValue().intValue(); + } + + @Override + public long longValue() { + return bigDecimalValue().longValue(); + } + + @Override + public float floatValue() { + return bigDecimalValue().floatValue(); + } + + @Override + public double doubleValue() { + return bigDecimalValue().doubleValue(); + } + + @Override + public java.math.BigInteger bigIntegerValue() { + return bigDecimalValue().toBigInteger(); + } + + @Override + public int intValueExact() { + return bigDecimalValue().intValueExact(); + } + + @Override + public long longValueExact() { + return bigDecimalValue().longValueExact(); + } + + @Override + public BigInteger bigIntegerValueExact() { + return bigDecimalValue().toBigIntegerExact(); + } + + @Override + public boolean isIntegral() { + return bigDecimalValue().scale() == 0; + } + + @Override + public java.lang.String toString() { + return this.value; + } + + @Serial + private Object writeReplace() { + return new JsonSerializationProxy(Json.writeString(this)); + } + + @Serial + private Object readResolve() { + throw new IllegalStateException(); + } +} diff --git a/src/main/java/dev/mccue/json/internal/BigIntegerImpl.java b/src/main/java/dev/mccue/json/internal/JsonIntegerImpl.java similarity index 51% rename from src/main/java/dev/mccue/json/internal/BigIntegerImpl.java rename to src/main/java/dev/mccue/json/internal/JsonIntegerImpl.java index d3e8bf6..2f4267f 100644 --- a/src/main/java/dev/mccue/json/internal/BigIntegerImpl.java +++ b/src/main/java/dev/mccue/json/internal/JsonIntegerImpl.java @@ -1,30 +1,30 @@ package dev.mccue.json.internal; import dev.mccue.json.Json; -import dev.mccue.json.JsonNumber; +import dev.mccue.json.JsonInteger; import dev.mccue.json.serialization.JsonSerializationProxy; import java.io.Serial; -import java.util.Objects; +import java.math.BigInteger; -@ValueCandidate -public final class BigIntegerImpl extends JsonNumber { +public final class JsonIntegerImpl extends JsonInteger { @Serial private static final long serialVersionUID = 1L; - private final java.math.BigInteger bigIntegerValue; - public BigIntegerImpl(java.math.BigInteger bigIntegerValue) { - this.bigIntegerValue = Objects.requireNonNull(bigIntegerValue, "value must not be null"); + private final String value; + + public JsonIntegerImpl(String value) { + this.value = value; } @Override public java.math.BigDecimal bigDecimalValue() { - return new java.math.BigDecimal(bigIntegerValue); + return new java.math.BigDecimal(bigIntegerValue()); } @Override public java.math.BigInteger bigIntegerValue() { - return bigIntegerValue; + return new BigInteger(value); } @Override @@ -34,12 +34,12 @@ public int intValueExact() { @Override public long longValueExact() { - return bigIntegerValue.longValueExact(); + return bigIntegerValue().longValueExact(); } @Override public java.math.BigInteger bigIntegerValueExact() { - return bigIntegerValue; + return bigIntegerValue(); } @Override @@ -49,40 +49,27 @@ public boolean isIntegral() { @Override public int intValue() { - return bigIntegerValue.intValue(); + return Integer.parseInt(value); } @Override public long longValue() { - return bigIntegerValue.longValue(); + return Long.parseLong(value); } @Override public float floatValue() { - return bigIntegerValue.floatValue(); + return Float.parseFloat(value); } @Override public double doubleValue() { - return bigIntegerValue.doubleValue(); - } - - @Override - public boolean equals(Object o) { - return (this == o) || ( - o instanceof BigIntegerImpl otherBigInteger && - this.bigIntegerValue.equals(otherBigInteger.bigIntegerValue) - ); - } - - @Override - public int hashCode() { - return this.bigIntegerValue.hashCode(); + return Double.parseDouble(value); } @Override public java.lang.String toString() { - return this.bigIntegerValue.toString(); + return this.value; } @Serial diff --git a/src/main/java/dev/mccue/json/internal/JsonReaderMethods.java b/src/main/java/dev/mccue/json/internal/JsonReaderMethods.java index cf34be3..b42767a 100644 --- a/src/main/java/dev/mccue/json/internal/JsonReaderMethods.java +++ b/src/main/java/dev/mccue/json/internal/JsonReaderMethods.java @@ -2,18 +2,16 @@ import dev.mccue.json.Json; -import dev.mccue.json.JsonReadOptions; -import dev.mccue.json.stream.JsonArrayHandler; import dev.mccue.json.JsonNumber; import dev.mccue.json.JsonReadException; +import dev.mccue.json.JsonReadOptions; +import dev.mccue.json.stream.JsonArrayHandler; import dev.mccue.json.stream.JsonStreamReadOptions; import dev.mccue.json.stream.JsonValueHandler; import org.jspecify.annotations.Nullable; import java.io.IOException; import java.io.PushbackReader; -import java.math.BigDecimal; -import java.math.BigInteger; public final class JsonReaderMethods { private JsonReaderMethods() {} @@ -84,28 +82,14 @@ private static String readQuotedString(PushbackReader stream) throws IOException } private static JsonNumber readInteger(String string) { - if (string.length() < 18) { // definitely fits in a Long - return JsonNumber.of(Long.parseLong(string)); - } - else { - try { - return JsonNumber.of(Long.parseLong(string)); - } catch (NumberFormatException __) { - return JsonNumber.of(new BigInteger(string)); - } - } + return new JsonIntegerImpl(string); } - private static JsonNumber readDecimal(String string, boolean bigDecimal) { - if (bigDecimal) { - return new BigDecimalImpl(new BigDecimal(string)); - } - else { - return new DoubleImpl(Double.parseDouble(string)); - } + private static JsonNumber readDecimal(String string) { + return new JsonDecimalImpl(string); } - private static JsonNumber readNumber(PushbackReader stream, boolean bigDecimal) throws IOException { + private static JsonNumber readNumber(PushbackReader stream) throws IOException { var buffer = new StringBuilder(); enum Stage { @@ -304,7 +288,7 @@ enum Stage { } if (isDecimal) { - return readDecimal(buffer.toString(), bigDecimal); + return readDecimal(buffer.toString()); } else { return readInteger(buffer.toString()); @@ -448,7 +432,7 @@ public static void readStream( switch (c) { case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { stream.unread(c); - valueHandler.onNumber(readNumber(stream, options.useBigDecimals())); + valueHandler.onNumber(readNumber(stream)); } case '"' -> { valueHandler.onString(readQuotedString(stream)); @@ -498,7 +482,7 @@ public static void readStream( public static Json read(PushbackReader stream, JsonReadOptions options) throws IOException { var handler = new Handlers.BaseTreeValueHandler(); - readStream(stream, false, new JsonStreamReadOptions(options.useBigDecimals()), handler); + readStream(stream, false, new JsonStreamReadOptions(), handler); if (handler.result == null && options.eofBehavior() == JsonReadOptions.EOFBehavior.THROW_EXCEPTION) { throw JsonReadException.unexpectedEOF(); } diff --git a/src/main/java/dev/mccue/json/internal/JsonWriter.java b/src/main/java/dev/mccue/json/internal/JsonWriter.java index 499e7bc..aa7ac97 100644 --- a/src/main/java/dev/mccue/json/internal/JsonWriter.java +++ b/src/main/java/dev/mccue/json/internal/JsonWriter.java @@ -1,32 +1,12 @@ package dev.mccue.json.internal; import dev.mccue.json.*; -import dev.mccue.json.internal.*; import java.io.IOException; import java.util.IdentityHashMap; public final class JsonWriter { public JsonWriter() {} - private interface Writer { - void write(Json v, Appendable out, OptionsWithIndentDepth options) throws IOException; - } - - private static final IdentityHashMap, Writer> WRITERS; - - static { - WRITERS = new IdentityHashMap<>(); - WRITERS.put(JsonNull.class, (__, out, ___) -> out.append("null")); - WRITERS.put(JsonTrue.class, (__, out, ___) -> out.append("true")); - WRITERS.put(JsonFalse.class, (__, out, ___) -> out.append("false")); - WRITERS.put(LongImpl.class, (v, out, ___) -> out.append(v.toString())); - WRITERS.put(DoubleImpl.class, (v, out, ___) -> out.append(v.toString())); - WRITERS.put(BigIntegerImpl.class, (v, out, ___) -> out.append(v.toString())); - WRITERS.put(BigDecimalImpl.class, (v, out, ___) -> out.append(v.toString())); - WRITERS.put(StringImpl.class, (v, out, options) -> writeString((JsonString) v, out, options)); - WRITERS.put(ArrayImpl.class, (v, out, options) -> writeArray((JsonArray) v, out, options)); - WRITERS.put(ObjectImpl.class, (v, out, options) -> writeObject((JsonObject) v, out, options)); - } private static final short[] CODEPOINT_DECODER; @@ -203,7 +183,15 @@ static void writeArray(JsonArray a, Appendable out, OptionsWithIndentDepth optio static void write(Json v, Appendable out, OptionsWithIndentDepth options) throws IOException { - WRITERS.get(v.getClass()).write(v, out, options); + switch (v) { + case JsonNull __ -> out.append("null"); + case JsonTrue __ -> out.append("true"); + case JsonFalse __ -> out.append("false"); + case JsonNumber number -> out.append(number.toString()); + case JsonString string -> writeString(string, out, options); + case JsonArray array -> writeArray(array, out, options); + case JsonObject object -> writeObject(object, out, options); + } } public record OptionsWithIndentDepth( diff --git a/src/main/java/dev/mccue/json/internal/LongImpl.java b/src/main/java/dev/mccue/json/internal/LongImpl.java deleted file mode 100644 index 2570013..0000000 --- a/src/main/java/dev/mccue/json/internal/LongImpl.java +++ /dev/null @@ -1,103 +0,0 @@ -package dev.mccue.json.internal; - -import dev.mccue.json.Json; -import dev.mccue.json.JsonNumber; -import dev.mccue.json.serialization.JsonSerializationProxy; - -import java.io.Serial; -import java.math.BigInteger; - -@ValueCandidate -public final class LongImpl extends JsonNumber { - @Serial - private static final long serialVersionUID = 1L; - private final long longValue; - - public LongImpl(long longValue) { - this.longValue = longValue; - } - - @Override - public java.math.BigDecimal bigDecimalValue() { - return java.math.BigDecimal.valueOf(longValue); - } - - @Override - public java.math.BigInteger bigIntegerValue() { - return java.math.BigInteger.valueOf(longValue); - } - - @Override - public int intValueExact() { - if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) { - return (int) longValue; - } - else { - throw new ArithmeticException(longValue + " cannot fit into an int."); - } - } - - @Override - public long longValueExact() { - return longValue; - } - - @Override - public BigInteger bigIntegerValueExact() { - return BigInteger.valueOf(longValue); - } - - @Override - public boolean isIntegral() { - return true; - } - - - @Override - public int intValue() { - return (int) longValue; - } - - @Override - public long longValue() { - return longValue; - } - - @Override - public float floatValue() { - return (float) longValue; - } - - @Override - public double doubleValue() { - return (double) longValue; - } - - @Override - public boolean equals(Object o) { - return (this == o) || ( - o instanceof LongImpl otherLong && - this.longValue == otherLong.longValue - ); - } - - @Override - public int hashCode() { - return java.lang.Long.hashCode(this.longValue); - } - - @Override - public java.lang.String toString() { - return java.lang.Long.toString(longValue); - } - - @Serial - private Object writeReplace() { - return new JsonSerializationProxy(Json.writeString(this)); - } - - @Serial - private Object readResolve() { - throw new IllegalStateException(); - } -} diff --git a/src/main/java/dev/mccue/json/stream/JsonStreamReadOptions.java b/src/main/java/dev/mccue/json/stream/JsonStreamReadOptions.java index 9d873f0..138713f 100644 --- a/src/main/java/dev/mccue/json/stream/JsonStreamReadOptions.java +++ b/src/main/java/dev/mccue/json/stream/JsonStreamReadOptions.java @@ -1,14 +1,7 @@ package dev.mccue.json.stream; -public record JsonStreamReadOptions( - boolean useBigDecimals -) { +public final class JsonStreamReadOptions { public JsonStreamReadOptions() { - this(false); - } - - public JsonStreamReadOptions withUseBigDecimals(boolean useBigDecimals) { - return new JsonStreamReadOptions(useBigDecimals); } } diff --git a/src/test/java/dev/mccue/json/JsonParsingTest.java b/src/test/java/dev/mccue/json/JsonParsingTest.java index 9dc33b8..8782534 100644 --- a/src/test/java/dev/mccue/json/JsonParsingTest.java +++ b/src/test/java/dev/mccue/json/JsonParsingTest.java @@ -3,13 +3,14 @@ import org.junit.jupiter.api.Test; import java.io.StringReader; +import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Random; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; public final class JsonParsingTest { @Test @@ -337,4 +338,42 @@ public void testReadMultipleTopLevel() { forms ); } + + @Test + public void testExtremelyBigNumber() { + assertEquals( + JsonDecimal.of(new BigDecimal("1231231234124125412532523452345.4325342523452353245345345")), + Json.readString("1231231234124125412532523452345.4325342523452353245345345") + ); + } + + @Test + public void testNumberEquivalences() { + assertEquals( + Json.of(new BigInteger("3")), + Json.of(new BigDecimal("3")) + ); + + assertNotEquals( + Json.of(new BigInteger("3")), + Json.of(new BigDecimal("3.0")) + ); + + assertEquals( + Json.of(new BigInteger("3")), + Json.of(3) + ); + + assertNotEquals( + Json.of(3.0), + Json.of(3) + ); + + assertEquals( + Json.of(3.0f), + Json.of(3.0) + ); + } + + }