diff --git a/jpa/aot-generation/pom.xml b/jpa/aot-generation/pom.xml
new file mode 100644
index 00000000..c8c2e9cf
--- /dev/null
+++ b/jpa/aot-generation/pom.xml
@@ -0,0 +1,89 @@
+
+
+ 4.0.0
+
+ org.springframework.data.examples
+ spring-data-jpa-examples
+ 2.0.0.BUILD-SNAPSHOT
+
+
+ org.example
+ aot-generation
+
+
+ UTF-8
+ 7.0.0.Beta5
+
+
+
+
+ org.jspecify
+ jspecify
+ 1.0.0
+
+
+
+ com.querydsl
+ querydsl-jpa
+ 5.1.0
+ jakarta
+
+
+ com.querydsl
+ querydsl-apt
+ 5.1.0
+ jakarta
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ com.querydsl
+ querydsl-jpa
+ 5.1.0
+ jakarta
+
+
+ com.querydsl
+ querydsl-apt
+ 5.1.0
+ jakarta
+
+
+ jakarta.persistence
+ jakarta.persistence-api
+ 3.2.0
+
+
+
+
+ target/generated-test-sources
+
+ target/generated-sources
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ process-aot
+
+ process-aot
+
+
+
+
+
+
+
+
diff --git a/jpa/aot-generation/src/main/java/example/springdata/aot/AotJpaApp.java b/jpa/aot-generation/src/main/java/example/springdata/aot/AotJpaApp.java
new file mode 100644
index 00000000..5256d51e
--- /dev/null
+++ b/jpa/aot-generation/src/main/java/example/springdata/aot/AotJpaApp.java
@@ -0,0 +1,30 @@
+/*
+ * 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
+ *
+ * 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.aot;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author Christoph Strobl
+ */
+@SpringBootApplication
+public class AotJpaApp {
+
+ public static void main(String[] args) {
+ SpringApplication.run(AotJpaApp.class, args);
+ }
+}
diff --git a/jpa/aot-generation/src/main/java/example/springdata/aot/CLR.java b/jpa/aot-generation/src/main/java/example/springdata/aot/CLR.java
new file mode 100644
index 00000000..aaa2ed51
--- /dev/null
+++ b/jpa/aot-generation/src/main/java/example/springdata/aot/CLR.java
@@ -0,0 +1,124 @@
+/*
+ * 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.aot;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Slice;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Christoph Strobl
+ * @since 2025/01
+ */
+@Component
+public class CLR implements CommandLineRunner {
+
+ @Autowired UserRepository repository;
+
+ @Override
+ public void run(String... args) throws Exception {
+
+ User luke = new User("id-1", "luke");
+ luke.setFirstname("Luke");
+ luke.setLastname("Skywalker");
+// Post lukeP1 = new Post("I have a bad feeling about this.");
+// em.persist(lukeP1);
+// luke.setPosts(List.of(lukeP1));
+
+ User leia = new User("id-2", "leia");
+ leia.setFirstname("Leia");
+ leia.setLastname("Organa");
+
+ User han = new User("id-3", "han");
+ han.setFirstname("Han");
+ han.setLastname("Solo");
+// Post hanP1 = new Post("It's the ship that made the Kessel Run in less than 12 Parsecs.");
+// em.persist(hanP1);
+// han.setPosts(List.of(hanP1));
+
+ User chewbacca = new User("id-4", "chewbacca");
+ User yoda = new User("id-5", "yoda");
+ Post yodaP1 = new Post("Do. Or do not. There is no try.");
+ Post yodaP2 = new Post("Decide you must, how to serve them best. If you leave now, help them you could; but you would destroy all for which they have fought, and suffered.");
+// em.persist(yodaP1);
+// em.persist(yodaP2);
+// yoda.setPosts(List.of(yodaP1, yodaP2));
+
+ User vader = new User("id-6", "vader");
+ vader.setFirstname("Anakin");
+ vader.setLastname("Skywalker");
+// Post vaderP1 = new Post("I am your father");
+// em.persist(vaderP1);
+// vader.setPosts(List.of(vaderP1));
+
+ User kylo = new User("id-7", "kylo");
+ kylo.setFirstname("Ben");
+ kylo.setLastname("Solo");
+
+ repository.saveAll(List.of(luke, leia, han, chewbacca, yoda, vader, kylo));
+
+ System.out.println("------- annotated multi -------");
+ System.out.println(repository.usersWithUsernamesStartingWith("l"));
+
+ System.out.println("------- derived single -------");
+ System.out.println(repository.findUserByUsername("yoda"));
+
+// System.out.println("------- derived nested.path -------");
+// System.out.println(repository.findUserByPostsMessageLike("father"));
+
+ System.out.println("------- derived optional -------");
+ System.out.println(repository.findOptionalUserByUsername("yoda"));
+
+ System.out.println("------- derived count -------");
+ Long count = repository.countUsersByLastnameLike("Sky");
+ System.out.println("user count " + count);
+
+ System.out.println("------- derived exists -------");
+ Boolean exists = repository.existsByUsername("vader");
+ System.out.println("user exists " + exists);
+
+ System.out.println("------- derived multi -------");
+ System.out.println(repository.findUserByLastnameStartingWith("Sky"));
+
+ System.out.println("------- derived sorted -------");
+ System.out.println(repository.findUserByLastnameStartingWithOrderByFirstname("Sky"));
+
+ System.out.println("------- derived page -------");
+ Page page0 = repository.findUserByLastnameStartingWith("S", PageRequest.of(0, 2));
+ System.out.println("page0: " + page0);
+ System.out.println("page0.content: " + page0.getContent());
+
+ Page page1 = repository.findUserByLastnameStartingWith("S", PageRequest.of(1, 2));
+ System.out.println("page1: " + page1);
+ System.out.println("page1.content: " + page1.getContent());
+
+ System.out.println("------- derived slice -------");
+ Slice slice0 = repository.findUserByUsernameAfter("luke", PageRequest.of(0, 2));
+ System.out.println("slice0: " + slice0);
+ System.out.println("slice0.content: " + slice0.getContent());
+
+ System.out.println("------- derived top -------");
+ System.out.println(repository.findTop2UsersByLastnameStartingWith("S"));
+
+// System.out.println("------- derived with fields -------");
+// System.out.println(repository.findJustUsernameBy());
+ }
+}
diff --git a/jpa/aot-generation/src/main/java/example/springdata/aot/Post.java b/jpa/aot-generation/src/main/java/example/springdata/aot/Post.java
new file mode 100644
index 00000000..e950f2aa
--- /dev/null
+++ b/jpa/aot-generation/src/main/java/example/springdata/aot/Post.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
+ *
+ * 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.aot;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Random;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.Id;
+
+/**
+ * @author Christoph Strobl
+ * @since 2025/01
+ */
+@Entity
+public class Post {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private String message;
+ private Instant date;
+
+ public Post() {
+ }
+
+ public Post(String message) {
+ this.message = message;
+ this.date = Instant.now().minus(new Random().nextLong(100), ChronoUnit.MINUTES);
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Instant getDate() {
+ return date;
+ }
+
+ public void setDate(Instant date) {
+ this.date = date;
+ }
+
+ @Override
+ public String toString() {
+ return message;
+ }
+}
diff --git a/jpa/aot-generation/src/main/java/example/springdata/aot/User.java b/jpa/aot-generation/src/main/java/example/springdata/aot/User.java
new file mode 100644
index 00000000..2a5d37d6
--- /dev/null
+++ b/jpa/aot-generation/src/main/java/example/springdata/aot/User.java
@@ -0,0 +1,114 @@
+/*
+ * 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.aot;
+
+import java.time.Instant;
+import java.util.List;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.OneToMany;
+
+/**
+ * @author Christoph Strobl
+ * @since 2025/01
+ */
+@Entity(name = "users")
+public class User {
+
+ @Id
+ private String id;
+ private String username;
+
+ @Column(name = "first_name") String firstname;
+ @Column(name = "last_name") String lastname;
+
+// @OneToMany
+// private List posts;
+
+ Instant registrationDate;
+ Instant lastSeen;
+
+ public User() {
+ }
+
+ public User(String id, String username) {
+ this.id = id;
+ this.username = username;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getFirstname() {
+ return firstname;
+ }
+
+ public void setFirstname(String firstname) {
+ this.firstname = firstname;
+ }
+
+ public String getLastname() {
+ return lastname;
+ }
+
+ public void setLastname(String lastname) {
+ this.lastname = lastname;
+ }
+
+ public Instant getRegistrationDate() {
+ return registrationDate;
+ }
+
+ public void setRegistrationDate(Instant registrationDate) {
+ this.registrationDate = registrationDate;
+ }
+
+ public Instant getLastSeen() {
+ return lastSeen;
+ }
+
+ public void setLastSeen(Instant lastSeen) {
+ this.lastSeen = lastSeen;
+ }
+
+// public List getPosts() {
+// return posts;
+// }
+//
+// public void setPosts(List posts) {
+// this.posts = posts;
+// }
+
+ @Override
+ public String toString() {
+ return "User{" +
+ "id='" + id + '\'' +
+ ", username='" + username + '\'' +
+ ", firstname='" + firstname + '\'' +
+ ", lastname='" + lastname + '\'' +
+ ", registrationDate=" + registrationDate +
+ ", lastSeen=" + lastSeen +
+// ", posts=" + posts +
+ '}';
+ }
+}
diff --git a/jpa/aot-generation/src/main/java/example/springdata/aot/UserProjection.java b/jpa/aot-generation/src/main/java/example/springdata/aot/UserProjection.java
new file mode 100644
index 00000000..8ac144a1
--- /dev/null
+++ b/jpa/aot-generation/src/main/java/example/springdata/aot/UserProjection.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.aot;
+
+import java.time.Instant;
+
+/**
+ * @author Christoph Strobl
+ * @since 2025/01
+ */
+public record UserProjection(String username, Instant registrationDate) {
+
+}
diff --git a/jpa/aot-generation/src/main/java/example/springdata/aot/UserRepository.java b/jpa/aot-generation/src/main/java/example/springdata/aot/UserRepository.java
new file mode 100644
index 00000000..4d28f9a5
--- /dev/null
+++ b/jpa/aot-generation/src/main/java/example/springdata/aot/UserRepository.java
@@ -0,0 +1,57 @@
+/*
+ * 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.aot;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Slice;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.querydsl.QuerydslPredicateExecutor;
+import org.springframework.data.repository.CrudRepository;
+
+/**
+ * @author Christoph Strobl
+ * @since 2025/01
+ */
+public interface UserRepository extends CrudRepository, QuerydslPredicateExecutor {
+
+ User findUserByUsername(String username);
+
+ Optional findOptionalUserByUsername(String username);
+
+ Long countUsersByLastnameLike(String lastname);
+
+ Boolean existsByUsername(String username);
+
+ List findUserByLastnameLike(String lastname);
+
+ List findUserByLastnameStartingWithOrderByFirstname(String lastname);
+
+ List findTop2UsersByLastnameStartingWith(String lastname);
+
+ Slice findUserByUsernameAfter(String username, Pageable pageable);
+
+ List findUserByLastnameStartingWith(String lastname);
+
+ Page findUserByLastnameStartingWith(String lastname, Pageable page);
+
+ @Query("SELECT u FROM example.springdata.aot.User u WHERE u.username LIKE ?1%")
+ List usersWithUsernamesStartingWith(String username);
+
+}
diff --git a/jpa/aot-generation/src/main/resources/application.properties b/jpa/aot-generation/src/main/resources/application.properties
new file mode 100644
index 00000000..a036d6f1
--- /dev/null
+++ b/jpa/aot-generation/src/main/resources/application.properties
@@ -0,0 +1,5 @@
+spring.jpa.defer-datasource-initialization=true
+spring.jpa.properties.hibernate.boot.allow_jdbc_metadata_access=false
+spring.aot.repositories.enabled=true
+#logging.level.org.springframework.data.repository.aot.generate.RepositoryContributor=trace
+
diff --git a/jpa/pom.xml b/jpa/pom.xml
index 80661b14..622bb759 100644
--- a/jpa/pom.xml
+++ b/jpa/pom.xml
@@ -29,6 +29,7 @@
vavr
multitenant
graalvm-native
+ aot-generation
@@ -38,6 +39,24 @@
spring-boot-starter-data-jpa
+
+ org.springframework.data
+ spring-data-commons
+ 4.0.0-SNAPSHOT
+
+
+
+ org.springframework.data
+ spring-data-jpa
+ 4.0.0-SNAPSHOT
+
+
+
+ jakarta.persistence
+ jakarta.persistence-api
+ 3.2.0
+
+
org.hsqldb
hsqldb
diff --git a/mongodb/aot-generation/pom.xml b/mongodb/aot-generation/pom.xml
new file mode 100644
index 00000000..c7105144
--- /dev/null
+++ b/mongodb/aot-generation/pom.xml
@@ -0,0 +1,71 @@
+
+
+ 4.0.0
+
+ org.springframework.data.examples
+ spring-data-mongodb-examples
+ 2.0.0.BUILD-SNAPSHOT
+
+
+ org.example
+ aot-generation
+
+
+ 21
+ 21
+ UTF-8
+
+
+
+
+ org.springframework.data
+ spring-data-commons
+ 4.0.x-GENERATED-REPOSITORIES-SNAPSHOT
+
+
+ org.springframework.data
+ spring-data-mongodb
+ 5.0.0-GENERATED-REPOSITORIES-SNAPSHOT
+
+
+ org.mongodb
+ bson
+ 5.3.1
+
+
+ org.mongodb
+ mongodb-driver-core
+ 5.3.1
+
+
+ org.mongodb
+ mongodb-driver-sync
+ 5.3.1
+
+
+ org.jspecify
+ jspecify
+ 1.0.0
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ process-aot
+
+ process-aot
+
+
+
+
+
+
+
+
diff --git a/mongodb/aot-generation/src/main/java/example/springdata/aot/App.java b/mongodb/aot-generation/src/main/java/example/springdata/aot/App.java
new file mode 100644
index 00000000..b63c97cd
--- /dev/null
+++ b/mongodb/aot-generation/src/main/java/example/springdata/aot/App.java
@@ -0,0 +1,30 @@
+/*
+ * 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
+ *
+ * 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.aot;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author Christoph Strobl
+ */
+@SpringBootApplication
+public class App {
+
+ public static void main(String[] args) {
+ SpringApplication.run(App.class, args);
+ }
+}
diff --git a/mongodb/aot-generation/src/main/java/example/springdata/aot/CLR.java b/mongodb/aot-generation/src/main/java/example/springdata/aot/CLR.java
new file mode 100644
index 00000000..1ccacfaa
--- /dev/null
+++ b/mongodb/aot-generation/src/main/java/example/springdata/aot/CLR.java
@@ -0,0 +1,114 @@
+/*
+ * 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.aot;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Slice;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Christoph Strobl
+ * @since 2025/01
+ */
+@Component
+public class CLR implements CommandLineRunner {
+
+ @Autowired UserRepository repository;
+
+ @Override
+ public void run(String... args) throws Exception {
+
+ User luke = new User("id-1", "luke");
+ luke.setFirstname("Luke");
+ luke.setLastname("Skywalker");
+ luke.setPosts(List.of(new Post("I have a bad feeling about this.")));
+
+ User leia = new User("id-2", "leia");
+ leia.setFirstname("Leia");
+ leia.setLastname("Organa");
+
+ User han = new User("id-3", "han");
+ han.setFirstname("Han");
+ han.setLastname("Solo");
+ han.setPosts(List.of(new Post("It's the ship that made the Kessel Run in less than 12 Parsecs.")));
+
+ User chewbacca = new User("id-4", "chewbacca");
+ User yoda = new User("id-5", "yoda");
+ yoda.setPosts(List.of(new Post("Do. Or do not. There is no try."), new Post("Decide you must, how to serve them best. If you leave now, help them you could; but you would destroy all for which they have fought, and suffered.")));
+
+ User vader = new User("id-6", "vader");
+ vader.setFirstname("Anakin");
+ vader.setLastname("Skywalker");
+ vader.setPosts(List.of(new Post("I am your father")));
+
+ User kylo = new User("id-7", "kylo");
+ kylo.setFirstname("Ben");
+ kylo.setLastname("Solo");
+
+ repository.saveAll(List.of(luke, leia, han, chewbacca, yoda, vader, kylo));
+
+ System.out.println("------- annotated multi -------");
+ System.out.println(repository.usersWithUsernamesStartingWith("l"));
+
+ System.out.println("------- derived single -------");
+ System.out.println(repository.findUserByUsername("yoda"));
+
+ System.out.println("------- derived nested.path -------");
+ System.out.println(repository.findUserByPostsMessageLike("father"));
+
+ System.out.println("------- derived optional -------");
+ System.out.println(repository.findOptionalUserByUsername("yoda"));
+
+ System.out.println("------- derived count -------");
+ Long count = repository.countUsersByLastnameLike("Sky");
+ System.out.println("user count " + count);
+
+ System.out.println("------- derived exists -------");
+ Boolean exists = repository.existsByUsername("vader");
+ System.out.println("user exists " + exists);
+
+ System.out.println("------- derived multi -------");
+ System.out.println(repository.findUserByLastnameLike("Sky"));
+
+ System.out.println("------- derived sorted -------");
+ System.out.println(repository.findUserByLastnameLikeOrderByFirstname("Sky"));
+
+ System.out.println("------- derived page -------");
+ Page page0 = repository.findUserByLastnameStartingWith("S", PageRequest.of(0, 2));
+ System.out.println("page0: " + page0);
+ System.out.println("page0.content: " + page0.getContent());
+
+ Page page1 = repository.findUserByLastnameStartingWith("S", PageRequest.of(1, 2));
+ System.out.println("page1: " + page1);
+ System.out.println("page1.content: " + page1.getContent());
+
+ System.out.println("------- derived slice -------");
+ Slice slice0 = repository.findUserByUsernameAfter("luke", PageRequest.of(0, 2));
+ System.out.println("slice0: " + slice0);
+ System.out.println("slice0.content: " + slice0.getContent());
+
+ System.out.println("------- derived top -------");
+ System.out.println(repository.findTop2UsersByLastnameLike("S"));
+
+ System.out.println("------- derived with fields -------");
+ System.out.println(repository.findJustUsernameBy());
+ }
+}
diff --git a/mongodb/aot-generation/src/main/java/example/springdata/aot/Post.java b/mongodb/aot-generation/src/main/java/example/springdata/aot/Post.java
new file mode 100644
index 00000000..9ca0d2f6
--- /dev/null
+++ b/mongodb/aot-generation/src/main/java/example/springdata/aot/Post.java
@@ -0,0 +1,56 @@
+/*
+ * 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
+ *
+ * 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.aot;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Random;
+
+/**
+ * @author Christoph Strobl
+ * @since 2025/01
+ */
+public class Post {
+
+ private String message;
+ private Instant date;
+
+ public Post(String message) {
+ this.message = message;
+ this.date = Instant.now().minus(new Random().nextLong(100), ChronoUnit.MINUTES);
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public Instant getDate() {
+ return date;
+ }
+
+ public void setDate(Instant date) {
+ this.date = date;
+ }
+
+ @Override
+ public String toString() {
+ return message;
+ }
+}
diff --git a/mongodb/aot-generation/src/main/java/example/springdata/aot/User.java b/mongodb/aot-generation/src/main/java/example/springdata/aot/User.java
new file mode 100644
index 00000000..56317490
--- /dev/null
+++ b/mongodb/aot-generation/src/main/java/example/springdata/aot/User.java
@@ -0,0 +1,105 @@
+/*
+ * 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.aot;
+
+import java.time.Instant;
+import java.util.List;
+
+import org.springframework.data.mongodb.core.mapping.Field;
+
+/**
+ * @author Christoph Strobl
+ * @since 2025/01
+ */
+public class User {
+
+ private final String id;
+ private final String username;
+
+ @Field("first_name") String firstname;
+ @Field("last_name") String lastname;
+
+ private List posts;
+
+ Instant registrationDate;
+ Instant lastSeen;
+
+ public User(String id, String username) {
+ this.id = id;
+ this.username = username;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getFirstname() {
+ return firstname;
+ }
+
+ public void setFirstname(String firstname) {
+ this.firstname = firstname;
+ }
+
+ public String getLastname() {
+ return lastname;
+ }
+
+ public void setLastname(String lastname) {
+ this.lastname = lastname;
+ }
+
+ public Instant getRegistrationDate() {
+ return registrationDate;
+ }
+
+ public void setRegistrationDate(Instant registrationDate) {
+ this.registrationDate = registrationDate;
+ }
+
+ public Instant getLastSeen() {
+ return lastSeen;
+ }
+
+ public void setLastSeen(Instant lastSeen) {
+ this.lastSeen = lastSeen;
+ }
+
+ public List getPosts() {
+ return posts;
+ }
+
+ public void setPosts(List posts) {
+ this.posts = posts;
+ }
+
+ @Override
+ public String toString() {
+ return "User{" +
+ "id='" + id + '\'' +
+ ", username='" + username + '\'' +
+ ", firstname='" + firstname + '\'' +
+ ", lastname='" + lastname + '\'' +
+ ", registrationDate=" + registrationDate +
+ ", lastSeen=" + lastSeen +
+ ", posts=" + posts +
+ '}';
+ }
+}
diff --git a/mongodb/aot-generation/src/main/java/example/springdata/aot/UserProjection.java b/mongodb/aot-generation/src/main/java/example/springdata/aot/UserProjection.java
new file mode 100644
index 00000000..d243ba3a
--- /dev/null
+++ b/mongodb/aot-generation/src/main/java/example/springdata/aot/UserProjection.java
@@ -0,0 +1,28 @@
+/*
+ * 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.aot;
+
+import java.time.Instant;
+
+/**
+ * @author Christoph Strobl
+ * @since 2025/01
+ */
+public interface UserProjection {
+
+ String getUsername();
+ Instant getRegistrationDate();
+}
diff --git a/mongodb/aot-generation/src/main/java/example/springdata/aot/UserRepository.java b/mongodb/aot-generation/src/main/java/example/springdata/aot/UserRepository.java
new file mode 100644
index 00000000..0565148a
--- /dev/null
+++ b/mongodb/aot-generation/src/main/java/example/springdata/aot/UserRepository.java
@@ -0,0 +1,44 @@
+package example.springdata.aot;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Slice;
+import org.springframework.data.mongodb.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+
+/**
+ * @author Christoph Strobl
+ * @since 2025/01
+ */
+public interface UserRepository extends CrudRepository {
+
+ User findUserByUsername(String username);
+
+ Optional findOptionalUserByUsername(String username);
+
+ Long countUsersByLastnameLike(String lastname);
+
+ Boolean existsByUsername(String username);
+
+ List findUserByLastnameLike(String lastname);
+
+ List findUserByPostsMessageLike(String part);
+
+ List findUserByLastnameLikeOrderByFirstname(String lastname);
+
+ List findTop2UsersByLastnameLike(String lastname);
+
+ Slice findUserByUsernameAfter(String username, Pageable pageable);
+
+ Page findUserByLastnameStartingWith(String lastname, Pageable page);
+
+ @Query("{ 'username' : { $regex: '?0.*', $options: 'i' } }")
+ List usersWithUsernamesStartingWith(String username);
+
+ @Query(fields = "{ 'username' : 1 }", sort = "{ 'username' : -1 }")
+ List findJustUsernameBy();
+
+}
diff --git a/mongodb/aot-generation/src/main/resources/logback.xml b/mongodb/aot-generation/src/main/resources/logback.xml
new file mode 100644
index 00000000..1be6becb
--- /dev/null
+++ b/mongodb/aot-generation/src/main/resources/logback.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+ %d %5p %40.40c:%4L - %m%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mongodb/aot-generation/src/main/resources/spring.properties b/mongodb/aot-generation/src/main/resources/spring.properties
new file mode 100644
index 00000000..fb68fc02
--- /dev/null
+++ b/mongodb/aot-generation/src/main/resources/spring.properties
@@ -0,0 +1 @@
+spring.aot.repositories.enabled=true
diff --git a/mongodb/pom.xml b/mongodb/pom.xml
index c1798a21..920f82fa 100644
--- a/mongodb/pom.xml
+++ b/mongodb/pom.xml
@@ -36,7 +36,8 @@
linking
util
fragment-spi
-
+ aot-generation
+
diff --git a/pom.xml b/pom.xml
index 801bef88..d2ab97b6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,7 +37,10 @@
1.1.3
+ 21
+ 21
UTF-8
+ 2025.1.0-SNAPSHOT