Closed thaparraj closed 8 months ago
but still get the error
What error?
If you would like us to spend some time helping you to diagnose the problem, please spend some time describing it and, ideally, providing a minimal yet complete sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.
I am preparing a sample program, it connects to a Cassandra server installed within company. Will that be ok if I leave out instructions for deploying Cassandra server.
Error:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.time.Instant] to type [org.joda.time.DateTime]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:294) ~[spring-core-6.1.2.jar:6.1.2]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:185) ~[spring-core-6.1.2.jar:6.1.2]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:165) ~[spring-core-6.1.2.jar:6.1.2]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter.doConvert(MappingCassandraConverter.java:1059) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter.getPotentiallyConvertedSimpleRead(MappingCassandraConverter.java:1054) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter.getPotentiallyConvertedSimpleRead(MappingCassandraConverter.java:1022) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter$ConversionContext.convert(MappingCassandraConverter.java:1362) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter.getReadValue(MappingCassandraConverter.java:1102) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter.readProperties(MappingCassandraConverter.java:541) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter.doReadEntity(MappingCassandraConverter.java:521) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter.doReadEntity(MappingCassandraConverter.java:478) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter.doReadEntity(MappingCassandraConverter.java:441) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter.doReadRow(MappingCassandraConverter.java:421) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter.readRow(MappingCassandraConverter.java:417) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter.read(MappingCassandraConverter.java:399) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.convert.MappingCassandraConverter.project(MappingCassandraConverter.java:290) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.CassandraTemplate.lambda$getMapper$23(CassandraTemplate.java:936) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.CassandraTemplate.lambda$select$0(CassandraTemplate.java:371) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.cql.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:80) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.cql.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:43) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.cql.CqlTemplate.query(CqlTemplate.java:406) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.cql.CqlTemplate.query(CqlTemplate.java:424) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.CassandraTemplate.doQuery(CassandraTemplate.java:852) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.core.CassandraTemplate.select(CassandraTemplate.java:371) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$CollectionExecution.execute(CassandraQueryExecution.java:159) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$ResultProcessingExecution.execute(CassandraQueryExecution.java:270) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.cassandra.repository.query.AbstractCassandraQuery.execute(AbstractCassandraQuery.java:86) ~[spring-data-cassandra-4.2.1.jar:4.2.1]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:170) ~[spring-data-commons-3.2.1.jar:3.2.1]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:158) ~[spring-data-commons-3.2.1.jar:3.2.1]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:164) ~[spring-data-commons-3.2.1.jar:3.2.1]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143) ~[spring-data-commons-3.2.1.jar:3.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.2.jar:6.1.2]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:70) ~[spring-data-commons-3.2.1.jar:3.2.1]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.2.jar:6.1.2]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-6.1.2.jar:6.1.2]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.2.jar:6.1.2]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:249) ~[spring-aop-6.1.2.jar:6.1.2]
at jdk.proxy2/jdk.proxy2.$Proxy157.findBySomeCriteria(Unknown Source) ~[?:?]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:352) ~[spring-aop-6.1.2.jar:6.1.2]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) ~[spring-aop-6.1.2.jar:6.1.2]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-6.1.2.jar:6.1.2]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-6.1.2.jar:6.1.2]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.1.2.jar:6.1.2]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:249) ~[spring-aop-6.1.2.jar:6.1.2]
at jdk.proxy2/jdk.proxy2.$Proxy157.findBySomeCriteria(Unknown Source) ~[?:?]
at com.myorg.resolver.SomeQuery.SomeDataBySomeId(SomeQuery.java:33) ~[classes/:?]
I wasn't able to reproduce the problem with the code you've provided, see https://gist.github.com/mp911de/3603c9c78d6326f3cc8ea912ceeb1506.
Having the CQL for your schema, the entities and a really tiny reproducer is all that we need. We don't require any huge setup so that you can leave away any controllers, services, …
my code:
file1: CassandraClusterConfig.java
package com.myorg.aiml.config;
import java.net.InetSocketAddress; import java.util.Date; import java.util.ArrayList; import java.util.Arrays; import java.util.List;
import com.datastax.oss.driver.api.core.CqlSessionBuilder; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.convert.converter.Converter; import org.springframework.data.cassandra.config.CqlSessionFactoryBean; import org.springframework.data.cassandra.config.SessionBuilderConfigurer; import org.springframework.data.cassandra.core.CassandraTemplate; import org.springframework.data.cassandra.core.convert.CassandraCustomConversions; import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories; import org.springframework.data.convert.ReadingConverter; import org.springframework.data.convert.WritingConverter; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils;
import com.datastax.oss.driver.api.core.config.DefaultDriverOption; import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
/**
@EnableCassandraRepositories @Configuration public class CassandraClusterConfig { private static final Logger logger = LoggerFactory.getLogger(CassandraClusterConfig.class); @Value("${CASSANDRA_HOSTS}") private String contactPoints; @Value("${CASSANDRA_PORT}") private int port; @Value("${CASSANDRA_KEYSPACE}") private String keyspaceName; @Value("${CASSANDRA_USERNAME}") private String userName; @Value("${CASSANDRA_PASSWORD}") private String password; @Value("${CASSANDRA_LOCAL_DC}") private String localDataCenter;
@Value("${session_bean_consistency_level}")
private String sessionBeanConsistency;
@Value("${cassandra_query_request_timeout}")
private String cassandraQueryRequestTimeout;
public String getKeyspaceName() {
return this.keyspaceName;
}
protected String getContactPoints() {
return this.contactPoints;
}
@Bean("session")
@Primary
public CqlSessionFactoryBean session() {
CqlSessionFactoryBean session = new CqlSessionFactoryBean();
List<InetSocketAddress> addressList = getInetSoketAddress(contactPoints);
DriverConfigLoader driverConfigLoader = DriverConfigLoader.programmaticBuilder()
.withString(DefaultDriverOption.REQUEST_CONSISTENCY, sessionBeanConsistency.trim())
.withString(DefaultDriverOption.REQUEST_TIMEOUT, cassandraQueryRequestTimeout)
.build();
logger.info("Session Bean consistency level set to: " + sessionBeanConsistency);
logger.info("cassandraQueryRequestTimeout set to:" + cassandraQueryRequestTimeout);
SessionBuilderConfigurer sessionBuilderConfigurer = getSessionBuilderConfigurer(addressList, driverConfigLoader,
localDataCenter);
session.setSessionBuilderConfigurer(sessionBuilderConfigurer);
session.setKeyspaceName(getKeyspaceName());
return session;
}
@Bean("cassandraTemplate")
@Primary
public CassandraTemplate cassandraTemplate(CqlSessionFactoryBean session, CassandraCustomConversions ccv) {
CassandraTemplate ct = new CassandraTemplate(session.getObject());
return ct;
}
@Bean
public CassandraCustomConversions cassandraCustomConversions(DateTimeToInstantConverter dateTimeToInstantConverter,
InstantToDateTimeConverter instantToDateTimeConverter) {
return new CassandraCustomConversions(Arrays.asList(dateTimeToInstantConverter, instantToDateTimeConverter));
}
@Component
@WritingConverter
public static class DateTimeToInstantConverter implements Converter<DateTime, java.time.Instant> {
@Override
public java.time.Instant convert(DateTime source) {
return source.toDate().toInstant();
}
}
@Component
@ReadingConverter
public static class InstantToDateTimeConverter implements Converter<java.time.Instant, DateTime> {
@Override
public DateTime convert(java.time.Instant source) {
return new DateTime(Date.from(source));
}
}
private SessionBuilderConfigurer getSessionBuilderConfigurer(List<InetSocketAddress> addressList, DriverConfigLoader driverConfigLoader, String dataCenter) {
SessionBuilderConfigurerModel configurerModel = new SessionBuilderConfigurerModel();
configurerModel.setAddressList(addressList);
configurerModel.setDataCenter(dataCenter);
configurerModel.setDriverConfigLoader(driverConfigLoader);
configurerModel.setKeyspaceName(keyspaceName);
configurerModel.setPassword(password);
configurerModel.setUserName(userName);
return getSessionBuilderConfigurer(configurerModel);
}
private SessionBuilderConfigurer getSessionBuilderConfigurer(SessionBuilderConfigurerModel configurerModel) {
return new SessionBuilderConfigurer() {
@Override
public CqlSessionBuilder configure(CqlSessionBuilder sessionBuilder) {
DriverConfigLoader driverConfigLoader = configurerModel.getDriverConfigLoader();
sessionBuilder.addContactPoints(configurerModel.getAddressList())
.withConfigLoader(driverConfigLoader)
.withLocalDatacenter(configurerModel.getDataCenter())
.withKeyspace(configurerModel.getKeyspaceName())
.withAuthCredentials(configurerModel.getUserName(), configurerModel.getPassword());
return sessionBuilder;
}
};
}
private List<InetSocketAddress> getInetSoketAddress(String contactPoints) {
List<InetSocketAddress> addressList = new ArrayList<>();
StringUtils.commaDelimitedListToSet(contactPoints)
.forEach(host -> addressList.add(new InetSocketAddress(host, port)));
return addressList;
}
}
File: SessionBuilderConfigurerModel.java
package com.myorg.aiml.config;
import com.datastax.oss.driver.api.core.config.DriverConfigLoader; import lombok.Data; import org.springframework.context.ApplicationContext;
import java.net.InetSocketAddress; import java.util.List;
@Data
public class SessionBuilderConfigurerModel {
List
File3: ackage com.myorg.aiml.repo;
import com.myorg.aiml.model.MyUserAccount; import com.myorg.aiml.model.UserAccount;
import java.util.List; import org.springframework.data.cassandra.repository.CassandraRepository; import org.springframework.stereotype.Repository;
@Repository
public interface AccntsByUseridRepo extends CassandraRepository<MyUserAccount, String> {
public List
File4: application.properties spring.autoconfigure.exclude=org.springframework.boot.actuate.autoconfigure.metrics.MetricsAspectsAutoConfiguration spring.application.name=mycassandra server.servlet.context-path=/ server.port=8075
CASSANDRA_HOSTS=localhost CASSANDRA_PORT=9042 CASSANDRA_KEYSPACE=accountdb CASSANDRA_USERNAME=cassandra CASSANDRA_PASSWORD=cassandra CASSANDRA_LOCAL_DC=datacenter1 session_bean_consistency_level=LOCAL_ONE cassandra_query_request_timeout=2000 milliseconds date_limit_duration_in_days=30 date_time_limit_duration_in_days=30
File5: Readme
download docker desktop
run commands:
docker run --name mycass -p 9042:9042 -d cassandra:3.11.5
docker exec -it mycass cqlsh
cqlsh> CREATE KEYSPACE accountdb WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };
cqlsh> create table account_tbl (name text, status boolean, createts timestamp, userid text, primary key (userid));
cqlsh> insert into account_tbl (name , status , createts , userid) values ('john', true, toTimeStamp(now()), 'idjohn');
cqlsh> select * from account_tbl;
start app
run following curl command: curl --location 'http://localhost:8075/Users/idjohn'
Controller., service and pom files file1: package com.myorg.aiml.controller;
import com.myorg.aiml.model.MyUserAccount; import com.myorg.aiml.model.UserAccount; import com.myorg.aiml.service.AccountsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class AccountsController {
@Autowired
private AccountsService accountsService;
@GetMapping(path="/Users/{id}")
@ResponseBody
public List
@PostMapping(path="/Users")
public void addAccount(@RequestBody MyUserAccount userAccount) {
accountsService.createAccnt(userAccount);
}
@PutMapping(path="/Users/{id}")
public void updateAccount(@PathVariable String id, @RequestBody MyUserAccount userAccount) {
accountsService.updateAccnt(userAccount);
}
}
file2: package com.myorg.aiml.service;
import com.myorg.aiml.model.MyUserAccount; import com.myorg.aiml.model.UserAccount; import com.myorg.aiml.repo.AccntsByUseridRepo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.cassandra.CassandraConnectionFailureException; import org.springframework.data.cassandra.CassandraInvalidQueryException; import org.springframework.stereotype.Service;
import java.util.*; import java.util.stream.Collectors;
@Service
public class AccountsService {
private static final Logger logger = LoggerFactory.getLogger(AccountsService.class);
@Autowired
AccntsByUseridRepo accntsByUseridRepo;
public List
public void createAccnt(MyUserAccount userAccount) {
try {
accntsByUseridRepo.save(userAccount);
} catch (CassandraInvalidQueryException e) {
throw e;
}
}
public void updateAccnt(MyUserAccount userAccount) {
try {
accntsByUseridRepo.save(userAccount);
} catch (Exception e) {
throw e;
}
}
}
file3: package com.myorg.aiml.model;
import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; import org.joda.time.DateTime; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.data.cassandra.core.cql.PrimaryKeyType; import org.springframework.data.cassandra.core.mapping.Column; import org.springframework.data.cassandra.core.mapping.PrimaryKeyColumn; import org.springframework.data.cassandra.core.mapping.Table;
import java.io.Serializable;
@EntityScan @Table("account_tbl") @Getter @Setter @RequiredArgsConstructor @AllArgsConstructor public class MyUserAccount implements Serializable { // create table account_tbl (name text, status boolean, createts timestamp, userid text, primary key (userid)); // insert into account_tbl (name , status , createts , userid) values ('john', true, toTimeStamp(now()), 'idjohn'); private static final long serialVersionUID = 1L; @Column("name") private String name; @Column("status") private Boolean status; @Column("status") private DateTime createts; @PrimaryKeyColumn(name = "userid", type = PrimaryKeyType.PARTITIONED) @Column("userid") private String userid; }
file4: package com.myorg.aiml;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@SpringBootApplication(scanBasePackages = "com.myorg") @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class }) public class CrudGraphQlApplication {
public static void main(String[] args){
SpringApplication.run(CrudGraphQlApplication.class, args);
}
}
file5: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <project xmlns=http://maven.apache.org/POM/4.0.0 xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation=http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
<relativePath />
</parent>
<groupId>com.myorg.aiml</groupId>
<artifactId>custom-conversions-sample</artifactId>
<version>2.0.0</version>
<name>custom-conversions-sample</name>
<description>custom-conversions-sample</description>
<!-- Start SpringBoot Dependencies -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope> </dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tinkerpop</groupId>
<artifactId>gremlin-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tinkerpop</groupId>
<artifactId>gremlin-shaded</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
</plugins>
</build>
@Bean("cassandraTemplate")
@Primary
public CassandraTemplate cassandraTemplate(CqlSessionFactoryBean session, CassandraCustomConversions ccv) {
CassandraTemplate ct = new CassandraTemplate(session.getObject());
return ct;
}
Well, if you spin up a custom CassandraTemplate
that isn't wired with CassandraCustomConversions
(ideally through CassandraMappingContext
and MappingCassandraConverter
), then your converters won't get applied.
I need help in wiring the conversions to CassandraTemplate. I have uploaded code to github: https://github.com/thaparraj/custom-conversions-sample.git
I started getting the exception after I upgraded to spring-data-commons-3.2.1 and spring-data-cassandra-4.2.1.
I added the custom conversions (below) but still get the error