Polish "Auto-configure CqlTemplate and ReactiveCqlTemplate"

See gh-44291
This commit is contained in:
Stéphane Nicoll 2025-02-17 09:14:26 +01:00
parent e8661f6bee
commit 8d713fb6c7
5 changed files with 87 additions and 99 deletions

View File

@ -116,18 +116,18 @@ public class CassandraDataAutoConfiguration {
return session;
}
@Bean
@ConditionalOnMissingBean(CassandraOperations.class)
public CassandraTemplate cassandraTemplate(SessionFactory sessionFactory, CassandraConverter converter) {
return new CassandraTemplate(sessionFactory, converter);
}
@Bean
@ConditionalOnMissingBean(CqlOperations.class)
public CqlTemplate cqlTemplate(SessionFactory sessionFactory) {
return new CqlTemplate(sessionFactory);
}
@Bean
@ConditionalOnMissingBean(CassandraOperations.class)
public CassandraTemplate cassandraTemplate(CqlTemplate cqlTemplate, CassandraConverter converter) {
return new CassandraTemplate(cqlTemplate, converter);
}
@Bean
@ConditionalOnMissingBean
public CassandraCustomConversions cassandraCustomConversions() {

View File

@ -60,17 +60,17 @@ public class CassandraReactiveDataAutoConfiguration {
return new DefaultReactiveSessionFactory(reactiveCassandraSession);
}
@Bean
@ConditionalOnMissingBean(ReactiveCassandraOperations.class)
public ReactiveCassandraTemplate reactiveCassandraTemplate(ReactiveSession reactiveCassandraSession,
CassandraConverter converter) {
return new ReactiveCassandraTemplate(reactiveCassandraSession, converter);
}
@Bean
@ConditionalOnMissingBean(ReactiveCqlOperations.class)
public ReactiveCqlTemplate reactiveCqlTemplate(ReactiveSessionFactory reactiveCassandraSessionFactory) {
return new ReactiveCqlTemplate(reactiveCassandraSessionFactory);
}
@Bean
@ConditionalOnMissingBean(ReactiveCassandraOperations.class)
public ReactiveCassandraTemplate reactiveCassandraTemplate(ReactiveCqlTemplate reactiveCqlTemplate,
CassandraConverter converter) {
return new ReactiveCassandraTemplate(reactiveCqlTemplate, converter);
}
}

View File

@ -19,13 +19,13 @@ package org.springframework.boot.autoconfigure.data.cassandra;
import java.util.Collections;
import com.datastax.oss.driver.api.core.CqlSession;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.data.cassandra.city.City;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -36,9 +36,6 @@ import org.springframework.data.cassandra.core.convert.CassandraCustomConversion
import org.springframework.data.cassandra.core.cql.CqlTemplate;
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver;
import org.springframework.data.domain.ManagedTypes;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.ObjectUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -51,80 +48,81 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
class CassandraDataAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.cassandra.keyspaceName=boot_test")
.withUserConfiguration(CassandraMockConfiguration.class)
.withConfiguration(
AutoConfigurations.of(CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class));
@AfterEach
void close() {
if (this.context != null) {
this.context.close();
}
@Test
void cqlTemplateExists() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(CqlTemplate.class));
}
@Test
void templateExists() {
load(CassandraMockConfiguration.class);
assertThat(this.context.getBeanNamesForType(CassandraTemplate.class)).hasSize(1);
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(CassandraTemplate.class));
}
@Test
void cqlTemplateExists() {
load(CassandraMockConfiguration.class);
assertThat(this.context.getBeanNamesForType(CqlTemplate.class)).hasSize(1);
void templateUsesCqlTemplate() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(CassandraTemplate.class);
assertThat(context.getBean(CassandraTemplate.class).getCqlOperations())
.isSameAs(context.getBean(CqlTemplate.class));
});
}
@Test
void entityScanShouldSetManagedTypes() {
load(EntityScanConfig.class);
CassandraMappingContext mappingContext = this.context.getBean(CassandraMappingContext.class);
ManagedTypes managedTypes = (ManagedTypes) ReflectionTestUtils.getField(mappingContext, "managedTypes");
assertThat(managedTypes.toList()).containsOnly(City.class);
this.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> {
assertThat(context).hasSingleBean(CassandraMappingContext.class);
CassandraMappingContext mappingContext = context.getBean(CassandraMappingContext.class);
assertThat(mappingContext.getManagedTypes()).singleElement()
.satisfies((typeInformation) -> assertThat(typeInformation.getType()).isEqualTo(City.class));
});
}
@Test
void userTypeResolverShouldBeSet() {
load();
CassandraConverter cassandraConverter = this.context.getBean(CassandraConverter.class);
assertThat(cassandraConverter).extracting("userTypeResolver").isInstanceOf(SimpleUserTypeResolver.class);
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(CassandraConverter.class);
assertThat(context.getBean(CassandraConverter.class)).extracting("userTypeResolver")
.isInstanceOf(SimpleUserTypeResolver.class);
});
}
@Test
void codecRegistryShouldBeSet() {
load();
CassandraConverter cassandraConverter = this.context.getBean(CassandraConverter.class);
assertThat(cassandraConverter.getCodecRegistry())
.isSameAs(this.context.getBean(CassandraMockConfiguration.class).codecRegistry);
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(CassandraConverter.class);
assertThat(context.getBean(CassandraConverter.class).getCodecRegistry())
.isSameAs(context.getBean(CassandraMockConfiguration.class).codecRegistry);
});
}
@Test
void defaultConversions() {
load();
CassandraTemplate template = this.context.getBean(CassandraTemplate.class);
assertThat(template.getConverter().getConversionService().canConvert(Person.class, String.class)).isFalse();
this.contextRunner.run((context) -> {
CassandraTemplate template = context.getBean(CassandraTemplate.class);
assertThat(template.getConverter().getConversionService().canConvert(Person.class, String.class)).isFalse();
});
}
@Test
void customConversions() {
load(CustomConversionConfig.class);
CassandraTemplate template = this.context.getBean(CassandraTemplate.class);
assertThat(template.getConverter().getConversionService().canConvert(Person.class, String.class)).isTrue();
this.contextRunner.withUserConfiguration(CustomConversionConfig.class).run((context) -> {
CassandraTemplate template = context.getBean(CassandraTemplate.class);
assertThat(template.getConverter().getConversionService().canConvert(Person.class, String.class)).isTrue();
});
}
@Test
void clusterDoesNotExist() {
this.context = new AnnotationConfigApplicationContext(CassandraDataAutoConfiguration.class);
assertThat(this.context.getBeansOfType(CqlSession.class)).isEmpty();
}
void load(Class<?>... config) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
TestPropertyValues.of("spring.cassandra.keyspaceName:boot_test").applyTo(ctx);
if (!ObjectUtils.isEmpty(config)) {
ctx.register(config);
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
CassandraDataAutoConfiguration.class)) {
assertThat(context.getBeansOfType(CqlSession.class)).isEmpty();
}
ctx.register(CassandraMockConfiguration.class, CassandraAutoConfiguration.class,
CassandraDataAutoConfiguration.class);
ctx.refresh();
this.context = ctx;
}
@Configuration(proxyBeanMethods = false)

View File

@ -16,22 +16,19 @@
package org.springframework.boot.autoconfigure.data.cassandra;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.data.cassandra.city.City;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.core.ReactiveCassandraTemplate;
import org.springframework.data.cassandra.core.convert.CassandraConverter;
import org.springframework.data.cassandra.core.cql.ReactiveCqlTemplate;
import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver;
import org.springframework.data.domain.ManagedTypes;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -44,56 +41,49 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
class CassandraReactiveDataAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.cassandra.keyspaceName=boot_test")
.withUserConfiguration(CassandraMockConfiguration.class)
.withConfiguration(AutoConfigurations.of(CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class,
CassandraReactiveDataAutoConfiguration.class));
@AfterEach
void close() {
if (this.context != null) {
this.context.close();
}
@Test
void reactiveCqlTemplateExists() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ReactiveCqlTemplate.class));
}
@Test
void templateExists() {
load("spring.cassandra.keyspaceName:boot_test");
assertThat(this.context.getBeanNamesForType(ReactiveCassandraTemplate.class)).hasSize(1);
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ReactiveCassandraTemplate.class));
}
@Test
void reactiveCqlTemplateExists() {
load("spring.cassandra.keyspaceName:boot_test");
assertThat(this.context.getBeanNamesForType(ReactiveCqlTemplate.class)).hasSize(1);
void templateUsesReactiveCqlTemplate() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(ReactiveCassandraTemplate.class);
assertThat(context.getBean(ReactiveCassandraTemplate.class).getReactiveCqlOperations())
.isSameAs(context.getBean(ReactiveCqlTemplate.class));
});
}
@Test
void entityScanShouldSetManagedTypes() {
load(EntityScanConfig.class, "spring.cassandra.keyspaceName:boot_test");
CassandraMappingContext mappingContext = this.context.getBean(CassandraMappingContext.class);
ManagedTypes managedTypes = (ManagedTypes) ReflectionTestUtils.getField(mappingContext, "managedTypes");
assertThat(managedTypes.toList()).containsOnly(City.class);
this.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> {
assertThat(context).hasSingleBean(CassandraMappingContext.class);
CassandraMappingContext mappingContext = context.getBean(CassandraMappingContext.class);
assertThat(mappingContext.getManagedTypes()).singleElement()
.satisfies((typeInformation) -> assertThat(typeInformation.getType()).isEqualTo(City.class));
});
}
@Test
void userTypeResolverShouldBeSet() {
load("spring.cassandra.keyspaceName:boot_test");
CassandraConverter cassandraConverter = this.context.getBean(CassandraConverter.class);
assertThat(cassandraConverter).extracting("userTypeResolver").isInstanceOf(SimpleUserTypeResolver.class);
}
private void load(String... environment) {
load(null, environment);
}
private void load(Class<?> config, String... environment) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
TestPropertyValues.of(environment).applyTo(ctx);
if (config != null) {
ctx.register(config);
}
ctx.register(CassandraMockConfiguration.class, CassandraAutoConfiguration.class,
CassandraDataAutoConfiguration.class, CassandraReactiveDataAutoConfiguration.class);
ctx.refresh();
this.context = ctx;
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(CassandraConverter.class);
assertThat(context).hasSingleBean(CassandraConverter.class);
assertThat(context.getBean(CassandraConverter.class)).extracting("userTypeResolver")
.isInstanceOf(SimpleUserTypeResolver.class);
});
}
@Configuration(proxyBeanMethods = false)

View File

@ -440,7 +440,7 @@ There is a `spring-boot-starter-data-cassandra` starter for collecting the depen
[[data.nosql.cassandra.connecting]]
=== Connecting to Cassandra
You can inject an auto-configured javadoc:org.springframework.data.cassandra.core.CassandraTemplate[] or a Cassandra `CqlSession` instance as you would with any other Spring Bean.
You can inject an auto-configured javadoc:org.springframework.data.cassandra.core.cql.CqlTemplate[], javadoc:org.springframework.data.cassandra.core.CassandraTemplate[], or a Cassandra `CqlSession` instance as you would with any other Spring Bean.
The `spring.cassandra.*` properties can be used to customize the connection.
Generally, you provide `keyspace-name` and `contact-points` as well the local datacenter name, as shown in the following example: