Skip to content

Commit 5d0d5d9

Browse files
committed
The code to compare two numbers in json object/array does not correctly compare BigInteger/BigDecimal values.
Fix this issue and also simplify / refactor this code to be more compact and reused between object/array
1 parent aec1041 commit 5d0d5d9

File tree

3 files changed

+59
-97
lines changed

3 files changed

+59
-97
lines changed

src/main/java/io/vertx/core/json/JsonArray.java

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.function.Function;
2121
import java.util.stream.Stream;
2222

23+
import static io.vertx.core.json.JsonObject.compareObjects;
2324
import static io.vertx.core.json.impl.JsonUtil.*;
2425
import static java.time.format.DateTimeFormatter.ISO_INSTANT;
2526

@@ -644,42 +645,7 @@ public boolean equals(Object o) {
644645
for (int i = 0; i < this.size(); i++) {
645646
Object thisValue = this.getValue(i);
646647
Object otherValue = other.getValue(i);
647-
// identity check
648-
if (thisValue == otherValue) {
649-
continue;
650-
}
651-
// special case for numbers
652-
if (thisValue instanceof Number && otherValue instanceof Number && thisValue.getClass() != otherValue.getClass()) {
653-
Number n1 = (Number) thisValue;
654-
Number n2 = (Number) otherValue;
655-
// floating point values
656-
if (thisValue instanceof Float || thisValue instanceof Double || otherValue instanceof Float || otherValue instanceof Double) {
657-
// compare as floating point double
658-
if (n1.doubleValue() == n2.doubleValue()) {
659-
// same value check the next entry
660-
continue;
661-
}
662-
}
663-
if (thisValue instanceof Integer || thisValue instanceof Long || otherValue instanceof Integer || otherValue instanceof Long) {
664-
// compare as integer long
665-
if (n1.longValue() == n2.longValue()) {
666-
// same value check the next entry
667-
continue;
668-
}
669-
}
670-
}
671-
// special case for char sequences
672-
if (thisValue instanceof CharSequence && otherValue instanceof CharSequence && thisValue.getClass() != otherValue.getClass()) {
673-
CharSequence s1 = (CharSequence) thisValue;
674-
CharSequence s2 = (CharSequence) otherValue;
675-
676-
if (Objects.equals(s1.toString(), s2.toString())) {
677-
// same value check the next entry
678-
continue;
679-
}
680-
}
681-
// fallback to standard object equals checks
682-
if (!Objects.equals(thisValue, otherValue)) {
648+
if (thisValue != otherValue && !compareObjects(thisValue, otherValue)) {
683649
return false;
684650
}
685651
}

src/main/java/io/vertx/core/json/JsonObject.java

Lines changed: 47 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,7 @@ public String toString() {
11581158
return encode();
11591159
}
11601160

1161+
11611162
@Override
11621163
public boolean equals(Object o) {
11631164
// null check
@@ -1182,72 +1183,58 @@ public boolean equals(Object o) {
11821183

11831184
Object thisValue = this.getValue(key);
11841185
Object otherValue = other.getValue(key);
1185-
// identity check
1186-
if (thisValue == otherValue) {
1187-
continue;
1186+
if (thisValue != otherValue && !compareObjects(thisValue, otherValue)) {
1187+
return false;
11881188
}
1189-
// special case for numbers
1190-
1191-
if (thisValue instanceof Number && otherValue instanceof Number) {
1192-
if (thisValue.getClass() == otherValue.getClass()) {
1193-
if (thisValue.equals(otherValue)) {
1194-
continue;
1195-
}
1196-
} else {
1197-
// meaning that the numbers are different types
1198-
Number n1 = (Number) thisValue;
1199-
Number n2 = (Number) otherValue;
1200-
if ((thisValue instanceof Float || thisValue instanceof Double) &&
1201-
(otherValue instanceof Float || otherValue instanceof Double)) {
1202-
// compare as floating point double
1203-
if (n1.doubleValue() == n2.doubleValue()) {
1204-
// same value, check the next entry
1205-
continue;
1206-
}
1207-
}
1208-
1209-
if ((thisValue instanceof Integer || thisValue instanceof Long) &&
1210-
(otherValue instanceof Integer || otherValue instanceof Long)) {
1211-
// compare as integer long
1212-
if (n1.longValue() == n2.longValue()) {
1213-
// same value, check the next entry
1214-
continue;
1215-
}
1216-
}
1217-
1189+
}
1190+
// all checks passed
1191+
return true;
1192+
}
12181193

1219-
// if its either integer or long and the other is float or double or vice versa,
1220-
// compare as floating point double
1221-
if ((thisValue instanceof Integer || thisValue instanceof Long) &&
1222-
(otherValue instanceof Float || otherValue instanceof Double) ||
1223-
(thisValue instanceof Float || thisValue instanceof Double) &&
1224-
(otherValue instanceof Integer || otherValue instanceof Long)) {
1225-
// compare as floating point double
1226-
if (n1.doubleValue() == n2.doubleValue()) {
1227-
// same value, check the next entry
1228-
continue;
1229-
}
1230-
}
1231-
}
1194+
static boolean compareObjects(Object o1, Object o2) {
1195+
if (o1 instanceof Number && o2 instanceof Number) {
1196+
if (o1.getClass() == o2.getClass()) {
1197+
return o1.equals(o2);
1198+
} else {
1199+
// meaning that the numbers are different types
1200+
Number n1 = (Number) o1;
1201+
Number n2 = (Number) o2;
1202+
return compareNumbers(n1, n2);
12321203
}
1204+
} else if (o1 instanceof CharSequence && o2 instanceof CharSequence && o1.getClass() != o2.getClass()) {
1205+
return Objects.equals(o1.toString(), o2.toString());
1206+
} else {
1207+
return Objects.equals(o1, o2);
1208+
}
1209+
}
12331210

1234-
// special case for char sequences
1235-
if (thisValue instanceof CharSequence && otherValue instanceof CharSequence && thisValue.getClass() != otherValue.getClass()) {
1236-
CharSequence s1 = (CharSequence) thisValue;
1237-
CharSequence s2 = (CharSequence) otherValue;
1238-
1239-
if (Objects.equals(s1.toString(), s2.toString())) {
1240-
// same value, check the next entry
1241-
continue;
1242-
}
1243-
}
1244-
// fallback to standard object equals checks
1245-
if (!Objects.equals(thisValue, otherValue)) {
1246-
return false;
1211+
private static boolean compareNumbers(Number n1, Number n2) {
1212+
if (isDecimalNumber(n1) && isDecimalNumber(n2)) {
1213+
// compare as floating point double
1214+
return n1.doubleValue() == n2.doubleValue();
1215+
} else if (isWholeNumber(n1) && isWholeNumber(n2)) {
1216+
// compare as integer long
1217+
return n1.longValue() == n2.longValue();
1218+
} else if (isWholeNumber(n1) && isDecimalNumber(n2) ||
1219+
isDecimalNumber(n1) && isWholeNumber(n2)) {
1220+
// if its either integer or long and the other is float or double or vice versa,
1221+
// compare as floating point double
1222+
return n1.doubleValue() == n2.doubleValue();
1223+
} else {
1224+
if (isWholeNumber(n1)) {
1225+
return n1.longValue() == n2.longValue();
1226+
} else {
1227+
return n1.doubleValue() == n2.doubleValue();
12471228
}
12481229
}
1249-
// all checks passed
1250-
return true;
1230+
}
1231+
1232+
private static boolean isWholeNumber(Number thisValue) {
1233+
return thisValue instanceof Integer || thisValue instanceof Long;
1234+
}
1235+
1236+
private static boolean isDecimalNumber(Number thisValue) {
1237+
return thisValue instanceof Float || thisValue instanceof Double;
12511238
}
12521239

12531240
@Override

src/test/java/io/vertx/core/json/JsonObjectTest.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1578,7 +1578,16 @@ public void testNumberEquality() {
15781578
assertNumberEquals(2D, 2);
15791579
assertNumberNotEquals(2.3D, 2);
15801580
assertNumberNotEquals(2.3f, 2);
1581-
1581+
assertNumberEquals(2, new BigDecimal(2));
1582+
assertNumberEquals(new BigDecimal(2), 2);
1583+
assertNumberEquals(2D, new BigDecimal(2));
1584+
assertNumberEquals(new BigDecimal(2), 2D);
1585+
assertNumberEquals(2, BigInteger.valueOf(2));
1586+
assertNumberEquals(BigInteger.valueOf(2), 2);
1587+
assertNumberEquals(2D, BigInteger.valueOf(2));
1588+
assertNumberEquals(BigInteger.valueOf(2), 2D);
1589+
assertNumberEquals(BigInteger.valueOf(2), new BigDecimal(2));
1590+
assertNumberEquals(new BigDecimal(2), BigInteger.valueOf(2));
15821591
}
15831592

15841593
private void assertNumberEquals(Number value1, Number value2) {

0 commit comments

Comments
 (0)