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]

Reply via email to