DataStax Java Driver Mapper error on PrimitiveType cannot be cast to UserDefinedType

510 views
Skip to first unread message

Dongsheng Song

unread,
Jul 26, 2020, 11:42:27 AM7/26/20
to DataStax Java Driver for Apache Cassandra User Mailing List
Hi,

When I use DataStax Java Driver 4.7.2 with the Mapper, I got a class cast error:

java.lang.ClassCastException: com.datastax.oss.driver.internal.core.type.PrimitiveType cannot be cast to com.datastax.oss.driver.api.core.type.UserDefinedType

This error on the generated mapper MyCounterDaoImpl__MapperGenerated.java code:

UserDefinedType udtType = (UserDefinedType) boundStatementBuilder.getType("counter");

Here is the DAO:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@CqlName("my_counter")
public class MyCounter {
@PartitionKey
private long id;
private long counter;
}

and the Mapper:

@Dao
@DefaultNullSavingStrategy(SET_TO_NULL)
public interface MyCounterDao {
@Query("UPDATE ${qualifiedTableId} SET counter = counter + :counter WHERE id= :id")
void create(MyCounter counter);
}

Why the generated code treat the counter (long) as UserDefinedType ?

if (value != null) {
UserDefinedType udtType = (UserDefinedType) boundStatementBuilder.getType("counter");
UdtValue udtValue = udtType.newValue();
myCounterHelper.set(value, udtValue, NullSavingStrategy.DO_NOT_SET);
boundStatementBuilder = boundStatementBuilder.setUdtValue("counter", udtValue);
} else if (nullSavingStrategy == NullSavingStrategy.SET_TO_NULL) {
boundStatementBuilder = boundStatementBuilder.setUdtValue("counter", null);
}

Thanks,
Dongsheng

Olivier Michallat

unread,
Jul 26, 2020, 1:22:05 PM7/26/20
to DataStax Java Driver for Apache Cassandra User Mailing List
Hi,

When you annotate a method with @Query, the mapper assumes that each parameter will match a query placeholder with the same name. Therefore the generated code attempts to fill :counter with MyCounter counter. Then it needs to decide how to convert the value. When it's a custom Java type annotated with @Entity, it assumes that the target CQL column is a UDT.

Obviously this doesn't  work here, what you want is to map counter.getId() to :id and counter.getCounter() to :counter. Explicitly dereferencing fields like that is not supported. What you'd really need is something like @Insert or @Update, but they don't work with counter columns.
Currently the only workaround is to pass the fields individually:

    @Query("UPDATE ${qualifiedTableId} SET counter = counter + :counter WHERE id= :id")
    void create(long id, long counter);

I'll admit that this is a bit of a letdown. This problem came up already, we have an open ticket to provide better support for counter tables: JAVA-2721.

Hope this helps,

Olivier Michallat



--
You received this message because you are subscribed to the Google Groups "DataStax Java Driver for Apache Cassandra User Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to java-driver-us...@lists.datastax.com.
To view this discussion on the web visit https://groups.google.com/a/lists.datastax.com/d/msgid/java-driver-user/f9cafb74-6cd3-45cb-afe9-08bfb0d2a7b9o%40lists.datastax.com.

Dongsheng Song

unread,
Jul 27, 2020, 10:44:44 AM7/27/20
to java-dri...@lists.datastax.com
Reply all
Reply to author
Forward
0 new messages