Issue
I have a timestamp field in my Cassandra table which I want to map to a Java Instant type. Its fairly easy to do achieve this while writing.
I add the href="http://docs.datastax.com/en/developer/java-driver/3.1/manual/custom_codecs/extras/" rel="nofollow noreferrer">custom codecs.
@Override
protected ClusterBuilderConfigurer getClusterBuilderConfigurer() {
return clusterBuilder -> {
clusterBuilder.getConfiguration().getCodecRegistry()
.register(InstantCodec.instance,
LocalDateCodec.instance,
LocalTimeCodec.instance);
return clusterBuilder;
};
}
Tell spring to not convert my Instant to some other type.
private enum InstantWriteConverter implements Converter<Instant, Instant> {
INSTANT;
@Override
public Instant convert(Instant source) {
return source;
}
}
This way Instant is passed along as it is and gets handled by the InstantCodec.
But when reading back from Cassandra, the read timestamp gets mapped to a Date and I am not able to change this behaviour. Due to this, I need to add a special constructer to my entity just to convert the Date to Instant.
My analysis. When parsing the Row data, Cassandra performs a look up to find an appropriate Codec. It does not respect the parameter types of the provided entity constructor and simply picks up the first codec which can handle the row data. In my case it picks up the timestamp->date codec because its present before the timestamp->instant codec in the CodecRegistry codecs list.
Any way to directly convert the timestamp to Instant ?
EDIT
tried registering read write converters, but the read converter is not getting used.
@WritingConverter
private enum InstantWriteConverter implements Converter<Instant, Long> {
INSTANT;
@Override
public Long convert(Instant source) {
return source.toEpochMilli();
}
}
@ReadingConverter
private enum InstantReadConverter implements Converter<Long, Instant> {
INSTANT;
@Override
public Instant convert(Long source) {
return Instant.ofEpochMilli(source);
}
}
Solution
Got it working. The read converter needs to be on Row->Class level.
@Override
protected ClusterBuilderConfigurer getClusterBuilderConfigurer() {
return clusterBuilder -> {
clusterBuilder.getConfiguration().getCodecRegistry()
.register(InstantCodec.instance,
LocalDateCodec.instance,
LocalTimeCodec.instance);
return clusterBuilder;
};
}
@Override
public CustomConversions customConversions() {
return new CustomConversions(
Arrays.asList(ReadConverter.INSTANCE,
InstantWriteConverter.INSTANCE,
LocalTimeWriteConverter.INSTANCE,
DurationWriteConverter.INSTANCE,
LocalDateWriteConverter.INSTANCE));
}
@ReadingConverter
private enum ReadConverter implements Converter<Row, FlightFareInfo> {
INSTANCE;
@Override
public FlightFareInfo convert(Row source) {
return FlightFareInfo.convertFromRow(source);
}
}
Answered By - Dexter
Answer Checked By - Katrina (JavaFixing Volunteer)