Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
.project
.idea/
.settings/
/.DS_Store
.DS_Store
bin/
.envrc
.vscode/
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ private JsonNumber getJsonNumberValue() {
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;
}
Expand Down
111 changes: 111 additions & 0 deletions src/test/java/org/eclipse/yasson/jsonstructure/Issue707.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -322,4 +322,69 @@ public void testGetArray() {
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());
}
}