Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Cassandra converter

I'v started looking for nice solution how to nicely persist entity using Spring CassandraOperations. The problems started because some fields within my entity is not cassandra supported, e.g. joda DateTime.

The workaround is to have additional fields within the same entity of type java.util.Date instead of joda DateTime, mark unrequired fields with @Transient. But this is not clean, so I started looking for automatic custom conversion.

Currently spring-data-cassandra reference does not provide information how to register custom converter. http://docs.spring.io/spring-data/cassandra/docs/current/reference/html/#cassandra.custom-converters

Is it possible to register custom converter (like here Spring Data Cassandra LocalDateTime Conversion) in CassandraSessionFactoryBean?

This is my code @Configuration public class CassandraConfig {

@Value("${cassandra.contactpoints}")
private String cassandraContactPoint;

@Value("${cassandra.port}")
private int cassandraPort;

@Value("${cassandra.keyspace}")
private String cassandraKeySpace;

@Bean
public CassandraClusterFactoryBean cluster() {

    CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
    cluster.setContactPoints(cassandraContactPoint);
    cluster.setPort(cassandraPort);

    return cluster;
}

@Bean
public CassandraMappingContext mappingContext() {
    return new BasicCassandraMappingContext();
}

@Bean
public CassandraConverter converter() {
    return new MappingCassandraConverter(mappingContext());
}

@Bean
public CassandraSessionFactoryBean session() throws Exception {
    CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
    session.setCluster(cluster().getObject());
    session.setKeyspaceName(cassandraKeySpace);
    session.setConverter(converter());
    session.setSchemaAction(SchemaAction.NONE);

    return session;
}

@Bean
public CassandraOperations cassandraTemplate() throws Exception {
    return new CassandraTemplate(session().getObject());
}

@Bean
public ConversionService getConversionService() {
    ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
    bean.setConverters(new HashSet<>(getConverters()));
    bean.afterPropertiesSet();

    return bean.getObject();
}

private Set<Converter<?, ?>> getConverters() {
    Set<Converter<?, ?>> converters = new HashSet<>();
    converters.addAll(Jsr310Converters.getConvertersToRegister());
    converters.add(new DateTimeWriteConverter());
    converters.add(new DateTimeReadConverter());

    return converters;
}

public static class DateTimeWriteConverter implements Converter<DateTime, Long> {
    @Override
    public Long convert(DateTime source) {
        return source.getMillis();
    }
}

public static class DateTimeReadConverter implements Converter<Long, DateTime> {
    @Override
    public DateTime convert(Long source) {
        return new DateTime(source);
    }
}

}

like image 860
Vytautas Arminas Avatar asked Jan 14 '16 09:01

Vytautas Arminas


1 Answers

Spring Cassandra's custom conversion works when you create a CassandraCustomConversions bean. Just add your custom converter and the default converters will stay. Below is my @Configuration class.

@Bean
CassandraCustomConversions cassandraCustomConversions() {
    List<Converter<?, ?>> converters = new ArrayList<>();
    converters.add(new MyDataReadConverter());
    return new CassandraCustomConversions(converters);
}

static class CounterDataReadConverter implements Converter<ByteBuffer, MyData> {
    @Override
    public MyData convert(ByteBuffer source) {
        try {
            return MyData.parseFrom(source.array());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

I am using spring-boot-starter-data-cassandra based on SpringBoot 2.0.0.RELEASE.

like image 120
bill23 Avatar answered Nov 06 '22 18:11

bill23