malte-f19 opened a new issue, #12506:
URL: https://github.com/apache/ignite/issues/12506
We are trying to fetch a record using `RecordView` from Apache Ignite 3.1
which contains a `BigDecimal`, but get a `ClassCastException`. Not sure if I
did something wrong or this is an issue in the Ignite client.
Here is a minimal example:
I've taken the "Getting started"-example and added a `weight` field to the
`Person` class (please find the full source at the end of this post). Then I
adjusted the code inserting data to include a weight. After that, I checked
data is populated to the table as expected:
```
sql-cli> select * from person2 ;
╔════╤══════╤════════╗
║ ID │ NAME │ WEIGHT ║
╠════╪══════╪════════╣
║ 3 │ Jack │ 68.50 ║
╟────┼──────┼────────╢
║ 4 │ Jill │ 62.30 ║
╟────┼──────┼────────╢
║ 2 │ Jane │ 65.10 ║
╚════╧══════╧════════╝
```
Then, I used a `RecordView` to query the objects. As soon as I loop over the
curser and the first object is about to be created, I get the following
exception:
```
Exception in thread "main" org.apache.ignite.lang.MarshallerException:
IGN-MARSHALLING-1 class java.math.BigDecimal cannot be cast to class
java.math.BigInteger (java.math.BigDecimal and java.math.BigInteger are in
module java.base of loader 'bootstrap') TraceId:a2f05638
at
org.apache.ignite.internal.marshaller.FieldAccessor.read(FieldAccessor.java:390)
at
org.apache.ignite.internal.marshaller.Marshaller$PojoMarshaller.readObject(Marshaller.java:289)
at
org.apache.ignite.internal.client.table.ClientRecordView.lambda$queryMapper$56(ClientRecordView.java:561)
at
org.apache.ignite.internal.util.CollectionUtils$6$1.next(CollectionUtils.java:579)
at
org.apache.ignite.internal.table.criteria.CursorAdapter$IteratorImpl.next(CursorAdapter.java:123)
at
org.apache.ignite.internal.table.criteria.CursorAdapter.next(CursorAdapter.java:76)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at org.example.Main.queryNewTable(Main.java:95)
at org.example.Main.main(Main.java:43)
Caused by: java.lang.ClassCastException: class java.math.BigDecimal cannot
be cast to class java.math.BigInteger (java.math.BigDecimal and
java.math.BigInteger are in module java.base of loader 'bootstrap')
at
org.apache.ignite.internal.marshaller.TupleReader.readBigDecimal(TupleReader.java:137)
at
org.apache.ignite.internal.marshaller.FieldAccessor.readRefValue(FieldAccessor.java:232)
at
org.apache.ignite.internal.marshaller.FieldAccessor$ReferenceFieldAccessor.read0(FieldAccessor.java:780)
at
org.apache.ignite.internal.marshaller.FieldAccessor.read(FieldAccessor.java:388)
... 8 more
```
I checked the `TupleReader` and the method failing is this:
```java
@Override
public BigDecimal readBigDecimal(int scale) {
return new BigDecimal(tuple.value(index++), scale);
}
```
Here, a new `BigDecimal` is created, calling the constructor which expects a
`BigInteger` and a scale. While the scale is set to 2, `tuple.value(index++)`
is already a `BigDecimal`, which can't be casted into a `BigInteger`, of
course, raising the exception.
I also tried to use a `Mapper` to map the value manually but the error is
the same. Maybe the mapper is called after the `TupleReader` is executed for
the column.
Am I doing something wrong? Or is that an issue in the driver code?
I could also upload a project to GitHub in case it helps. Here is the code
I've used:
```java
package org.example;
import org.apache.ignite.catalog.ColumnType;
import org.apache.ignite.catalog.definitions.ColumnDefinition;
import org.apache.ignite.catalog.definitions.TableDefinition;
import org.apache.ignite.client.IgniteClient;
import org.apache.ignite.lang.Cursor;
import org.apache.ignite.table.KeyValueView;
import org.apache.ignite.table.RecordView;
import org.apache.ignite.table.Table;
import org.apache.ignite.table.Tuple;
import org.apache.ignite.table.criteria.Criteria;
import java.math.BigDecimal;
/**
* This example demonstrates connecting to an Ignite 3 cluster
* and working with data using different table view patterns.
*/
public class Main {
public static void main(String[] args) {
// Create an array of connection addresses for fault tolerance
String[] addresses = {
"localhost:10800",
"localhost:10801",
"localhost:10802"
};
// Connect to the Ignite cluster using the client builder pattern
try (IgniteClient client = IgniteClient.builder()
.addresses(addresses)
.build()) {
System.out.println("Connected to the cluster: " +
client.connections());
// Create a new table using Java API
Table table = createTable(client);
// Demonstrate different ways to interact with tables
populateTableWithDifferentViews(table);
// Query the new table using SQL API
queryNewTable(client);
}
}
/**
* Creates a new table using the Java API
*/
private static Table createTable(IgniteClient client) {
System.out.println("\n--- Creating Person2 table ---");
return client.catalog().createTable(
TableDefinition.builder("Person2")
.ifNotExists()
.columns(
ColumnDefinition.column("ID",
ColumnType.INT32),
ColumnDefinition.column("NAME",
ColumnType.VARCHAR),
ColumnDefinition.column("WEIGHT",
"DECIMAL(5, 2)"))
.primaryKey("ID")
.build());
}
/**
* Demonstrates different ways to interact with tables
*/
private static void populateTableWithDifferentViews(Table table) {
System.out.println("\n--- Populating Person2 table using different
views ---");
// 1. Using RecordView with Tuples
RecordView<Tuple> recordView = table.recordView();
recordView.upsert(null, Tuple.create().set("id", 2).set("name",
"Jane").set("weight", BigDecimal.valueOf(65.1)));
System.out.println("Added record using RecordView with Tuple");
// 2. Using RecordView with POJOs
RecordView<Person> pojoView = table.recordView(Person.class);
pojoView.upsert(null, new Person(3, "Jack",
BigDecimal.valueOf(68.5)));
System.out.println("Added record using RecordView with POJO");
// 3. Using KeyValueView with Tuples
KeyValueView<Tuple, Tuple> keyValueView = table.keyValueView();
keyValueView.put(null, Tuple.create().set("id", 4),
Tuple.create().set("name", "Jill").set("weight", BigDecimal.valueOf(62.3)));
System.out.println("Added record using KeyValueView with Tuples");
}
/**
* Queries the newly created Person2 table using SQL
*/
private static void queryNewTable(IgniteClient client) {
System.out.println("\n--- Querying Person2 table ---");
client.sql().execute(null, "SELECT * FROM Person2")
.forEachRemaining(row -> System.out.println("Person2: " +
row.stringValue("name") + " (" + row.decimalValue("weight") + ")"));
RecordView<Person> recordView =
client.tables().table("Person2").recordView(Person.class);
Cursor<Person> cursor = recordView.query(null,
Criteria.columnValue("id", Criteria.equalTo(2)));
cursor.forEachRemaining(person -> System.out.println("Person2: " +
person.name + " (" + person.weight + ")"));
cursor.close();
}
/**
* POJO class representing a Person
*/
public static class Person {
// Default constructor required for serialization
public Person() { }
public Person(Integer id, String name, BigDecimal weight) {
this.id = id;
this.name = name;
this.weight = weight;
}
Integer id;
String name;
BigDecimal weight;
}
}
```
Thanks in advance!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]