I'm doing some research bout spring-data-cassandra-reactive
and it looks like I can't figure out or find the right documentation about this.
According to the documentation you can create an interface
which is annotated with @Repository
and then use annotations to create custom queries that will retrieve the data you want. The code would look something like this:
@Repository
public interface UserRepository
extends ReactiveCassandraRepository<UserEntity, UUID>
{
@Query("SELECT u FROM UserEntity u WHERE username = :user ALLOW FILTERING")
Mono<UserEntity> findUserEntityByUsername(@Param("user") String user);
/**
* This is just to illustrate/simulate some custom/advanced logic that cannot be
* done via @Query()
*/
default Mono<UserEntity> saveWithBase64EncodedPassword(UserEntity entity)
{
String encodedPassword = Base64.getEncoder().encodeToString(entity.getPassword().getBytes());
entity.updatePassword(encodedPassword);
return this.save(entity);
}
}
@Table(UserEntity.TABLE_NAME)
public class UserEntity
{
public final static String TABLE_NAME = "users";
@PrimaryKeyColumn(name = "uuid", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
@CassandraType(type = CassandraType.Name.UUID)
@Column
private UUID id;
@Column
@CassandraType(type = CassandraType.Name.VARCHAR)
private String username;
@Column
@CassandraType(type = CassandraType.Name.VARCHAR)
private String password;
public UserEntity()
{
this.id = UUID.randomUUID();
}
public UserEntity(String username, String password)
{
this.id = UUID.randomUUID();
this.username = username;
this.password = password;
}
public UUID getId()
{
return id;
}
public void setId(UUID id)
{
this.id = id;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public void updatePassword(String newPassword)
{
this.password = newPassword;
}
}
Dependencies:
plugins {
id("org.springframework.boot") version "2.6.6"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
}
dependencies {
// Embedded Cassandra Server - used for testing.
implementation("com.github.nosan:embedded-cassandra-spring-boot-starter:4.1.0")
// Spring Data Cassandra Dependencies
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("org.springframework.boot:spring-boot-starter-data-cassandra-reactive")
testImplementation("org.springframework.boot:spring-boot-starter-test") {
exclude("org.junit.vintage:junit-vintage-engine")
exclude("com.vaadin.external.google:android-json")
}
testImplementation("io.projectreactor:reactor-test")
// /Spring Data Cassandra Dependencies
}
This, so far, works fine. However, I'm trying to figure out how to switch to implementing the interface in order to be able to use @Autowire
(i.e. in this example code to autowire
org.springframework.security.crypto.password.PasswordEncoder
)
Surfing through the code in the spring-data-cassandra
jar I noticed there's a class named org.springframework.data.cassandra.repository.support.SimpleReactiveCassandraRepository
which you can extend from. It already has most of the common things you would need implemented for you which is why it looks like the perfect candidate to extend
from.
And here comes the problem - it requires CassandraEntityInformation<T, ID> metadata
.
I cannot seem to find where this is taken from or how it's supposed to be auto-wired and I feel like I might be missing something or maybe a dependency.
Any ideas?
SimpleReactiveCassandraRepository
is a great class as it gives you access to ReactiveCassandraOperations
and as such to CqlSession
. It is a great way to have fine grained operations. (LWT, Bacthes)
You are correct the different classes would be autowired. Here is a sample code:
@Repository
public class OwnerReactiveCassandraRepository extends SimpleReactiveCassandraRepository<OwnerEntitySpring, UUID> {
protected final CqlSession cqlSession;
protected final ReactiveCassandraOperations reactiveCassandraTemplate;
@SuppressWarnings("unchecked")
public OwnerReactiveCassandraRepository(CqlSession cqlSession, ReactiveCassandraOperations ops) {
super(new MappingCassandraEntityInformation<OwnerEntitySpring, UUID>(
(CassandraPersistentEntity<OwnerEntitySpring>) ops.getConverter().getMappingContext()
.getRequiredPersistentEntity(OwnerEntitySpring.class), ops.getConverter()), ops);
this.cqlSession = cqlSession;
this.reactiveCassandraTemplate = ops;
}
public Flux<OwnerEntitySpring> searchByOwnerName(String ownerLastName) {
return reactiveCassandraTemplate.getReactiveCqlOperations()
.query(SimpleStatement
.builder("SELECT * FROM " + TABLE_NAME + " WHERE " + COLUMN_LASTNAME + "=?")
.addPositionalValues(ownerLastName)
.build(), (row, rownum) -> new OwnerEntitySpring(row));
}
TLDR; I implemented the Spring PetClinic with Spring data Reactive and you can have access to the full code here It is a step by step workshop with the code. You may want to look specially at this folder
In the project you will find reactive with the drivers only
, reactive with CassandraRepositories
and reactive with SimpleCassandraRepositories
. (Check the TEST folder)