Merge pull request #710 from KyleAure/707-fix-isIntegralNumber
707 fix is integral number
diff --git a/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonStructureToParserAdapter.java b/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonStructureToParserAdapter.java
index f44999b..f70210e 100644
--- a/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonStructureToParserAdapter.java
+++ b/src/main/java/org/eclipse/yasson/internal/jsonstructure/JsonStructureToParserAdapter.java
@@ -141,7 +141,7 @@
JsonStructureIterator iterator = iterators.peek();
JsonValue value = iterator.getValue();
if (value.getValueType() != JsonValue.ValueType.NUMBER) {
- throw iterator.createIncompatibleValueError();
+ throw new IllegalStateException(iterator.createIncompatibleValueError().getMessage());
}
return (JsonNumber) value;
}
diff --git a/src/test/java/org/eclipse/yasson/jsonstructure/Issue707.java b/src/test/java/org/eclipse/yasson/jsonstructure/Issue707.java
new file mode 100644
index 0000000..c9a9836
--- /dev/null
+++ b/src/test/java/org/eclipse/yasson/jsonstructure/Issue707.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2026 Contributors to the Eclipse Foundation
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0,
+ * or the Eclipse Distribution License v. 1.0 which is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
+ */
+
+package org.eclipse.yasson.jsonstructure;
+
+import jakarta.json.bind.annotation.JsonbTypeDeserializer;
+import jakarta.json.bind.serializer.DeserializationContext;
+import jakarta.json.bind.serializer.JsonbDeserializer;
+import jakarta.json.stream.JsonParser;
+import java.lang.reflect.Type;
+import java.util.Objects;
+
+/**
+ * Test resources for Issue #707: YassonParser.isIntegralNumber throws JsonbException
+ * instead of IllegalStateException.
+ *
+ * This replicates the user's scenario where they want to handle both numeric and
+ * string IDs by catching IllegalStateException when the value is not a number.
+ */
+public class Issue707 {
+
+ /**
+ * Simple ID wrapper that can be created from either a long or a string.
+ */
+ public static class RequestId {
+ private final String value;
+
+ private RequestId(String value) {
+ this.value = value;
+ }
+
+ public static RequestId of(long id) {
+ return new RequestId(String.valueOf(id));
+ }
+
+ public static RequestId of(String id) {
+ return new RequestId(id);
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RequestId requestId = (RequestId) o;
+ return Objects.equals(value, requestId.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(value);
+ }
+
+ @Override
+ public String toString() {
+ return "RequestId{" + value + "}";
+ }
+ }
+
+ /**
+ * Container class that uses a custom deserializer for the ID field.
+ */
+ public static class Request {
+ private RequestId id;
+
+ @JsonbTypeDeserializer(RequestIdDeserializer.class)
+ public RequestId getId() {
+ return id;
+ }
+
+ public void setId(RequestId id) {
+ this.id = id;
+ }
+ }
+
+ /**
+ * Custom deserializer that handles both numeric and string IDs.
+ * This is the exact pattern from the issue report.
+ */
+ public static class RequestIdDeserializer implements JsonbDeserializer<RequestId> {
+ @Override
+ public RequestId deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) {
+ RequestId id = null;
+ try {
+ // Try to read as a number first
+ if (parser.isIntegralNumber()) {
+ id = RequestId.of(parser.getLong());
+ } else {
+ // Not an integral number, but is still a number
+ id = RequestId.of(parser.getBigDecimal().toString());
+ }
+ } catch (IllegalStateException e) {
+ id = RequestId.of(parser.getString());
+ }
+ return id;
+ }
+ }
+}
+
diff --git a/src/test/java/org/eclipse/yasson/jsonstructure/JsonStructureToParserAdapterTest.java b/src/test/java/org/eclipse/yasson/jsonstructure/JsonStructureToParserAdapterTest.java
index f148600..8cf1779 100644
--- a/src/test/java/org/eclipse/yasson/jsonstructure/JsonStructureToParserAdapterTest.java
+++ b/src/test/java/org/eclipse/yasson/jsonstructure/JsonStructureToParserAdapterTest.java
@@ -322,4 +322,69 @@
assertEquals("test1, test2", tags);
}
+ /**
+ * Test for Issue #707: isIntegralNumber() should throw IllegalStateException, not JsonbException
+ * when called on a non-numeric value.
+ *
+ * This test verifies that the user's code pattern from the issue works correctly:
+ * - When the value is a string, isIntegralNumber() throws IllegalStateException
+ * - The exception can be caught and the value read as a string
+ */
+ @Test
+ public void isIntegralNumberThrowsIllegalStateException() {
+ // Test with string ID - should catch IllegalStateException and handle gracefully
+ // This test uses fromJsonStructure to exercise JsonStructureToParserAdapter
+ JsonObjectBuilder objectBuilder = jsonProvider.createObjectBuilder();
+ objectBuilder.add("id", "abc123");
+ JsonObject jsonObject = objectBuilder.build();
+
+ YassonJsonb jsonb = (YassonJsonb) JsonbBuilder.create();
+ Issue707.Request result = jsonb.fromJsonStructure(jsonObject, Issue707.Request.class);
+
+ assertNotNull(result);
+ assertNotNull(result.getId());
+ assertEquals("abc123", result.getId().getValue());
+ }
+
+ /**
+ * Test for Issue #707: Verify that an integral ID still works correctly.
+ */
+ @Test
+ public void isIntegralNumberWithNumericValue() {
+ // Test with numeric ID - should work without throwing any exception
+ // This test uses fromJsonStructure to exercise JsonStructureToParserAdapter
+ JsonObjectBuilder objectBuilder = jsonProvider.createObjectBuilder();
+ objectBuilder.add("id", 12345);
+ JsonObject jsonObject = objectBuilder.build();
+
+ YassonJsonb jsonb = (YassonJsonb) JsonbBuilder.create();
+ Issue707.Request result = jsonb.fromJsonStructure(jsonObject, Issue707.Request.class);
+
+ assertNotNull(result);
+ assertNotNull(result.getId());
+ assertEquals("12345", result.getId().getValue());
+ }
+
+ /**
+ * Test for Issue #707: Verify that floating point numbers are handled correctly.
+ * isIntegralNumber() should return false for non-integral numbers.
+ * isIntegralNumber() should not throw an exception for floating point numbers.
+ */
+ @Test
+ public void isIntegralNumberWithFloatingPoint() {
+ // Test with floating point ID - isIntegralNumber() returns false,
+ // so the else block handles it as a string
+ // This test uses fromJsonStructure to exercise JsonStructureToParserAdapter
+ JsonObjectBuilder objectBuilder = jsonProvider.createObjectBuilder();
+ objectBuilder.add("id", 123.45);
+ JsonObject jsonObject = objectBuilder.build();
+
+ YassonJsonb jsonb = (YassonJsonb) JsonbBuilder.create();
+ Issue707.Request result = jsonb.fromJsonStructure(jsonObject, Issue707.Request.class);
+
+ assertNotNull(result);
+ assertNotNull(result.getId());
+ // The deserializer will read it as a string when isIntegralNumber() returns false
+ assertEquals("123.45", result.getId().getValue());
+ }
}