You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ignite.apache.org by "malte-f19 (via GitHub)" <gi...@apache.org> on 2025/11/07 16:42:46 UTC

[I] Fail to load a BigDecimal, getting `MarshallerException` [ignite]

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: notifications-unsubscribe@ignite.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Fail to load a BigDecimal, getting `MarshallerException` [ignite]

Posted by "malte-f19 (via GitHub)" <gi...@apache.org>.
malte-f19 commented on issue #12506:
URL: https://github.com/apache/ignite/issues/12506#issuecomment-3516320578

   Thanks for confirming and happy to help 🙂
   Any ideas when version 3.2 will be released? I wasn't abel to find a roadmap.
   Is there a workaround other than using `Tuple` instead? Is it possible to overwrite the mapping process itself somehow so we could use some manual written mapper until the bug is fixed?


-- 
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: notifications-unsubscribe@ignite.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Fail to load a BigDecimal, getting `MarshallerException` [ignite]

Posted by "ptupitsyn (via GitHub)" <gi...@apache.org>.
ptupitsyn commented on issue #12506:
URL: https://github.com/apache/ignite/issues/12506#issuecomment-3516508280

   The bug is only in Criteria API, so the workaround is to use SQL instead:
   
   ```java
           client.sql().execute(null, Mapper.of(Person.class), "SELECT * FROM Person2 WHERE id = ?", 2)
                   .forEachRemaining(person -> System.out.println("SQL Person2: " + person.name + " (" + person.weight + ")"));
   ```
   
   This also maps the query results to `Person` class.


-- 
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: notifications-unsubscribe@ignite.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Fail to load a BigDecimal, getting `MarshallerException` [ignite]

Posted by "ptupitsyn (via GitHub)" <gi...@apache.org>.
ptupitsyn commented on issue #12506:
URL: https://github.com/apache/ignite/issues/12506#issuecomment-3510583191

   Ticket created, thank you for the detailed report: https://issues.apache.org/jira/browse/IGNITE-26990


-- 
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: notifications-unsubscribe@ignite.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [I] Fail to load a BigDecimal, getting `MarshallerException` [ignite]

Posted by "ptupitsyn (via GitHub)" <gi...@apache.org>.
ptupitsyn closed issue #12506: Fail to load a BigDecimal, getting `MarshallerException`
URL: https://github.com/apache/ignite/issues/12506


-- 
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: notifications-unsubscribe@ignite.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org