question

tyuen_144153 avatar image
tyuen_144153 asked Erick Ramirez answered

InvalidTypeException: class java.time.LocalDateTime does not correspond to any CQL3 type

import com.datastax.driver.core.querybuilder.Batch;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.datastax.driver.core.querybuilder.Update.Where;
...
Batch updateBatch = QueryBuilder.batch();
...
final Where updateQueryForProduct= QueryBuilder
    .update(keyspaceName, "product")
    .with(QueryBuilder.putAll("currentprice", value.getLeft()))
    .and(QueryBuilder.putAll("regularprice", value.getRight()))
    .and(QueryBuilder.set("datecreated", LocalDateTime.now()))
    .where(QueryBuilder.eq("id", id));
updateBatch.add(updateQueryForProduct);

Error:

Caused by: com.datastax.driver.core.exceptions.InvalidTypeException: Value 2 of type class java.time.LocalDateTime does not correspond to any CQL3 type
    at com.datastax.driver.core.querybuilder.Utils.convert(Utils.java:354) ~[cassandra-driver-core-3.7.2.jar:na]
    at com.datastax.driver.core.querybuilder.BuiltStatement.getValues(BuiltStatement.java:268) ~[cassandra-driver-core-3.7.2.jar:na]
    at com.datastax.driver.core.querybuilder.Batch.getValues(Batch.java:121) ~[cassandra-driver-core-3.7.2.jar:na]
    at com.datastax.driver.core.SessionManager.makeRequestMessage(SessionManager.java:600) ~[cassandra-driver-core-3.7.2.jar:na]
    at com.datastax.driver.core.SessionManager.executeAsync(SessionManager.java:142) ~[cassandra-driver-core-3.7.2.jar:na]
    at com.datastax.driver.core.AbstractSession.execute(AbstractSession.java:58) ~[cassandra-driver-core-3.7.2.jar:na]
    at org.springframework.data.cassandra.core.cql.CqlTemplate.query(CqlTemplate.java:296) ~[spring-data-cassandra-2.2.6.RELEASE.jar:2.2.6.RELEASE]
cassandrajava driver
10 |1000

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

Erick Ramirez avatar image
Erick Ramirez answered

Root cause

The Java driver can't serialise the LocalDateTime object in your code and so it throws the InvalidTypeException.

Workaround

I apologise that it's not clear to me from your code what class the LocalDateTime object is but if it's Joda Time, it might be possible for you to get around it by converting it to Java Date like this:

    LocalDateTime.now().toDate()

It isn't elegant but may work in your situation.

Custom codecs

The correct way of handling this is to map the CQL timestamp to a Joda class using a custom codec.

Here's an example implementation of a custom DateTimeCodec:

public class DateTimeCodec extends TypeCodec<DateTime> {
  public DateTimeCodec() {
    super(DataType.timestamp(), DateTime.class);
  }

  @Override
  public DateTime parse(String value) {
    if (value == null || value.equals("NULL"))
      return null;

    try {
      return DateTime.parse(value);
    } catch (IllegalArgumentException iae) {
      throw new InvalidTypeException("Could not parse format: " + value, iae);
    }
  }

  @Override
  public String format(DateTime value) {
    if (value == null)
      return "NULL";

    return Long.toString(value.getMillis());
  }

  @Override
  public ByteBuffer serialize(DateTime value, ProtocolVersion protocolVersion) {
    return value == null ? null : BigintCodec.instance.serializeNoBoxing(value.getMillis(), protocolVersion);
  }

  @Override
  public DateTime deserialize(ByteBuffer bytes, ProtocolVersion protocolVersion) {
    return bytes == null || bytes.remaining() == 0 ? null: new DateTime(BigintCodec.instance.deserializeNoBoxing(bytes, protocolVersion));
  }
}

The full example is available on https://github.com/o19s/JodaTimeCodecs.

Credits

The example is compliments of Christopher Bradford (@bradfordcp).

For more information, see the Java driver Custom Codecs page. Cheers!

Share
10 |1000

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

Cedrick Lunven avatar image
Cedrick Lunven answered tyuen_144153 published

Hello,


That would help to have type of `datecreated` in the Cassandra table to give you the proper expected java class.

Here is the documentation

https://docs.datastax.com/en/developer/java-driver/4.8/manual/core/temporal_types/


CQL JAVA
date
java.time.LocalDate
time java.time.LocalTime
timestamp
java.time.Instant
duration
CqlDuration





Cheers.

1 comment Share
10 |1000

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

tyuen_144153 avatar image tyuen_144153 commented ·

Hi Cedrick,


I changed the java code to use java.time.Instant.now(), but I getting the below error message:


Updated to use "java.time.Instant":

final Where updateQueryForProduct= QueryBuilder
.update(keyspaceName, "product")
.with(QueryBuilder.putAll("currentprice", value.getLeft()))
.and(QueryBuilder.putAll("regularprice", value.getRight()))
.and(QueryBuilder.set("datecreated", java.time.Instant.now()))
.where(QueryBuilder.eq("id", id));


ERROR Message:

Caused by: com.datastax.driver.core.exceptions.CodecNotFoundException: Codec not found for requested operation: [ANY <-> java.time.Instant]
at com.datastax.driver.core.CodecRegistry.notFound(CodecRegistry.java:806) ~[cassandra-driver-core-3.7.2.jar:na]
at com.datastax.driver.core.CodecRegistry.createCodec(CodecRegistry.java:649) ~[cassandra-driver-core-3.7.2.jar:na]
at com.datastax.driver.core.CodecRegistry.findCodec(CodecRegistry.java:631)

0 Likes 0 ·