diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 000000000..568014294
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,12 @@
+
+
+- [ ] You have read the [Spring Data contribution guidelines](https://github.com/spring-projects/spring-data-build/blob/main/CONTRIBUTING.adoc).
+- [ ] You use the code formatters provided [here](https://github.com/spring-projects/spring-data-build/tree/main/etc/ide) and have them applied to your changes. Don’t submit any formatting related changes.
+- [ ] You submit test cases (unit or integration tests) that back your changes.
+- [ ] You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).
+
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
new file mode 100644
index 000000000..20dd84a5d
--- /dev/null
+++ b/.github/workflows/build.yaml
@@ -0,0 +1,27 @@
+name: CI Build
+
+on:
+ push:
+ branches: [ main ]
+
+jobs:
+ build:
+ name: Build project
+ runs-on: ubuntu-latest
+
+ steps:
+
+ - name: Check out sources
+ uses: actions/checkout@v4
+
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin'
+ java-version: 17
+ cache: 'maven'
+
+ - name: Build with Maven
+ env:
+ DEVELOCITY_ACCESS_KEY: ${{ secrets.GRADLE_ENTERPRISE_SECRET_ACCESS_KEY }}
+ run: ./mvnw clean verify -B -Pci
diff --git a/.github/workflows/project.yml b/.github/workflows/project.yml
new file mode 100644
index 000000000..606226523
--- /dev/null
+++ b/.github/workflows/project.yml
@@ -0,0 +1,47 @@
+# GitHub Actions to automate GitHub issues for Spring Data Project Management
+
+name: Spring Data GitHub Issues
+
+on:
+ issues:
+ types: [opened, edited, reopened]
+ issue_comment:
+ types: [created]
+ pull_request_target:
+ types: [opened, edited, reopened]
+
+jobs:
+ Inbox:
+ runs-on: ubuntu-latest
+ if: github.repository_owner == 'spring-projects' && (github.event.action == 'opened' || github.event.action == 'reopened') && github.event.pull_request == null
+ steps:
+ - name: Create or Update Issue Card
+ uses: peter-evans/create-or-update-project-card@v1.1.2
+ with:
+ project-name: 'Spring Data'
+ column-name: 'Inbox'
+ project-location: 'spring-projects'
+ token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
+ Pull-Request:
+ runs-on: ubuntu-latest
+ if: github.repository_owner == 'spring-projects' && (github.event.action == 'opened' || github.event.action == 'reopened') && github.event.pull_request != null
+ steps:
+ - name: Create or Update Pull Request Card
+ uses: peter-evans/create-or-update-project-card@v1.1.2
+ with:
+ project-name: 'Spring Data'
+ column-name: 'Review pending'
+ project-location: 'spring-projects'
+ issue-number: ${{ github.event.pull_request.number }}
+ token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
+ Feedback-Provided:
+ runs-on: ubuntu-latest
+ if: github.repository_owner == 'spring-projects' && github.event_name == 'issue_comment' && github.event.action == 'created' && github.actor != 'spring-projects-issues' && github.event.pull_request == null && github.event.issue.state == 'open' && contains(toJSON(github.event.issue.labels), 'waiting-for-feedback')
+ steps:
+ - name: Update Project Card
+ uses: peter-evans/create-or-update-project-card@v1.1.2
+ with:
+ project-name: 'Spring Data'
+ column-name: 'Feedback provided'
+ project-location: 'spring-projects'
+ token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
diff --git a/.gitignore b/.gitignore
index 8a95788e7..7cc5f4de1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,15 @@
.project
.classpath
.springBeans
+.develocity/
.settings/
target/
+.mvn/.gradle-enterprise
#IntelliJ Stuff
.idea
*.iml
+
+#Geode Stuff
+*.log
+*.dat
diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml
new file mode 100644
index 000000000..1e3bb355f
--- /dev/null
+++ b/.mvn/extensions.xml
@@ -0,0 +1,8 @@
+
+
+
+ io.spring.develocity.conventions
+ develocity-conventions-maven-extension
+ 0.0.19
+
+
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 000000000..c1dd12f17
Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 000000000..b7cb93e70
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
diff --git a/.travis.yml b/.travis.yml
index 41503a712..abfaad348 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,18 +1,40 @@
language: java
-jdk:
- - oraclejdk8
+os: linux
+
+jobs:
+ include:
+ - env: JDK='OpenJDK 16'
+ before_install: wget https://github.com/sormuras/bach/raw/master/install-jdk.sh && . ./install-jdk.sh -f 16
+
+addons:
+ apt:
+ sources:
+ - sourceline: 'deb http://packages.couchbase.com/releases/couchbase-server/community/deb/ xenial xenial/main'
+ key_url: 'http://packages.couchbase.com/ubuntu/couchbase.key'
+ packages:
+ - couchbase-server-community
services:
- - redis-server
- - cassandra
+ - redis
+ - docker
cache:
directories:
- $HOME/.m2
+ - download
-sudo: false
-
-install: true
+# See https://issues.couchbase.com/browse/MB-26556
+install:
+ - curl -X POST http://127.0.0.1:8091/pools/default -d memoryQuota=2000 -d indexMemoryQuota=256 -d ftsMemoryQuota=256
+ - curl -X POST http://127.0.0.1:8091/node/controller/setupServices -d "services=kv,index,n1ql,fts"
+ - curl -X POST http://127.0.0.1:8091/settings/indexes -d "storageMode=forestdb"
+ - curl -X POST http://127.0.0.1:8091/settings/web -d "username=Administrator&password=password&port=8091&"
+ - /opt/couchbase/bin/cbdocloader -c 127.0.0.1:8091 -u Administrator -p password -b travel-sample -m 256 -d /opt/couchbase/samples/travel-sample.zip
+ - /opt/couchbase/bin/couchbase-cli user-manage -c 127.0.0.1:8091 -u Administrator -p password --set --rbac-username=travel-sample --rbac-password=password --roles=admin --auth-domain local
-script: "mvn clean dependency:list test -Dsort"
+script:
+ - cp -f settings.xml $HOME/.m2/settings.xml
+ - mvn -version
+ - java -version
+ - mvn clean test -U -Dsort -Dmaven.test.redirectTestOutputToFile=true -B -s settings.xml
diff --git a/LICENSE b/LICENSE
index e06d20818..8d50b18f3 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
Apache License
Version 2.0, January 2004
- http://www.apache.org/licenses/
+ https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
@@ -192,7 +192,7 @@ Apache License
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
diff --git a/README.adoc b/README.adoc
new file mode 100644
index 000000000..43d26ddbd
--- /dev/null
+++ b/README.adoc
@@ -0,0 +1,130 @@
+= Spring Data Examples image:https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Develocity", link="https://ge.spring.io/scans?search.rootProjectNames=Spring%20Data%20-%20Examples"]
+
+image:https://travis-ci.org/spring-projects/spring-data-examples.svg?branch=main[Build Status,link=https://travis-ci.org/spring-projects/spring-data-examples]
+
+This repository contains example projects for the different Spring Data modules to showcase the API and how to use the features provided by the modules.
+
+We have separate folders for the samples of individual modules:
+
+== Spring Data for Apache Cassandra
+
+* `example` - Shows core Spring Data support for Apache Cassandra.
+* `kotlin` - Example for using Cassandra with Kotlin.
+* `reactive` - Example project to show reactive template and repository support.
+
+== Spring Data Elasticsearch
+
+* `example` - Example how to use basic text search, geo-spatial search and facets. It uses
+ the High Level REST Client backing template and repository.
+* `reactive` - Example how to use reactive client, template and repository features.
+
+Local Elasticsearch instance must be running to run the tests.
+
+== Spring Data JDBC
+
+* `basic` - Basic usage of Spring Data JDBC.
+* `graalvm-native` - This example compiles a basic Spring Data JDBC application into a GraalVM native image.
+* `howto` - A collection of projects to go with the https://spring.io/blog/2021/09/09/spring-data-jdbc-how-to-use-custom-id-generation[Spring Data JDBC - How to blog posts].
+* `immutables` - Showing Spring Data JDBC usage
+ with https://immutables.github.io/[Immutables]
+* `jmolecules` - Demonstrates the interaction of jMolecules with Spring Data JDBC.
+* `jooq` - Demonstrates how to use jOOQ and Spring Data JDBC together.
+* `mybatis` - Demonstrate how to use MyBatis to generate SQL for Spring Data JDBC.
+* `singlequeryloading` - Demonstrates how to enable Single Query Loading.
+
+== Spring Data JPA
+
+* `eclipselink` - Sample project to show how to use Spring Data JPA with Spring Boot and https://www.eclipse.org/eclipselink/[Eclipselink].
+* `example` - Probably the project you want to have a look at first.
+Contains a variety of sample packages, showcasing the different levels at which you can use Spring Data JPA.
+Have a look at the `simple` package for the most basic setup.
+Contains also examples running on Virtual Threads.
+* `interceptors` - Example of how to enrich the repositories with AOP.
+* `jpa21` - Shows support for JPA 2.1 specific features (stored procedures support).
+* `multiple-datasources` - Examples of how to use Spring Data JPA with multiple `DataSource`s.
+* `query-by-example` - Example project showing usage of Query by Example with Spring Data JPA.
+* `security` - Example of how to integrate Spring Data JPA Repositories with Spring Security.
+* `showcase` - Refactoring show case of how to improve a plain-JPA-based persistence layer by using Spring Data JPA (read: removing close to all of the implementation code).Follow the `demo.txt` file for detailed instructions.
+* `vavr` - Shows the support of https://www.vavr.io[Vavr] collection types as return types for query methods.
+
+== Spring Data LDAP
+
+* `example` - Sample for Spring Data repositories to access an LDAP store.
+
+== Spring Data MongoDB
+
+* `aggregation` - Example project to showcase the MongoDB aggregation framework support.
+* `example` - Example project for general repository functionality (including geo-spatial functionality), Querydsl integration and advanced topics.
+* `fluent-api` - Example project to show the new fluent API (`MongoTemplate`-alternative) to interact with MongoDB.
+* `geo-json` - Example project showing usage of http://geojson.org[GeoJSON] with MongoDB.
+* `gridfs` - Example project showing usage of gridFS with MongoDB.
+* `jmolecules` - Example of Spring Data MongoDB working with a jMolecules based domain model.
+* `kotlin` - Example for using https://kotlinlang.org/[Kotlin] with MongoDB.
+* `linking` - Example demonstrating possibilities for linking documents.
+* `query-by-example` - Example project showing usage of Query by Example with MongoDB.
+* `querydsl` - Example project showing imperative and reactive https://github.com/querydsl/querydsl[Querydsl] support for MongoDB.
+* `reactive` - Example project to show reactive template and repository support.
+* `repository-metrics` - Example project to show how to collect repository method invocation metrics.
+* `security` - Example project showing usage of Spring Security with MongoDB.
+* `text-search` - Example project showing usage of MongoDB text search feature.
+* `transactions` - Example project for imperative and reactive MongoDB 4.0 transaction support.
+
+== Spring Data Neo4j
+
+* `example` - Example to show basic node and relationship entities and repository usage.
+
+== Spring Data R2DBC
+
+* `example` - Basic usage of Spring Data R2DBC.
+
+== Spring Data Redis
+
+* `cluster` - Example for Redis Cluster support.
+* `example` - Example for basic Spring Data Redis setup.
+* `pubsub` - Example project to show Pub/Sub usage using Platform and Virtual Threads.
+* `reactive` - Example project to show reactive template support.
+* `repositories` - Example demonstrating Spring Data repository abstraction on top of Redis.
+* `sentinel` - Example for Redis Sentinel support.
+* `streams` - Example for https://redis.io/topics/streams-intro[Redis Streams] support.
+
+Local Redis instances must be running to run the tests. One option is to use Docker in a separate terminal:
+
+```
+$ docker run -p 6379:6379 redis:5.0
+```
+
+WARNING: If you're done using it, don't forget to shut it down!
+
+== Spring Data REST
+
+* `headers` - A sample showing the population of HTTP headers and the usage of them to perform conditional `GET` requests.
+* `multi-store` - A sample REST web-service based on both Spring Data JPA and Spring Data MongoDB.
+* `projections` - A sample REST web-service showing how to use projections.
+* `security` - A sample REST web-service secured using Spring Security.
+* `starbucks` - A sample REST web-service built with Spring Data REST and MongoDB.
+* `uri-customizations` - Example project to show URI customization capabilities.
+
+== Spring Data web support
+
+* `projections` - Example for Spring Data web support for JSONPath and XPath expressions on projection interfaces.
+* `querydsl` - Example for Spring Data Querydsl web integration (creating a `Predicate` from web requests).
+* `web` - Example for Spring Data web integration (binding `Pageable` instances to Spring MVC controller methods, using interfaces to bind Spring MVC request payloads).
+
+== Miscellaneous
+
+* `mongodb/fragment-spi` - Example project how to use Spring Data Fragment SPI to provide reusable custom extensions.
+* `bom` - Example project how to use the Spring Data release train bom in non-Spring-Boot scenarios.
+* `map` - Example project to show how to use `Map`-backed repositories.
+* `multi-store` - Example project to use both Spring Data MongoDB and Spring Data JPA in
+ one project.
+
+== Note
+
+* The example projects make use of the https://projectlombok.org/[Lombok] plugin. To get
+ proper code navigation in your IDE, you must install it separately. Lombok is available
+ in the IntelliJ plugins repository and as
+ a https://projectlombok.org/download[download] for Eclipse-based IDEs.
+* The code makes use of Java 16 language features therefore you need Java 16 or newer to
+ run and compile the examples.
+* Most store modules examples start their database via Testcontainers or as
+ embedded/in-memory server unless stated otherwise.
diff --git a/README.md b/README.md
deleted file mode 100644
index a9226a219..000000000
--- a/README.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Spring Data Examples
-
-[](https://travis-ci.org/spring-projects/spring-data-examples)
-
-This repository contains example projects for the different Spring Data modules to showcase the API and how to use the features provided by the modules.
-
-We have separate folders for the samples of individual modules:
-
-## Spring Data JPA
-
-* `example` - Probably the project you want to have a look at first. Contains a variety of sample packages, showcasing the different levels at which you can use Spring Data JPA. Have a look at the `simple` package for the most basic setup.
-* `java8` - Example of how to use Spring Data JPA auditing with Java 8 date time types as well as the usage of `Optional` as return type for repository methods. Note, this project requires to be build with JDK 8.
-* `showcase` - Refactoring show case of how to improve a plain-JPA-based persistence layer by using Spring Data JPA (read: removing close to all of the implementation code). Follow the `demo.txt` file for detailed instructions.
-* `interceptors` - Example of how to enrich the repositories with AOP.
-* `security` - Example of how to integrate Spring Data JPA Repositories with Spring Security.
-* `multiple-datasources` - Examples of how to use Spring Data JPA with multiple `DataSource`s.
-* `query-by-example` - Example project showing usage of Query by Example with MongoDB.
-
-## Spring Data MongoDB
-
-* `example` - Example project for general repository functionality (including geo-spatial functionality), Querydsl integration and advanced topics.
-* `java8` - Example of how to use Spring Data MongoDB with Java 8 date time types as well as the usage of `Optional` as return type for repository methods. Note, this project requires to be build with JDK 8.
-* `aggregation` - Example project to showcase the MongoDB aggregation framework support.
-* `text-search` - Example project showing usage of MongoDB text search feature.
-* `geo-json` - Example project showing usage of [GeoJSON](http://geojson.org) with MongoDB.
-* `security` - Example project showing usage of Spring Security with MongoDB.
-* `query-by-example` - Example project showing usage of Query by Example with MongoDB.
-
-## Spring Data REST
-
-* `starbucks` - A sample REST web-service built with Spring Data REST and MongoDB.
-* `multi-store` - A sample REST web-service based on both Spring Data JPA and Spring Data MongoDB.
-* `projections` - A sample REST web-service showing how to use projections.
-* `security` - A sample REST web-service secured using Spring Security.
-* `headers` - A sample showing the population of HTTP headers and the usage of them to perform conditional `GET` requests.
-
-## Spring Data Redis
-
-* `example` - Example for basic Spring Data Redis setup.
-* `cluster` - Example for Redis Cluster support.
-* `cluster-sentinel` - Example for Redis Sentinel support.
-* `repository` - Example demonstrating Spring Data repository abstraction on top of Redis.
-
-## Spring Data Elasticsearch
-
-* `example` - Example how to use basic text search, geo-spatial search and facets.
-
-## Spring Data Neo4j
-
-* `example` - Example to show basic node and relationship entities and repository usage.
-
-## Spring Data web support
-
-* `web` - Example for Spring Data web integration (binding `Pageable` instances to Spring MVC controller methods, using interfaces to bind Spring MVCrequest payloads).
-* `querydsl` - Example for Spring Data Querydsl web integration (creating a `Predicate` from web requests).
-* `projections` - Example for Spring Data web support for JSONPath and XPath expressions on projection interfaces.
-
-## Miscellaneous
-
-* `bom` - Example project how to use the Spring Data release train bom in non-Spring-Boot scenarios.
-* `multi-store` - Example project to use both Spring Data MongoDB and Spring Data JPA in one project.
diff --git a/bom/.gitignore b/bom/.gitignore
new file mode 100644
index 000000000..99860a5f4
--- /dev/null
+++ b/bom/.gitignore
@@ -0,0 +1,3 @@
+.gradle
+/build/
+!gradle/wrapper/gradle-wrapper.jar
diff --git a/bom/README.adoc b/bom/README.adoc
index d5d910ddc..439130629 100644
--- a/bom/README.adoc
+++ b/bom/README.adoc
@@ -1,17 +1,17 @@
= Spring Data - Release Train BOM example
-This project shows the usage of the Spring Data release train in a non-Spring-Boot project with both Maven and Gradle.
+This project shows the usage of the Spring Data BOM in a non-Spring-Boot project with both Maven and Gradle.
== Properties
-In both Maven and Gradle a couple of properties are used to define the versions of Spring Framework and Spring Data to use. For Spring Framework a plain version is used. For Spring Data we refer to a particular revision of a release train. The naming of Spring Data releases uses the following conventions:
+In both Maven and Gradle a couple of properties are used to define the versions of Spring Framework and Spring Data to use. For Spring Framework a plain version is used. For Spring Data we refer to the https://spring.io/blog/2020/04/30/updates-to-spring-versions[calver revision] of the BOM. The naming of Spring Data releases uses the following conventions:
-** `${release-train}-M1` -> Milestones
+** `${calver-version}-M1` -> Milestones
** …
-** `${release-train}-RC1` -> Release candidate
+** `${calver-version}-RC1` -> Release candidate
** …
-** `${release-train}-RELEASE` -> GA version
-** `${release-train}-SR1` -> Services release (bugfixes) for that release train
+** `${calver-version}` -> GA version
+** `${calver-version}` -> Services release (bugfixes) for that release train
== Maven
@@ -19,14 +19,18 @@ The `` section declares dependencies to the BOMs for bot
The standard `` section can now list Spring Framework and Spring Data dependencies without declaring a version and still be sure all libraries are in matching versions.
-Note, that we don't declare a Spring Framework dependency here. The import of the Spring Framework BOM nonetheless makes sure we control the version of all transitive Spring Framework dependencies pulled in by the Spring Data modules.
+Note that we do not declare a Spring Framework dependency here. The import of the Spring Framework BOM nonetheless makes sure we control the version of all transitive Spring Framework dependencies pulled in by the Spring Data modules.
== Gradle
-Gradle does not support Maven BOMs out of the box so the first thing to do is to declare a buildscript dependency on the https://github.com/spring-gradle-plugins/dependency-management-plugin[dependency management plugin] and apply it to the project.
+Gradle does not support Maven BOMs (Bill of Materials) out of the box, so the first thing to do is to import the
+https://github.com/spring-gradle-plugins/dependency-management-plugin[dependency management plugin]. This example is based on Java,
+but if you need a different language plugin (e.g. Kotlin), you can do so.
-With the plugin applied, the `dependencyManagement` section can be used to import the Spring Framework and Spring Data BOMs.
+The `dependencyManagement` section can be used to import the Spring Framework BOM and Spring Data BOM.
-The standard `dependencies` section can now list Spring and Spring Data dependencies without declaring a version and still be sure all libraries are in matching versions.
+The standard `dependencies` section can now list Spring and Spring Data dependencies without declaring a version and still
+be sure all libraries are align with each other.
-Note, that we don't declare a Spring Framework dependency here. The dependency management plugin and Spring Framework BOM nonetheless makes sure we control the version of all transitive Spring Framework dependencies pulled in by the Spring Data modules.
+Note how you do not declare a Spring Framework dependency. Nevertheless, the dependency management plugin and the Spring Framework BOM
+ensures you control the version of all transitive Spring Framework dependencies pulled in by Spring Data.
diff --git a/bom/build.gradle b/bom/build.gradle
index f6ea3a357..eeef658f5 100644
--- a/bom/build.gradle
+++ b/bom/build.gradle
@@ -1,32 +1,25 @@
-buildscript {
- repositories {
- jcenter()
- }
- dependencies {
- classpath 'io.spring.gradle:dependency-management-plugin:0.5.0.RELEASE'
- }
+plugins {
+ id 'io.spring.dependency-management' version '1.0.6.RELEASE'
+ id 'java'
}
-apply plugin: 'io.spring.dependency-management'
-apply plugin: 'java'
-
-ext {
- springVersion = '4.1.6.RELEASE'
- springDataVersion = 'Fowler-RELEASE'
+repositories {
+ mavenCentral()
}
-repositories {
- jcenter()
+ext {
+ springVersion = '5.3.9'
+ springDataVersion = '2021.0.4'
}
dependencyManagement {
imports {
mavenBom "org.springframework:spring-framework-bom:${springVersion}"
- mavenBom "org.springframework.data:spring-data-releasetrain:${springDataVersion}"
+ mavenBom "org.springframework.data:spring-data-bom:${springDataVersion}"
}
}
dependencies {
compile 'org.springframework.data:spring-data-rest-webmvc'
- compile 'org.springframework.data:spring-data-mongodb'
+ compile 'org.springframework.data:spring-data-jpa'
}
diff --git a/bom/gradle/wrapper/gradle-wrapper.jar b/bom/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..135367700
Binary files /dev/null and b/bom/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/bom/gradle/wrapper/gradle-wrapper.properties b/bom/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..e0b3fb8d7
--- /dev/null
+++ b/bom/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/bom/gradlew b/bom/gradlew
new file mode 100755
index 000000000..cccdd3d51
--- /dev/null
+++ b/bom/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/bom/gradlew.bat b/bom/gradlew.bat
new file mode 100644
index 000000000..f9553162f
--- /dev/null
+++ b/bom/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/bom/pom.xml b/bom/pom.xml
index 5fcb63638..441c4d4f2 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -1,16 +1,16 @@
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0%20https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0org.springframework.data.examplesspring-data-examples-bom
- 1.0.0.BUILD-SNAPSHOT
+ 1.0.0-SNAPSHOTSpring Data - Using the BOM for dependency management
- 4.2.1.RELEASE
- Gosling-RELEASE
+ 7.0.0-M9
+ 2025.1.0-M6
@@ -26,7 +26,7 @@
org.springframework.data
- spring-data-releasetrain
+ spring-data-bom${spring-data.version}importpom
@@ -50,4 +50,27 @@
+
+
+
+
+ com.gradle
+ develocity-maven-extension
+
+
+
+
+ maven-surefire-plugin
+
+ these tests showcase Spring Data features and should always rerun
+
+
+
+
+
+
+
+
+
+
diff --git a/bom/settings.gradle b/bom/settings.gradle
new file mode 100644
index 000000000..2226b0e98
--- /dev/null
+++ b/bom/settings.gradle
@@ -0,0 +1,5 @@
+pluginManagement {
+ repositories {
+ gradlePluginPortal()
+ }
+}
diff --git a/cassandra/aot-optimization/README.adoc b/cassandra/aot-optimization/README.adoc
new file mode 100644
index 000000000..107d8743d
--- /dev/null
+++ b/cassandra/aot-optimization/README.adoc
@@ -0,0 +1,94 @@
+= Spring Data Cassandra - Ahead of Time Repository Optimization Example
+
+The project shows the usage of AOT Repositories.
+Ahead of Time Repositories implement query methods through code contribution and allow for debugging queries during runtime.
+Additionally, AOT repositories improve startup time and reduce memory consumption because AOT optimized query methods do not require reflective introspection.
+Each AOT repository is documented with a JSON file that describes the queries implemented by the repository.
+
+== Using AOT Repositories
+
+Repository AOT processing is enabled by default when using Spring Boot's AOT processing (see `pom.xml` for `spring-boot-maven-plugin` usage).
+AOT processing generates AOT artifacts to `target/spring-aot` and through the regular build.
+When using the JVM mode (not Graal Native Images), then you need to enable AOT mode on the JVM when running your application through `-Dspring.aot.enabled=true`.
+
+[source,bash]
+----
+$ mvn clean package
+$ java -Dspring.aot.enabled=true -jar target/spring-data-cassandra-aot-optimization-4.0.0-SNAPSHOT.jar
+----
+
+You can find more details about AOT processing in the https://docs.spring.io/spring-data/cassandra/reference/5.0/cassandra/repositories/aot.html#aot.repositories[Spring Data Cassandra Reference Documentation].
+
+== AOT Repository
+
+**`UserRepositoryImpl__AotRepository`**
+
+Excerpt from: `target/spring-aot/main/sources/example/springdata/cassandra/UserRepositoryImpl__AotRepository.java`
+
+[source,java]
+----
+@Generated
+public class UserRepositoryImpl__AotRepository extends AotRepositoryFragmentSupport {
+ private final CassandraOperations operations;
+
+ public UserRepositoryImpl__AotRepository(CassandraOperations operations,
+ RepositoryFactoryBeanSupport.FragmentCreationContext context) {
+ // …
+ }
+
+ public User findUserByIdIn(long id) {
+ Object[] args = new Object[1];
+ args[0] = potentiallyConvertBindingValue(id);
+ SimpleStatement query = SimpleStatement.newInstance("SELECT * from users where user_id in(?)", args);
+
+ ExecutableSelectOperation.TerminatingResults select = operations.query(query).as(User.class);
+ return select.oneValue();
+ }
+
+ public User findUserByUsername(String username) {
+ Query query = Query.query(Criteria.where("username").is(username));
+
+ ExecutableSelectOperation.TerminatingSelect select = operations.query(User.class).matching(query);
+ return select.oneValue();
+ }
+}
+----
+
+== Metadata
+
+**`UserRepository.json`**
+
+Excerpt from: `target/spring-aot/main/resources/example/springdata/cassandra/UserRepository.json`
+
+[source,json]
+----
+{
+ "name": "example.springdata.cassandra.UserRepository",
+ "module": "Cassandra",
+ "type": "IMPERATIVE",
+ "methods": [
+ {
+ "name": "findUserByIdIn",
+ "signature": "public abstract example.springdata.cassandra.User example.springdata.cassandra.UserRepository.findUserByIdIn(long)",
+ "query": {
+ "query": "SELECT * from users where user_id in(?)"
+ }
+ },
+ {
+ "name": "findUserByUsername",
+ "signature": "public abstract example.springdata.cassandra.User example.springdata.cassandra.UserRepository.findUserByUsername(java.lang.String)",
+ "query": {
+ "query": "SELECT * FROM users WHERE uname=?"
+ }
+ },
+ {
+ "name": "save",
+ "signature": "org.springframework.data.cassandra.repository.support.SimpleCassandraRepository",
+ "fragment": {
+ "interface": "org.springframework.data.cassandra.repository.support.SimpleCassandraRepository",
+ "fragment": "org.springframework.data.cassandra.repository.support.SimpleCassandraRepository"
+ }
+ }
+ ]
+}
+----
diff --git a/cassandra/aot-optimization/pom.xml b/cassandra/aot-optimization/pom.xml
new file mode 100644
index 000000000..11cedb307
--- /dev/null
+++ b/cassandra/aot-optimization/pom.xml
@@ -0,0 +1,49 @@
+
+ 4.0.0
+
+
+ org.springframework.data.examples
+ spring-data-cassandra-examples
+ 4.0.0-SNAPSHOT
+
+
+ spring-data-cassandra-aot-optimization
+ Spring Data Cassandra - AOT Optimization Example
+
+
+
+
+ ${project.groupId}
+ spring-data-cassandra-example-utils
+ ${project.version}
+ test
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ process-aot
+
+ process-aot
+
+
+
+
+
+
+
+
diff --git a/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/Address.java b/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/Address.java
new file mode 100644
index 000000000..4ae619ac8
--- /dev/null
+++ b/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/Address.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.cassandra;
+
+import org.springframework.data.cassandra.core.mapping.UserDefinedType;
+
+/**
+ * @author Mark Paluch
+ */
+@UserDefinedType
+public record Address(String street, String zip, String city) {
+
+}
diff --git a/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/AotApplication.java b/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/AotApplication.java
new file mode 100644
index 000000000..bd0cb3add
--- /dev/null
+++ b/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/AotApplication.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.cassandra;
+
+import java.util.Collections;
+
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.cassandra.core.CassandraOperations;
+import org.springframework.data.domain.Limit;
+
+/**
+ * Basic Spring Boot application.
+ *
+ * @author Mark Paluch
+ */
+@SpringBootApplication
+public class AotApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(AotApplication.class, args);
+ }
+
+ @Bean
+ CommandLineRunner commandLineRunner(UserRepository repository, CassandraOperations operations)
+ throws InterruptedException {
+
+ operations.getCqlOperations().execute("CREATE INDEX IF NOT EXISTS user_username ON users (uname);");
+ operations.getCqlOperations().execute(
+ "CREATE CUSTOM INDEX IF NOT EXISTS users_lname_idx_1 ON users (lname) USING 'org.apache.cassandra.index.sasi.SASIIndex';");
+
+ /*
+ Cassandra secondary indexes are created in the background without the possibility to check
+ whether they are available or not. So we are forced to just wait. *sigh*
+ */
+ Thread.sleep(1000);
+
+ return args -> {
+
+ User user = new User();
+ user.setId(42L);
+ user.setUsername("heisenberg");
+ user.setFirstname("Walter");
+ user.setLastname("White");
+
+ user.setCurrent(new Address("308 Negra Arroyo Lane", "87104", "Albuquerque"));
+ user.setPrevious(Collections.singletonList(new Address("12000 – 12100 Coors Rd SW", "87045", "Albuquerque")));
+
+ repository.save(user);
+
+ System.out.println("------- Annotated Single -------");
+ System.out.println(repository.findUserByIdIn(1000));
+ System.out.println(repository.findUserByIdIn(42));
+
+ System.out.println("------- Derived Single -------");
+ System.out.println(repository.findUserByUsername(user.getUsername()));
+
+ System.out.println("------- Derived SASI -------");
+ System.out.println(repository.findUsersByLastnameStartsWith("White", Limit.of(1)));
+ };
+
+ }
+
+}
diff --git a/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/User.java b/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/User.java
new file mode 100644
index 000000000..111db6f2f
--- /dev/null
+++ b/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/User.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.cassandra;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+import org.springframework.data.cassandra.core.mapping.CassandraType;
+import org.springframework.data.cassandra.core.mapping.Column;
+import org.springframework.data.cassandra.core.mapping.PrimaryKey;
+import org.springframework.data.cassandra.core.mapping.Table;
+
+import com.datastax.oss.driver.api.core.data.UdtValue;
+
+/**
+ * Sample user class.
+ *
+ * @author Oliver Gierke
+ * @author Thomas Darimont
+ * @author Mark Paluch
+ */
+@Data
+@NoArgsConstructor
+@Table(value = "users")
+public class User {
+
+ @PrimaryKey("user_id") private Long id;
+
+ @Column("uname") private String username;
+ @Column("fname") private String firstname;
+ @Column("lname") private String lastname;
+
+ Address current;
+ List previous;
+
+ @CassandraType(type = CassandraType.Name.UDT, userTypeName = "address") UdtValue alternative;
+
+ public User(Long id) {
+ this.setId(id);
+ }
+
+ public User(Long id, String firstname, String lastname) {
+ this.id = id;
+ this.firstname = firstname;
+ this.lastname = lastname;
+ }
+}
diff --git a/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/UserRepository.java b/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/UserRepository.java
new file mode 100644
index 000000000..487f98efe
--- /dev/null
+++ b/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/UserRepository.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.cassandra;
+
+import java.util.List;
+
+import org.springframework.data.cassandra.repository.Query;
+import org.springframework.data.domain.Limit;
+import org.springframework.data.repository.CrudRepository;
+
+/**
+ * Simple repository interface for {@link User} instances. The interface is used to declare the so-called query methods,
+ * i.e. methods to retrieve single entities or collections of them.
+ *
+ * @author Thomas Darimont
+ */
+public interface UserRepository extends CrudRepository {
+
+ /**
+ * Sample method annotated with {@link Query}. This method executes the CQL from the {@link Query} value.
+ *
+ * @param id
+ * @return
+ */
+ @Query("SELECT * from users where user_id in(?0)")
+ User findUserByIdIn(long id);
+
+ /**
+ * Derived query method. This query corresponds with {@code SELECT * FROM users WHERE uname = ?0}.
+ * {@link User#username} is not part of the primary so it requires a secondary index.
+ *
+ * @param username
+ * @return
+ */
+ User findUserByUsername(String username);
+
+ /**
+ * Derived query method using SASI (SSTable Attached Secondary Index) features through the {@code LIKE} keyword. This
+ * query corresponds with {@code SELECT * FROM users WHERE lname LIKE '?0'}. {@link User#lastname} is not part of the
+ * primary key so it requires a secondary index.
+ *
+ * @param lastnamePrefix
+ * @return
+ */
+ List findUsersByLastnameStartsWith(String lastnamePrefix);
+
+ /**
+ * Same as {@link #findUsersByLastnameStartsWith(String)} but reducing the result size to a given {@link Limit}.
+ *
+ * @param lastnamePrefix
+ * @param maxResults the maximum number of results returned.
+ * @return
+ */
+ List findUsersByLastnameStartsWith(String lastnamePrefix, Limit maxResults);
+}
diff --git a/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/package-info.java b/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/package-info.java
new file mode 100644
index 000000000..b4857317a
--- /dev/null
+++ b/cassandra/aot-optimization/src/main/java/example/springdata/cassandra/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Package showing a simple repository interface to use basic query method execution functionality.
+ */
+package example.springdata.cassandra;
diff --git a/cassandra/aot-optimization/src/main/resources/application.properties b/cassandra/aot-optimization/src/main/resources/application.properties
new file mode 100644
index 000000000..8a531ae97
--- /dev/null
+++ b/cassandra/aot-optimization/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+spring.cassandra.keyspace-name=example
+spring.cassandra.schema-action=recreate
+spring.cassandra.local-datacenter=datacenter1
diff --git a/cassandra/example/Readme.MD b/cassandra/example/Readme.MD
deleted file mode 100644
index be5d0a2b4..000000000
--- a/cassandra/example/Readme.MD
+++ /dev/null
@@ -1,19 +0,0 @@
-# Spring Data Cassandra Example Application
-
-## Preparation
-
-### Install Cassandra
-Before we can start we have to install Cassandra, e.g. via brew on Max OS.
-```
-brew install cassandra
-
-More details can be found here: https://wiki.apache.org/cassandra/GettingStarted
-```
-
-### Start Cassandra
-```
-/usr/local/bin/cassandra -f
-```
-
-That should be enough to get you started.
-Now you can simply type ```mvn clean install``` to run the example.
diff --git a/cassandra/example/pom.xml b/cassandra/example/pom.xml
index d3624fcc8..8bf284bea 100644
--- a/cassandra/example/pom.xml
+++ b/cassandra/example/pom.xml
@@ -1,5 +1,5 @@
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0%20https://maven.apache.org/maven-v4_0_0.xsd">
4.0.0spring-data-cassandra-example
@@ -7,7 +7,7 @@
org.springframework.data.examplesspring-data-cassandra-examples
- 1.0.0.BUILD-SNAPSHOT
+ 4.0.0-SNAPSHOT../pom.xml
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/auditing/AuditedPerson.java b/cassandra/example/src/main/java/example/springdata/cassandra/auditing/AuditedPerson.java
new file mode 100644
index 000000000..95771e209
--- /dev/null
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/auditing/AuditedPerson.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.cassandra.auditing;
+
+import lombok.Data;
+
+import java.time.Instant;
+
+import org.springframework.data.annotation.CreatedBy;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.LastModifiedBy;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.annotation.Transient;
+import org.springframework.data.cassandra.core.mapping.Table;
+import org.springframework.data.domain.Persistable;
+
+/**
+ * Simple domain object that declares properties annotated with Spring Data's annotations for auditing.
+ *
+ * @author Mark Paluch
+ */
+@Data
+@Table
+public class AuditedPerson implements Persistable {
+
+ @Id Long id;
+
+ @CreatedBy String createdBy;
+
+ @LastModifiedBy String lastModifiedBy;
+
+ @CreatedDate Instant createdDate;
+
+ @LastModifiedDate Instant lastModifiedDate;
+
+ @Transient boolean isNew;
+
+ @Override
+ public boolean isNew() {
+ return isNew;
+ }
+}
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/auditing/AuditedPersonRepository.java b/cassandra/example/src/main/java/example/springdata/cassandra/auditing/AuditedPersonRepository.java
new file mode 100644
index 000000000..a21c26d8a
--- /dev/null
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/auditing/AuditedPersonRepository.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2020-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.cassandra.auditing;
+
+import org.springframework.data.repository.CrudRepository;
+
+/**
+ * Simple repository interface for {@link AuditedPerson} instances.
+ *
+ * @author Mark Paluch
+ */
+public interface AuditedPersonRepository extends CrudRepository {}
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/auditing/BasicConfiguration.java b/cassandra/example/src/main/java/example/springdata/cassandra/auditing/BasicConfiguration.java
new file mode 100644
index 000000000..392743c0d
--- /dev/null
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/auditing/BasicConfiguration.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.cassandra.auditing;
+
+import java.util.Optional;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.persistence.autoconfigure.EntityScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.cassandra.config.EnableCassandraAuditing;
+import org.springframework.data.cassandra.core.convert.CassandraCustomConversions;
+import org.springframework.data.cassandra.core.convert.MappingCassandraConverter;
+import org.springframework.data.cassandra.core.mapping.CassandraMappingContext;
+import org.springframework.data.cassandra.core.mapping.SimpleUserTypeResolver;
+import org.springframework.data.domain.AuditorAware;
+
+import com.datastax.oss.driver.api.core.CqlSession;
+
+/**
+ * Basic {@link Configuration} to create the necessary schema for the {@link AuditedPerson} table.
+ *
+ * @author Mark Paluch
+ */
+@SpringBootApplication
+@EntityScan(basePackageClasses = AuditedPerson.class)
+@EnableCassandraAuditing
+class BasicConfiguration {
+
+ /**
+ * {@code @Bean} method defining a supplier for an auditor. This could be also an integration with a security
+ * framework such as Spring Security.
+ */
+ @Bean
+ AuditorAware auditorAware() {
+ return () -> Optional.of("Some user");
+ }
+
+ /**
+ * {@code @Bean} method defining a {@link MappingCassandraConverter} as currently the auditing requires a bean
+ * definition for {@link MappingCassandraConverter}.
+ */
+ @Bean
+ public MappingCassandraConverter cassandraConverter(CassandraMappingContext mapping,
+ CassandraCustomConversions conversions, CqlSession session) {
+
+ var converter = new MappingCassandraConverter(mapping);
+
+ converter.setCodecRegistry(session.getContext().getCodecRegistry());
+ converter.setCustomConversions(conversions);
+ converter.setUserTypeResolver(new SimpleUserTypeResolver(session));
+
+ return converter;
+ }
+
+}
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/basic/BasicConfiguration.java b/cassandra/example/src/main/java/example/springdata/cassandra/basic/BasicConfiguration.java
index 38a27f8ad..824016c35 100644
--- a/cassandra/example/src/main/java/example/springdata/cassandra/basic/BasicConfiguration.java
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/basic/BasicConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2016 the original author or authors.
+ * Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,49 +15,18 @@
*/
package example.springdata.cassandra.basic;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.context.annotation.Bean;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.persistence.autoconfigure.EntityScan;
import org.springframework.context.annotation.Configuration;
-import org.springframework.data.cassandra.config.SchemaAction;
-import org.springframework.data.cassandra.config.java.AbstractCassandraConfiguration;
-import org.springframework.data.cassandra.core.CassandraTemplate;
-import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
-
-import com.datastax.driver.core.Session;
/**
* Basic {@link Configuration} to create the necessary schema for the {@link User} table.
- *
+ *
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
*/
-@Configuration
-@EnableAutoConfiguration
+@SpringBootApplication
+@EntityScan(basePackageClasses = User.class)
class BasicConfiguration {
-
- @Configuration
- @EnableCassandraRepositories
- static class CassandraConfig extends AbstractCassandraConfiguration {
-
- @Override
- public String getKeyspaceName() {
- return "example";
- }
-
- @Bean
- public CassandraTemplate cassandraTemplate(Session session) {
- return new CassandraTemplate(session);
- }
-
- @Override
- public String[] getEntityBasePackages() {
- return new String[] { User.class.getPackage().getName() };
- }
-
- @Override
- public SchemaAction getSchemaAction() {
- return SchemaAction.RECREATE;
- }
- }
}
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/basic/BasicUserRepository.java b/cassandra/example/src/main/java/example/springdata/cassandra/basic/BasicUserRepository.java
index a02b580a0..a3fc0601b 100644
--- a/cassandra/example/src/main/java/example/springdata/cassandra/basic/BasicUserRepository.java
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/basic/BasicUserRepository.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2013-2016 the original author or authors.
+ * Copyright 2013-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,19 +18,20 @@
import java.util.List;
import org.springframework.data.cassandra.repository.Query;
+import org.springframework.data.domain.Limit;
import org.springframework.data.repository.CrudRepository;
/**
- * Simple repository interface for {@link User} instances. The interface is used to declare so called query methods,
- * methods to retrieve single entities or collections of them.
- *
+ * Simple repository interface for {@link User} instances. The interface is used to declare the so-called query methods,
+ * i.e. methods to retrieve single entities or collections of them.
+ *
* @author Thomas Darimont
*/
public interface BasicUserRepository extends CrudRepository {
/**
* Sample method annotated with {@link Query}. This method executes the CQL from the {@link Query} value.
- *
+ *
* @param id
* @return
*/
@@ -48,11 +49,20 @@ public interface BasicUserRepository extends CrudRepository {
/**
* Derived query method using SASI (SSTable Attached Secondary Index) features through the {@code LIKE} keyword. This
- * query corresponds with {@code SELECT * FROM users WHERE uname LIKE '?0%'}. {@link User#username} is not part of the
- * primary so it requires a secondary index.
+ * query corresponds with {@code SELECT * FROM users WHERE lname LIKE '?0'}. {@link User#lastname} is not part of the
+ * primary key so it requires a secondary index.
*
* @param lastnamePrefix
* @return
*/
List findUsersByLastnameStartsWith(String lastnamePrefix);
+
+ /**
+ * Same as {@link #findUsersByLastnameStartsWith(String)} but reducing the result size to a given {@link Limit}.
+ *
+ * @param lastnamePrefix
+ * @param maxResults the maximum number of results returned.
+ * @return
+ */
+ List findUsersByLastnameStartsWith(String lastnamePrefix, Limit maxResults);
}
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/basic/User.java b/cassandra/example/src/main/java/example/springdata/cassandra/basic/User.java
index 7203c6b3c..96c05b186 100644
--- a/cassandra/example/src/main/java/example/springdata/cassandra/basic/User.java
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/basic/User.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2013-2016 the original author or authors.
+ * Copyright 2013-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,15 +18,16 @@
import lombok.Data;
import lombok.NoArgsConstructor;
-import org.springframework.data.cassandra.mapping.Column;
-import org.springframework.data.cassandra.mapping.PrimaryKey;
-import org.springframework.data.cassandra.mapping.Table;
+import org.springframework.data.cassandra.core.mapping.Column;
+import org.springframework.data.cassandra.core.mapping.PrimaryKey;
+import org.springframework.data.cassandra.core.mapping.Table;
/**
* Sample user class.
- *
+ *
* @author Oliver Gierke
* @author Thomas Darimont
+ * @author Mark Paluch
*/
@Data
@NoArgsConstructor
@@ -42,4 +43,10 @@ public class User {
public User(Long id) {
this.setId(id);
}
+
+ public User(Long id, String firstname, String lastname) {
+ this.id = id;
+ this.firstname = firstname;
+ this.lastname = lastname;
+ }
}
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/convert/Address.java b/cassandra/example/src/main/java/example/springdata/cassandra/convert/Address.java
new file mode 100644
index 000000000..47198f6dd
--- /dev/null
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/convert/Address.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.cassandra.convert;
+
+import org.springframework.data.cassandra.core.mapping.Element;
+import org.springframework.data.cassandra.core.mapping.Tuple;
+
+/**
+ * Simple mapped tuple.
+ *
+ * @author Mark Paluch
+ */
+@Tuple
+public record Address(@Element(0) String address, @Element(1) String city, @Element(2) String zip) {
+
+}
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/convert/Addressbook.java b/cassandra/example/src/main/java/example/springdata/cassandra/convert/Addressbook.java
index 0caff5931..97c817745 100644
--- a/cassandra/example/src/main/java/example/springdata/cassandra/convert/Addressbook.java
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/convert/Addressbook.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2016-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,16 +15,18 @@
*/
package example.springdata.cassandra.convert;
-import org.springframework.data.annotation.Id;
-import org.springframework.data.cassandra.mapping.Table;
-
import lombok.Data;
+import java.util.Currency;
import java.util.List;
+import java.util.Map;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.cassandra.core.mapping.Table;
/**
* Sample Addressbook class.
- *
+ *
* @author Mark Paluch
*/
@Data
@@ -35,4 +37,7 @@ public class Addressbook {
Contact me;
List friends;
+
+ Address address;
+ Map preferredCurrencies;
}
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/convert/Contact.java b/cassandra/example/src/main/java/example/springdata/cassandra/convert/Contact.java
index 1a4ebf587..8c9ca1a6d 100644
--- a/cassandra/example/src/main/java/example/springdata/cassandra/convert/Contact.java
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/convert/Contact.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2016-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,20 +15,11 @@
*/
package example.springdata.cassandra.convert;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
/**
* Sample Contact class.
- *
+ *
* @author Mark Paluch
*/
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class Contact {
+public record Contact(String firstname, String lastname) {
- String firstname;
- String lastname;
}
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/convert/ConverterConfiguration.java b/cassandra/example/src/main/java/example/springdata/cassandra/convert/ConverterConfiguration.java
index b813798b0..719b30af5 100644
--- a/cassandra/example/src/main/java/example/springdata/cassandra/convert/ConverterConfiguration.java
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/convert/ConverterConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,52 +17,40 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Currency;
import java.util.List;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.persistence.autoconfigure.EntityScan;
+import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
-import org.springframework.data.cassandra.config.SchemaAction;
-import org.springframework.data.cassandra.config.java.AbstractCassandraConfiguration;
-import org.springframework.data.cassandra.convert.CustomConversions;
-import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;
+import org.springframework.data.cassandra.core.convert.CassandraCustomConversions;
import org.springframework.util.StringUtils;
-import com.datastax.driver.core.Row;
+import com.datastax.oss.driver.api.core.cql.Row;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* {@link Configuration} class to register custom converters.
- *
+ *
* @author Mark Paluch
*/
-@Configuration
-@EnableCassandraRepositories
-class ConverterConfiguration extends AbstractCassandraConfiguration {
-
- @Override
- public String getKeyspaceName() {
- return "example";
- }
-
- @Override
- public String[] getEntityBasePackages() {
- return new String[] { Addressbook.class.getPackage().getName() };
- }
-
- @Override
- public SchemaAction getSchemaAction() {
- return SchemaAction.RECREATE;
- }
+@SpringBootApplication
+@EntityScan(basePackageClasses = Addressbook.class)
+class ConverterConfiguration {
- @Override
- public CustomConversions customConversions() {
+ @Bean
+ public CassandraCustomConversions customConversions() {
List> converters = new ArrayList<>();
converters.add(new PersonWriteConverter());
converters.add(new PersonReadConverter());
converters.add(new CustomAddressbookReadConverter());
+ converters.add(CurrencyToStringConverter.INSTANCE);
+ converters.add(StringToCurrencyConverter.INSTANCE);
- return new CustomConversions(converters);
+ return new CassandraCustomConversions(converters);
}
/**
@@ -105,12 +93,26 @@ static class CustomAddressbookReadConverter implements Converter {
+ INSTANCE;
+
+ @Override
+ public Currency convert(String source) {
+ return Currency.getInstance(source);
+ }
+ }
+
+ enum CurrencyToStringConverter implements Converter {
- result.setTheId(source.getString("id"));
- result.setMyDetailsAsJson(source.getString("me"));
+ INSTANCE;
- return result;
+ @Override
+ public String convert(Currency source) {
+ return source.getCurrencyCode();
}
}
}
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/convert/CustomAddressbook.java b/cassandra/example/src/main/java/example/springdata/cassandra/convert/CustomAddressbook.java
index 3a0e15eaa..fc6983690 100644
--- a/cassandra/example/src/main/java/example/springdata/cassandra/convert/CustomAddressbook.java
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/convert/CustomAddressbook.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2016 the original author or authors.
+ * Copyright 2016-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,14 +15,9 @@
*/
package example.springdata.cassandra.convert;
-import lombok.Data;
-
/**
* @author Mark Paluch
*/
-@Data
-public class CustomAddressbook {
+public record CustomAddressbook(String theId, String myDetailsAsJson) {
- String theId;
- String myDetailsAsJson;
}
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/events/BasicConfiguration.java b/cassandra/example/src/main/java/example/springdata/cassandra/events/BasicConfiguration.java
new file mode 100644
index 000000000..e365c45fe
--- /dev/null
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/events/BasicConfiguration.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.cassandra.events;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.persistence.autoconfigure.EntityScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Basic {@link Configuration} to create the necessary schema for the {@link User} table.
+ *
+ * @author Mark Paluch
+ */
+@SpringBootApplication
+@EntityScan(basePackageClasses = User.class)
+class BasicConfiguration {
+
+ @Bean
+ LoggingEventListener listener() {
+ return new LoggingEventListener();
+ }
+}
diff --git a/cassandra/example/src/main/java/example/springdata/cassandra/events/LoggingEventListener.java b/cassandra/example/src/main/java/example/springdata/cassandra/events/LoggingEventListener.java
new file mode 100644
index 000000000..ae763d958
--- /dev/null
+++ b/cassandra/example/src/main/java/example/springdata/cassandra/events/LoggingEventListener.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2018-2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package example.springdata.cassandra.events;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationListener;
+import org.springframework.data.cassandra.core.mapping.event.AbstractCassandraEventListener;
+import org.springframework.data.cassandra.core.mapping.event.AfterConvertEvent;
+import org.springframework.data.cassandra.core.mapping.event.AfterDeleteEvent;
+import org.springframework.data.cassandra.core.mapping.event.AfterLoadEvent;
+import org.springframework.data.cassandra.core.mapping.event.AfterSaveEvent;
+import org.springframework.data.cassandra.core.mapping.event.BeforeDeleteEvent;
+import org.springframework.data.cassandra.core.mapping.event.BeforeSaveEvent;
+
+/**
+ * {@link ApplicationListener} for Cassandra mapping events logging the events.
+ *
+ * @author Mark Paluch
+ */
+public class LoggingEventListener extends AbstractCassandraEventListener