Skip to content

Commit f2ab7f1

Browse files
committed
Handle NaNInfinite in JsonNumber
Signed-off-by: Jorge Bescos Gascon <[email protected]>
1 parent a0f1731 commit f2ab7f1

File tree

4 files changed

+180
-53
lines changed

4 files changed

+180
-53
lines changed

impl/src/main/java/org/eclipse/parsson/JsonGeneratorImpl.java

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616

1717
package org.eclipse.parsson;
1818

19-
import org.eclipse.parsson.JsonUtil.NormalNaNInfinite;
19+
import org.eclipse.parsson.JsonNumberImpl.JsonNaNInfiniteNumber;
20+
import org.eclipse.parsson.JsonUtil.NaNInfinite;
2021
import org.eclipse.parsson.api.BufferPool;
2122

2223
import jakarta.json.*;
@@ -191,8 +192,8 @@ public JsonGenerator write(String name, double value) {
191192
throw new JsonGenerationException(
192193
JsonMessages.GENERATOR_ILLEGAL_METHOD(currentContext.scope));
193194
}
194-
NormalNaNInfinite normalNaNInfinite = NormalNaNInfinite.get(value);
195-
Object result = normalNaNInfinite.processValue(writeNanAsNulls, writeNanAsStrings, value);
195+
NaNInfinite normalNaNInfinite = NaNInfinite.get(value);
196+
Object result = normalNaNInfinite == null ? value : normalNaNInfinite.processValue(writeNanAsNulls, writeNanAsStrings, value);
196197
writeName(name);
197198
writeString(String.valueOf(result));
198199
return this;
@@ -269,7 +270,17 @@ public JsonGenerator write(JsonValue value) {
269270
break;
270271
case NUMBER:
271272
JsonNumber number = (JsonNumber)value;
272-
writeValue(number.toString());
273+
if (number instanceof JsonNaNInfiniteNumber) {
274+
JsonNaNInfiniteNumber nanInfinite = (JsonNaNInfiniteNumber) number;
275+
String val = nanInfinite.naNInfinite().processValue(writeNanAsNulls, writeNanAsStrings, nanInfinite.doubleValue());
276+
if (val == null) {
277+
writeNull();
278+
} else {
279+
writeValue(val);
280+
}
281+
} else {
282+
writeValue(number.toString());
283+
}
273284
popFieldContext();
274285
break;
275286
case TRUE:
@@ -343,7 +354,17 @@ public JsonGenerator write(String name, JsonValue value) {
343354
break;
344355
case NUMBER:
345356
JsonNumber number = (JsonNumber)value;
346-
writeValue(name, number.toString());
357+
if (number instanceof JsonNaNInfiniteNumber) {
358+
JsonNaNInfiniteNumber nanInfinite = (JsonNaNInfiniteNumber) number;
359+
String val = nanInfinite.naNInfinite().processValue(writeNanAsNulls, writeNanAsStrings, nanInfinite.doubleValue());
360+
if (val == null) {
361+
writeNull(name);
362+
} else {
363+
writeValue(name, val);
364+
}
365+
} else {
366+
writeValue(name, number.toString());
367+
}
347368
break;
348369
case TRUE:
349370
write(name, true);
@@ -388,9 +409,13 @@ public JsonGenerator write(long value) {
388409
@Override
389410
public JsonGenerator write(double value) {
390411
checkContextForValue();
391-
NormalNaNInfinite normalNaNInfinite = NormalNaNInfinite.get(value);
392-
Object result = normalNaNInfinite.processValue(writeNanAsNulls, writeNanAsStrings, value);
393-
writeValue(String.valueOf(result));
412+
NaNInfinite normalNaNInfinite = NaNInfinite.get(value);
413+
if (normalNaNInfinite == null) {
414+
writeValue(String.valueOf(value));
415+
} else {
416+
Object result = normalNaNInfinite.processValue(writeNanAsNulls, writeNanAsStrings, value);
417+
writeValue(String.valueOf(result));
418+
}
394419
popFieldContext();
395420
return this;
396421
}

impl/src/main/java/org/eclipse/parsson/JsonNumberImpl.java

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import java.math.BigDecimal;
2121
import java.math.BigInteger;
2222

23+
import org.eclipse.parsson.JsonUtil.NaNInfinite;
24+
2325
/**
2426
* JsonNumber impl. Subclasses provide optimized implementations
2527
* when backed by int, long, BigDecimal
@@ -43,9 +45,14 @@ static JsonNumber getJsonNumber(BigInteger value) {
4345
}
4446

4547
static JsonNumber getJsonNumber(double value) {
46-
//bigDecimal = new BigDecimal(value);
47-
// This is the preferred way to convert double to BigDecimal
48-
return new JsonBigDecimalNumber(BigDecimal.valueOf(value));
48+
NaNInfinite normalNaNInfinite = NaNInfinite.get(value);
49+
if (normalNaNInfinite == null) {
50+
//bigDecimal = new BigDecimal(value);
51+
// This is the preferred way to convert double to BigDecimal
52+
return new JsonBigDecimalNumber(BigDecimal.valueOf(value));
53+
} else {
54+
return new JsonNaNInfiniteNumber(value, normalNaNInfinite);
55+
}
4956
}
5057

5158
static JsonNumber getJsonNumber(BigDecimal value) {
@@ -175,6 +182,32 @@ public String toString() {
175182

176183
}
177184

185+
static final class JsonNaNInfiniteNumber extends JsonNumberImpl {
186+
187+
private final double num;
188+
private final NaNInfinite naNInfinite;
189+
190+
private JsonNaNInfiniteNumber(double num, NaNInfinite naNInfinite) {
191+
this.num = num;
192+
this.naNInfinite = naNInfinite;
193+
}
194+
195+
NaNInfinite naNInfinite() {
196+
return naNInfinite;
197+
}
198+
199+
@Override
200+
public double doubleValue() {
201+
return num;
202+
}
203+
204+
@Override
205+
public BigDecimal bigDecimalValue() {
206+
// Every other method in this class that is not overridden will fail because of this exception
207+
throw new UnsupportedOperationException("Value is " + num);
208+
}
209+
}
210+
178211
// JsonNumber impl using BigDecimal numbers.
179212
private static final class JsonBigDecimalNumber extends JsonNumberImpl {
180213
private final BigDecimal bigDecimal;

impl/src/main/java/org/eclipse/parsson/JsonUtil.java

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -92,40 +92,35 @@ static boolean getConfigValue(String key, boolean defaultValue, Map<String, ?> c
9292
return defaultValue;
9393
}
9494

95-
static enum NormalNaNInfinite {
96-
NORMAL(null), NAN("\"NaN\""), ININITE_PLUS("\"+Infinity\""), INFINITE_MINUS("\"-Infinity\"");
95+
static enum NaNInfinite {
96+
NAN("\"NaN\""), POSITIVE_INFINITY("\"+Infinity\""), NEGATIVE_INFINITY("\"-Infinity\"");
9797

9898
private final String strVal;
9999

100-
private NormalNaNInfinite(String strVal) {
100+
private NaNInfinite(String strVal) {
101101
this.strVal = strVal;
102102
}
103103

104-
Object processValue(boolean writeNanAsNulls, boolean writeNanAsStrings, double value) {
105-
if (this == NormalNaNInfinite.NORMAL) {
106-
return value;
104+
String processValue(boolean writeNanAsNulls, boolean writeNanAsStrings, double value) {
105+
if (writeNanAsNulls) {
106+
return null;
107+
} else if (writeNanAsStrings) {
108+
return strVal;
107109
} else {
108-
if (writeNanAsNulls) {
109-
return null;
110-
} else if (writeNanAsStrings) {
111-
return strVal;
112-
} else {
113-
throw new NumberFormatException(JsonMessages.GENERATOR_DOUBLE_INFINITE_NAN());
114-
}
110+
throw new NumberFormatException(JsonMessages.GENERATOR_DOUBLE_INFINITE_NAN());
115111
}
116112
}
117113

118-
static NormalNaNInfinite get(double value) {
114+
static NaNInfinite get(double value) {
119115
if (Double.isNaN(value)) {
120116
return NAN;
121-
} else if (Double.isInfinite(value)) {
122-
if (Double.compare(value, 0.0) < 0) {
123-
return INFINITE_MINUS;
124-
} else {
125-
return ININITE_PLUS;
126-
}
117+
} else if (Double.NEGATIVE_INFINITY == value) {
118+
return NEGATIVE_INFINITY;
119+
} else if (Double.POSITIVE_INFINITY == value) {
120+
return POSITIVE_INFINITY;
121+
} else {
122+
return null;
127123
}
128-
return NORMAL;
129124
}
130125
}
131126
}

impl/src/test/java/org/eclipse/parsson/tests/JsonGeneratorTest.java

Lines changed: 95 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,30 @@
1616

1717
package org.eclipse.parsson.tests;
1818

19-
import junit.framework.TestCase;
20-
import org.eclipse.parsson.api.BufferPool;
21-
22-
import jakarta.json.*;
23-
import jakarta.json.stream.*;
24-
import java.io.*;
19+
import java.io.BufferedReader;
20+
import java.io.ByteArrayInputStream;
21+
import java.io.ByteArrayOutputStream;
22+
import java.io.StringReader;
23+
import java.io.StringWriter;
24+
import java.io.Writer;
2525
import java.util.HashMap;
2626
import java.util.Map;
2727
import java.util.Random;
2828

29+
import org.eclipse.parsson.api.BufferPool;
30+
31+
import jakarta.json.Json;
32+
import jakarta.json.JsonArray;
33+
import jakarta.json.JsonBuilderFactory;
34+
import jakarta.json.JsonObject;
35+
import jakarta.json.JsonReader;
36+
import jakarta.json.JsonReaderFactory;
37+
import jakarta.json.JsonValue;
38+
import jakarta.json.stream.JsonGenerationException;
39+
import jakarta.json.stream.JsonGenerator;
40+
import jakarta.json.stream.JsonGeneratorFactory;
41+
import junit.framework.TestCase;
42+
2943
/**
3044
* {@link JsonGenerator} tests
3145
*
@@ -536,8 +550,7 @@ public void testFlush() throws Exception {
536550
assertEquals("{}", baos.toString("UTF-8"));
537551
}
538552

539-
private String nameValueNanInfinity(Map<String, Object> config) {
540-
JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(config);
553+
private String nameValueNanInfinity(JsonGeneratorFactory generatorFactory) {
541554
StringWriter writer = new StringWriter();
542555
JsonGenerator generator = generatorFactory.createGenerator(writer);
543556
generator
@@ -547,57 +560,118 @@ private String nameValueNanInfinity(Map<String, Object> config) {
547560
.write("val3", 0.0)
548561
.write("val4", Double.POSITIVE_INFINITY)
549562
.write("val5", Double.NEGATIVE_INFINITY)
563+
.write("val6", Json.createValue(Double.NaN))
564+
.write("val7", Json.createValue(1.0))
565+
.write("val8", Json.createValue(0.0))
566+
.write("val9", Json.createValue(Double.POSITIVE_INFINITY))
567+
.write("val10", Json.createValue(Double.NEGATIVE_INFINITY))
550568
.writeEnd().close();
551569
return writer.toString();
552570
}
553571

554-
private String valueNanInfinity(Map<String, Object> config) {
555-
JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(config);
572+
private String valueNanInfinity(JsonGeneratorFactory generatorFactory, double value) {
556573
StringWriter writer = new StringWriter();
557574
JsonGenerator generator = generatorFactory.createGenerator(writer);
558-
generator.write(Double.NaN).close();
575+
generator.write(value).close();
576+
return writer.toString();
577+
}
578+
579+
private String jsonNumberNanInfinity(JsonGeneratorFactory generatorFactory, double value) {
580+
StringWriter writer = new StringWriter();
581+
JsonGenerator generator = generatorFactory.createGenerator(writer);
582+
generator.write(Json.createValue(value)).close();
559583
return writer.toString();
560584
}
561585

562586
public void testNanInfinityDefault() {
563587
Map<String, Object> config = new HashMap<>();
564-
assertEquals("{\"val1\":null,\"val2\":1.0,\"val3\":0.0,\"val4\":null,\"val5\":null}", nameValueNanInfinity(config));
565-
assertEquals("null", valueNanInfinity(config));
588+
JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(config);
589+
assertEquals("{\"val1\":null,\"val2\":1.0,\"val3\":0.0,\"val4\":null,\"val5\":null,\"val6\":null,\"val7\":1.0,\"val8\":0.0,\"val9\":null,\"val10\":null}", nameValueNanInfinity(generatorFactory));
590+
assertEquals("0.0", valueNanInfinity(generatorFactory, 0.0));
591+
assertEquals("1.0", valueNanInfinity(generatorFactory, 1.0));
592+
assertEquals("null", valueNanInfinity(generatorFactory, Double.NaN));
593+
assertEquals("null", valueNanInfinity(generatorFactory, Double.POSITIVE_INFINITY));
594+
assertEquals("null", valueNanInfinity(generatorFactory, Double.NEGATIVE_INFINITY));
595+
assertEquals("0.0", jsonNumberNanInfinity(generatorFactory, 0.0));
596+
assertEquals("1.0", jsonNumberNanInfinity(generatorFactory, 1.0));
597+
assertEquals("null", jsonNumberNanInfinity(generatorFactory, Double.NaN));
598+
assertEquals("null", jsonNumberNanInfinity(generatorFactory, Double.POSITIVE_INFINITY));
599+
assertEquals("null", jsonNumberNanInfinity(generatorFactory, Double.NEGATIVE_INFINITY));
566600
}
567601

568602
public void testNanInfinityWriteNanAsNull() {
569603
Map<String, Object> config = new HashMap<>();
570604
config.put(JsonGenerator.WRITE_NAN_AS_NULLS, true);
571-
assertEquals("{\"val1\":null,\"val2\":1.0,\"val3\":0.0,\"val4\":null,\"val5\":null}", nameValueNanInfinity(config));
572-
assertEquals("null", valueNanInfinity(config));
605+
JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(config);
606+
assertEquals("{\"val1\":null,\"val2\":1.0,\"val3\":0.0,\"val4\":null,\"val5\":null,\"val6\":null,\"val7\":1.0,\"val8\":0.0,\"val9\":null,\"val10\":null}", nameValueNanInfinity(generatorFactory));
607+
assertEquals("0.0", valueNanInfinity(generatorFactory, 0.0));
608+
assertEquals("1.0", valueNanInfinity(generatorFactory, 1.0));
609+
assertEquals("null", valueNanInfinity(generatorFactory, Double.NaN));
610+
assertEquals("null", valueNanInfinity(generatorFactory, Double.POSITIVE_INFINITY));
611+
assertEquals("null", valueNanInfinity(generatorFactory, Double.NEGATIVE_INFINITY));
612+
assertEquals("0.0", jsonNumberNanInfinity(generatorFactory, 0.0));
613+
assertEquals("1.0", jsonNumberNanInfinity(generatorFactory, 1.0));
614+
assertEquals("null", jsonNumberNanInfinity(generatorFactory, Double.NaN));
615+
assertEquals("null", jsonNumberNanInfinity(generatorFactory, Double.POSITIVE_INFINITY));
616+
assertEquals("null", jsonNumberNanInfinity(generatorFactory, Double.NEGATIVE_INFINITY));
573617
}
574618

575619
public void testNanInfinityWriteNanAsString() {
576620
Map<String, Object> config = new HashMap<>();
577621
config.put(JsonGenerator.WRITE_NAN_AS_STRINGS, true);
578-
assertEquals("{\"val1\":\"NaN\",\"val2\":1.0,\"val3\":0.0,\"val4\":\"+Infinity\",\"val5\":\"-Infinity\"}", nameValueNanInfinity(config));
579-
assertEquals("\"NaN\"", valueNanInfinity(config));
622+
JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(config);
623+
assertEquals("{\"val1\":\"NaN\",\"val2\":1.0,\"val3\":0.0,\"val4\":\"+Infinity\",\"val5\":\"-Infinity\",\"val6\":\"NaN\",\"val7\":1.0,\"val8\":0.0,\"val9\":\"+Infinity\",\"val10\":\"-Infinity\"}", nameValueNanInfinity(generatorFactory));
624+
assertEquals("0.0", valueNanInfinity(generatorFactory, 0.0));
625+
assertEquals("1.0", valueNanInfinity(generatorFactory, 1.0));
626+
assertEquals("\"NaN\"", valueNanInfinity(generatorFactory, Double.NaN));
627+
assertEquals("\"+Infinity\"", valueNanInfinity(generatorFactory, Double.POSITIVE_INFINITY));
628+
assertEquals("\"-Infinity\"", valueNanInfinity(generatorFactory, Double.NEGATIVE_INFINITY));
629+
assertEquals("0.0", jsonNumberNanInfinity(generatorFactory, 0.0));
630+
assertEquals("1.0", jsonNumberNanInfinity(generatorFactory, 1.0));
631+
assertEquals("\"NaN\"", jsonNumberNanInfinity(generatorFactory, Double.NaN));
632+
assertEquals("\"+Infinity\"", jsonNumberNanInfinity(generatorFactory, Double.POSITIVE_INFINITY));
633+
assertEquals("\"-Infinity\"", jsonNumberNanInfinity(generatorFactory, Double.NEGATIVE_INFINITY));
580634
}
581635

582636
public void testNanInfinityBothFalse() {
583637
Map<String, Object> config = new HashMap<>();
584638
config.put(JsonGenerator.WRITE_NAN_AS_STRINGS, false);
585639
config.put(JsonGenerator.WRITE_NAN_AS_NULLS, false);
640+
JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(config);
586641
try {
587-
nameValueNanInfinity(config);
642+
nameValueNanInfinity(generatorFactory);
588643
fail("Expected a failure");
589644
} catch (NumberFormatException e) {}
590645
try {
591-
valueNanInfinity(config);
646+
valueNanInfinity(generatorFactory, Double.NaN);
592647
fail("Expected a failure");
593648
} catch (NumberFormatException e) {}
649+
assertEquals("0.0", valueNanInfinity(generatorFactory, 0.0));
650+
assertEquals("1.0", valueNanInfinity(generatorFactory, 1.0));
651+
try {
652+
jsonNumberNanInfinity(generatorFactory, Double.NaN);
653+
fail("Expected a failure");
654+
} catch (NumberFormatException e) {}
655+
assertEquals("0.0", jsonNumberNanInfinity(generatorFactory, 0.0));
656+
assertEquals("1.0", jsonNumberNanInfinity(generatorFactory, 1.0));
594657
}
595658

596659
public void testNanInfinityBothTrue() {
597660
Map<String, Object> config = new HashMap<>();
598661
config.put(JsonGenerator.WRITE_NAN_AS_STRINGS, true);
599662
config.put(JsonGenerator.WRITE_NAN_AS_NULLS, true);
600-
assertEquals("{\"val1\":null,\"val2\":1.0,\"val3\":0.0,\"val4\":null,\"val5\":null}", nameValueNanInfinity(config));
601-
assertEquals("null", valueNanInfinity(config));
663+
JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(config);
664+
assertEquals("{\"val1\":null,\"val2\":1.0,\"val3\":0.0,\"val4\":null,\"val5\":null,\"val6\":null,\"val7\":1.0,\"val8\":0.0,\"val9\":null,\"val10\":null}", nameValueNanInfinity(generatorFactory));
665+
assertEquals("0.0", valueNanInfinity(generatorFactory, 0.0));
666+
assertEquals("1.0", valueNanInfinity(generatorFactory, 1.0));
667+
assertEquals("null", valueNanInfinity(generatorFactory, Double.NaN));
668+
assertEquals("null", valueNanInfinity(generatorFactory, Double.POSITIVE_INFINITY));
669+
assertEquals("null", valueNanInfinity(generatorFactory, Double.NEGATIVE_INFINITY));
670+
assertEquals("0.0", jsonNumberNanInfinity(generatorFactory, 0.0));
671+
assertEquals("1.0", jsonNumberNanInfinity(generatorFactory, 1.0));
672+
assertEquals("null", jsonNumberNanInfinity(generatorFactory, Double.NaN));
673+
assertEquals("null", jsonNumberNanInfinity(generatorFactory, Double.POSITIVE_INFINITY));
674+
assertEquals("null", jsonNumberNanInfinity(generatorFactory, Double.NEGATIVE_INFINITY));
602675
}
676+
603677
}

0 commit comments

Comments
 (0)