Skip to content

Commit

Permalink
provide NaN and Infinity for reading
Browse files Browse the repository at this point in the history
Signed-off-by: Jorge Bescos Gascon <[email protected]>
  • Loading branch information
jbescos committed Sep 24, 2021
1 parent fd48e04 commit 86811ef
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 16 deletions.
10 changes: 5 additions & 5 deletions impl/src/main/java/org/eclipse/parsson/JsonGeneratorImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ public JsonGenerator write(String name, double value) {
throw new JsonGenerationException(
JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
}
NaNInfinite normalNaNInfinite = NaNInfinite.get(value);
Object result = normalNaNInfinite == null ? value : normalNaNInfinite.processValue(writeNanAsNulls, writeNanAsStrings, value);
NaNInfinite nanInfinite = NaNInfinite.get(value);
Object result = nanInfinite == null ? value : nanInfinite.processValue(writeNanAsNulls, writeNanAsStrings, value);
writeName(name);
writeString(String.valueOf(result));
return this;
Expand Down Expand Up @@ -409,11 +409,11 @@ public JsonGenerator write(long value) {
@Override
public JsonGenerator write(double value) {
checkContextForValue();
NaNInfinite normalNaNInfinite = NaNInfinite.get(value);
if (normalNaNInfinite == null) {
NaNInfinite nanInfinite = NaNInfinite.get(value);
if (nanInfinite == null) {
writeValue(String.valueOf(value));
} else {
Object result = normalNaNInfinite.processValue(writeNanAsNulls, writeNanAsStrings, value);
Object result = nanInfinite.processValue(writeNanAsNulls, writeNanAsStrings, value);
writeValue(String.valueOf(result));
}
popFieldContext();
Expand Down
53 changes: 50 additions & 3 deletions impl/src/main/java/org/eclipse/parsson/JsonNumberImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,42 @@ static JsonNumber getJsonNumber(BigInteger value) {
}

static JsonNumber getJsonNumber(double value) {
NaNInfinite normalNaNInfinite = NaNInfinite.get(value);
if (normalNaNInfinite == null) {
NaNInfinite nanInfinite = NaNInfinite.get(value);
if (nanInfinite == null) {
//bigDecimal = new BigDecimal(value);
// This is the preferred way to convert double to BigDecimal
return new JsonBigDecimalNumber(BigDecimal.valueOf(value));
} else {
return new JsonNaNInfiniteNumber(value, normalNaNInfinite);
return JsonNaNInfiniteNumber.get(nanInfinite);
}
}

static JsonNumber getJsonNumber(BigDecimal value) {
return new JsonBigDecimalNumber(value);
}

static final class JsonNullNumber extends JsonNumberImpl {

static final JsonNullNumber NULL = new JsonNullNumber();

private JsonNullNumber() {}

@Override
public Number numberValue() {
return null;
}

@Override
public boolean isIntegral() {
return false;
}

@Override
public BigDecimal bigDecimalValue() {
throw new NullPointerException("Value is null");
}
}

// Optimized JsonNumber impl for int numbers.
private static final class JsonIntNumber extends JsonNumberImpl {
private final int num;
Expand Down Expand Up @@ -184,6 +206,9 @@ public String toString() {

static final class JsonNaNInfiniteNumber extends JsonNumberImpl {

private static final JsonNaNInfiniteNumber NAN = new JsonNaNInfiniteNumber(Double.NaN, NaNInfinite.NAN);
private static final JsonNaNInfiniteNumber POSITIVE_INFINITY = new JsonNaNInfiniteNumber(Double.POSITIVE_INFINITY, NaNInfinite.POSITIVE_INFINITY);
private static final JsonNaNInfiniteNumber NEGATIVE_INFINITY = new JsonNaNInfiniteNumber(Double.NEGATIVE_INFINITY, NaNInfinite.NEGATIVE_INFINITY);
private final double num;
private final NaNInfinite naNInfinite;

Expand All @@ -196,16 +221,38 @@ NaNInfinite naNInfinite() {
return naNInfinite;
}

@Override
public boolean isIntegral() {
return false;
}

@Override
public double doubleValue() {
return num;
}

@Override
public Number numberValue() {
return num;
}

@Override
public BigDecimal bigDecimalValue() {
// Every other method in this class that is not overridden will fail because of this exception
throw new UnsupportedOperationException("Value is " + num);
}

static JsonNaNInfiniteNumber get(NaNInfinite nanInfinite) {
if (nanInfinite == NaNInfinite.NAN) {
return NAN;
} else if (nanInfinite == NaNInfinite.NEGATIVE_INFINITY) {
return NEGATIVE_INFINITY;
} else if (nanInfinite == NaNInfinite.POSITIVE_INFINITY) {
return POSITIVE_INFINITY;
} else {
throw new IllegalArgumentException(nanInfinite + " is not known");
}
}
}

// JsonNumber impl using BigDecimal numbers.
Expand Down
36 changes: 31 additions & 5 deletions impl/src/main/java/org/eclipse/parsson/JsonObjectBuilderImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,29 @@

package org.eclipse.parsson;

import org.eclipse.parsson.api.BufferPool;

import jakarta.json.*;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import org.eclipse.parsson.JsonNumberImpl.JsonNaNInfiniteNumber;
import org.eclipse.parsson.JsonNumberImpl.JsonNullNumber;
import org.eclipse.parsson.JsonUtil.NaNInfinite;
import org.eclipse.parsson.api.BufferPool;

import jakarta.json.JsonArray;
import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonNumber;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
import jakarta.json.JsonString;
import jakarta.json.JsonValue;
import jakarta.json.JsonWriter;

/**
* JsonObjectBuilder implementation
Expand Down Expand Up @@ -246,7 +262,17 @@ public JsonObject getJsonObject(String name) {

@Override
public JsonNumber getJsonNumber(String name) {
return (JsonNumber)get(name);
JsonValue value = get(name);
if (value.getValueType() == ValueType.NULL) {
return JsonNullNumber.NULL;
} else {
NaNInfinite nanInfinite = null;
if (value.getValueType() == ValueType.STRING && (nanInfinite = NaNInfinite.get(value.toString())) != null) {
return JsonNaNInfiniteNumber.get(nanInfinite);
} else {
return (JsonNumber)get(name);
}
}
}

@Override
Expand Down
9 changes: 9 additions & 0 deletions impl/src/main/java/org/eclipse/parsson/JsonUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,15 @@ static NaNInfinite get(double value) {
return null;
}
}

static NaNInfinite get(String value) {
for (NaNInfinite item : NaNInfinite.values()) {
if (item.strVal.equals(value)) {
return item;
}
}
return null;
}
}
}

20 changes: 17 additions & 3 deletions impl/src/test/java/org/eclipse/parsson/tests/JsonReaderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,15 @@
import java.util.HashMap;
import java.util.Map;

import org.eclipse.parsson.api.BufferPool;

import jakarta.json.Json;
import jakarta.json.JsonArray;
import jakarta.json.JsonNumber;
import jakarta.json.JsonObject;
import jakarta.json.JsonReader;
import jakarta.json.JsonReaderFactory;
import jakarta.json.JsonValue;

import org.eclipse.parsson.api.BufferPool;

import junit.framework.TestCase;

/**
Expand Down Expand Up @@ -204,4 +203,19 @@ public void testEmptyStringUsingBuffers() throws Throwable {
}
}

public void testNanInfinity() {
// Configuration is irrelevant for reading, it just understands how to parse it.
Map<String, Object> config = new HashMap<>();
JsonReaderFactory factory = Json.createReaderFactory(config);
String json = "{\"val1\":null,\"val2\":1.0,\"val3\":0.0,\"val4\":\"NaN\",\"val5\":\"+Infinity\",\"val6\":\"-Infinity\"}";
JsonReader reader = factory.createReader(new StringReader(json));
JsonObject object = reader.readObject();
reader.close();
assertEquals(null, object.getJsonNumber("val1").numberValue());
assertEquals(1.0, object.getJsonNumber("val2").doubleValue());
assertEquals(0.0, object.getJsonNumber("val3").doubleValue());
assertTrue(Double.isNaN(object.getJsonNumber("val4").doubleValue()));
assertEquals(Double.POSITIVE_INFINITY, object.getJsonNumber("val5").doubleValue());
assertEquals(Double.NEGATIVE_INFINITY, object.getJsonNumber("val6").doubleValue());
}
}

0 comments on commit 86811ef

Please sign in to comment.