dings = repository.findProjectedByNameContaining("dings");
+ dings.forEach(it -> System.out.println("Name: %s, Description: %s, Combined: %s".formatted(it.getName(),
+ it.getDescription(), it.getNameAndDescription())));
+ };
+ }
+}
diff --git a/jdbc/aot-optimization/src/main/java/example/springdata/aot/Category.java b/jdbc/aot-optimization/src/main/java/example/springdata/aot/Category.java
new file mode 100644
index 000000000..479dbe509
--- /dev/null
+++ b/jdbc/aot-optimization/src/main/java/example/springdata/aot/Category.java
@@ -0,0 +1,104 @@
+/*
+ * 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.LocalDateTime;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.PersistenceCreator;
+
+/**
+ * Coarse classification.
+ *
+ * @author Jens Schauder
+ */
+public class Category {
+
+ private final @Id Long id;
+ private String name, description;
+ private LocalDateTime created;
+ private Long inserted;
+
+ public Category(String name, String description) {
+
+ this.id = null;
+ this.name = name;
+ this.description = description;
+ this.created = LocalDateTime.now();
+ }
+
+ @PersistenceCreator
+ Category(Long id, String name, String description, LocalDateTime created, Long inserted) {
+ this.id = id;
+ this.name = name;
+ this.description = description;
+ this.created = created;
+ this.inserted = inserted;
+ }
+
+ public void timeStamp() {
+
+ if (inserted == 0) {
+ inserted = System.currentTimeMillis();
+ }
+ }
+
+ public Long getId() {
+ return this.id;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getDescription() {
+ return this.description;
+ }
+
+ public LocalDateTime getCreated() {
+ return this.created;
+ }
+
+ public Long getInserted() {
+ return this.inserted;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public void setCreated(LocalDateTime created) {
+ this.created = created;
+ }
+
+ public void setInserted(Long inserted) {
+ this.inserted = inserted;
+ }
+
+ public Category withId(Long id) {
+ return this.id == id ? this : new Category(id, this.name, this.description, this.created, this.inserted);
+ }
+
+ @Override
+ public String toString() {
+ return "Category(id=" + this.getId() + ", name=" + this.getName() + ", description=" + this.getDescription()
+ + ", created=" + this.getCreated() + ", inserted=" + this.getInserted() + ")";
+ }
+}
diff --git a/jdbc/aot-optimization/src/main/java/example/springdata/aot/CategoryConfiguration.java b/jdbc/aot-optimization/src/main/java/example/springdata/aot/CategoryConfiguration.java
new file mode 100644
index 000000000..67006ef99
--- /dev/null
+++ b/jdbc/aot-optimization/src/main/java/example/springdata/aot/CategoryConfiguration.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.aot;
+
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.relational.core.mapping.event.BeforeSaveCallback;
+import org.springframework.data.relational.core.mapping.event.RelationalEvent;
+
+/**
+ * Contains infrastructure necessary for creating repositories, listeners and EntityCallbacks.
+ *
+ * Not that a listener may change an entity without any problem.
+ *
+ * @author Jens Schauder
+ * @author Mark Paluch
+ */
+@Configuration
+public class CategoryConfiguration {
+
+ /**
+ * @return {@link ApplicationListener} for {@link RelationalEvent}s.
+ */
+ @Bean
+ public ApplicationListener> loggingListener() {
+
+ return (ApplicationListener) event -> {
+ if (event instanceof RelationalEvent) {
+ System.out.println("Received an event: " + event);
+ }
+ };
+ }
+
+ /**
+ * @return {@link BeforeSaveCallback} for {@link Category}.
+ */
+ @Bean
+ public BeforeSaveCallback timeStampingSaveTime() {
+
+ return (entity, aggregateChange) -> {
+
+ entity.timeStamp();
+
+ return entity;
+ };
+ }
+}
diff --git a/jdbc/aot-optimization/src/main/java/example/springdata/aot/CategoryProjection.java b/jdbc/aot-optimization/src/main/java/example/springdata/aot/CategoryProjection.java
new file mode 100644
index 000000000..3a314cc1c
--- /dev/null
+++ b/jdbc/aot-optimization/src/main/java/example/springdata/aot/CategoryProjection.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
+ *
+ * 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;
+
+/**
+ * @author Mark Paluch
+ */
+public interface CategoryProjection {
+
+ String getName();
+
+ String getDescription();
+
+ default String getNameAndDescription() {
+ return getName() + " - " + getDescription();
+ }
+}
diff --git a/geode/security/src/main/java/example/springdata/geode/client/security/client/CustomerRepository.java b/jdbc/aot-optimization/src/main/java/example/springdata/aot/CategoryRepository.java
old mode 100755
new mode 100644
similarity index 52%
rename from geode/security/src/main/java/example/springdata/geode/client/security/client/CustomerRepository.java
rename to jdbc/aot-optimization/src/main/java/example/springdata/aot/CategoryRepository.java
index 13aaa686d..8efb47d70
--- a/geode/security/src/main/java/example/springdata/geode/client/security/client/CustomerRepository.java
+++ b/jdbc/aot-optimization/src/main/java/example/springdata/aot/CategoryRepository.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2020-2021 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.
* You may obtain a copy of the License at
*
- * https://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -13,20 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package example.springdata.geode.client.security.client;
-
-import example.springdata.geode.client.security.Customer;
+package example.springdata.aot;
import java.util.List;
+import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;
/**
- * @author Patrick Johnson
+ * Repository for Categories.
+ *
+ * @author Mark Paluch
*/
-public interface CustomerRepository extends CrudRepository {
+interface CategoryRepository extends CrudRepository {
+
+ List findAllByNameContaining(String name);
+
+ List findProjectedByNameContaining(String name);
- @Override
- List findAll();
+ @Query("SELECT * FROM category WHERE name = :name")
+ List findWithDeclaredQuery(String name);
}
diff --git a/jdbc/aot-optimization/src/main/resources/application.properties b/jdbc/aot-optimization/src/main/resources/application.properties
new file mode 100644
index 000000000..4e2092bc7
--- /dev/null
+++ b/jdbc/aot-optimization/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+#logging.level.org.springframework.data.repository.aot.generate.RepositoryContributor=trace
+
diff --git a/geode/expiration-eviction/src/main/java/example/springdata/geode/server/expiration/eviction/CustomerRepository.java b/jdbc/aot-optimization/src/main/resources/data.sql
old mode 100755
new mode 100644
similarity index 52%
rename from geode/expiration-eviction/src/main/java/example/springdata/geode/server/expiration/eviction/CustomerRepository.java
rename to jdbc/aot-optimization/src/main/resources/data.sql
index 09f73c124..f6c4d9ea3
--- a/geode/expiration-eviction/src/main/java/example/springdata/geode/server/expiration/eviction/CustomerRepository.java
+++ b/jdbc/aot-optimization/src/main/resources/data.sql
@@ -1,11 +1,11 @@
/*
- * Copyright 2020-2021 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.
* You may obtain a copy of the License at
*
- * https://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -13,13 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package example.springdata.geode.server.expiration.eviction;
-
-import org.springframework.data.gemfire.mapping.annotation.Region;
-import org.springframework.data.repository.CrudRepository;
-
-/**
- * @author Patrick Johnson
- */
-@Region("Customers")
-public interface CustomerRepository extends CrudRepository {}
+INSERT INTO category(name, description, created, inserted)
+VALUES ('Cars', 'Anything that has approximately 4 wheels.', now(), 1);
+INSERT INTO category(name, description, created, inserted)
+VALUES ('Buildings', 'Walls, anyone?', now(), 2);
+INSERT INTO category(name, description, created, inserted)
+VALUES ('Chemistry Labs', 'Heisenberg calling', now(), 3);
diff --git a/jdbc/aot-optimization/src/main/resources/schema.sql b/jdbc/aot-optimization/src/main/resources/schema.sql
new file mode 100644
index 000000000..369e89873
--- /dev/null
+++ b/jdbc/aot-optimization/src/main/resources/schema.sql
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+CREATE TABLE IF NOT EXISTS category
+(
+ id INTEGER IDENTITY PRIMARY KEY,
+ name VARCHAR(100),
+ description VARCHAR(2000),
+ created DATETIME,
+ inserted BIGINT
+);
diff --git a/jdbc/basics/pom.xml b/jdbc/basics/pom.xml
index cc22e6a9e..526ce850d 100644
--- a/jdbc/basics/pom.xml
+++ b/jdbc/basics/pom.xml
@@ -8,7 +8,7 @@
org.springframework.data.examples
spring-data-jdbc-examples
- 2.0.0.BUILD-SNAPSHOT
+ 4.0.0-SNAPSHOT
../pom.xml
diff --git a/jdbc/basics/src/main/java/example/springdata/jdbc/basics/simpleentity/Category.java b/jdbc/basics/src/main/java/example/springdata/jdbc/basics/simpleentity/Category.java
index b3ac203cc..d8232a161 100644
--- a/jdbc/basics/src/main/java/example/springdata/jdbc/basics/simpleentity/Category.java
+++ b/jdbc/basics/src/main/java/example/springdata/jdbc/basics/simpleentity/Category.java
@@ -26,7 +26,7 @@
import java.time.LocalDateTime;
import org.springframework.data.annotation.Id;
-import org.springframework.data.annotation.PersistenceConstructor;
+import org.springframework.data.annotation.PersistenceCreator;
/**
* Coarse classification for {@link LegoSet}s, like "Car", "Plane", "Building" and so on.
@@ -34,7 +34,7 @@
* @author Jens Schauder
*/
@Data
-@AllArgsConstructor(access = AccessLevel.PRIVATE, onConstructor = @__(@PersistenceConstructor))
+@AllArgsConstructor(access = AccessLevel.PRIVATE, onConstructor = @__(@PersistenceCreator))
public class Category {
private final @Id @With Long id;
diff --git a/jdbc/basics/src/main/resources/application.properties b/jdbc/basics/src/main/resources/application.properties
index 2804353df..912eeb5f4 100644
--- a/jdbc/basics/src/main/resources/application.properties
+++ b/jdbc/basics/src/main/resources/application.properties
@@ -1,2 +1,2 @@
logging.level.org.springframework.data=INFO
-logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
\ No newline at end of file
+logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
diff --git a/jdbc/basics/src/test/java/example/springdata/jdbc/basics/aggregate/AggregateTests.java b/jdbc/basics/src/test/java/example/springdata/jdbc/basics/aggregate/AggregateTests.java
index af44ca900..513c98997 100644
--- a/jdbc/basics/src/test/java/example/springdata/jdbc/basics/aggregate/AggregateTests.java
+++ b/jdbc/basics/src/test/java/example/springdata/jdbc/basics/aggregate/AggregateTests.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2017-2021 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.
* You may obtain a copy of the License at
*
- * https://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -21,13 +21,12 @@
import java.time.Period;
import java.util.Arrays;
-import java.util.List;
import org.assertj.core.groups.Tuple;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.data.jdbc.AutoConfigureDataJdbc;
+import org.springframework.boot.data.jdbc.test.autoconfigure.AutoConfigureDataJdbc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
diff --git a/jdbc/basics/src/test/java/example/springdata/jdbc/basics/simpleentity/SimpleEntityTests.java b/jdbc/basics/src/test/java/example/springdata/jdbc/basics/simpleentity/SimpleEntityTests.java
index d1eb7a9e6..bd2d83384 100644
--- a/jdbc/basics/src/test/java/example/springdata/jdbc/basics/simpleentity/SimpleEntityTests.java
+++ b/jdbc/basics/src/test/java/example/springdata/jdbc/basics/simpleentity/SimpleEntityTests.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2017-2021 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.
* You may obtain a copy of the License at
*
- * https://www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -23,14 +23,14 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureJdbc;
+import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureJdbc;
import org.springframework.boot.test.context.SpringBootTest;
/**
* Demonstrates simple CRUD operations with a simple entity without any references.
*
* @author Jens Schauder
- * @author Divya Srivastava
+ * @author Divya Srivastava
*/
@SpringBootTest(classes = CategoryConfiguration.class)
@AutoConfigureJdbc
diff --git a/jdbc/composite-ids/README.adoc b/jdbc/composite-ids/README.adoc
new file mode 100644
index 000000000..739d1d369
--- /dev/null
+++ b/jdbc/composite-ids/README.adoc
@@ -0,0 +1,8 @@
+== Spring Data JDBC Composite Id
+
+=== EmployeeTest
+
+Demonstrates saving an entity with composite id.
+
+Once by using a direct insert, via a custom `insert` method in the repository, backed by `JdbcAggregateTemplate.insert` and once by a custom id generating callback.
+See `CompositeConfiguration.idGeneration()`.
\ No newline at end of file
diff --git a/jdbc/composite-ids/pom.xml b/jdbc/composite-ids/pom.xml
new file mode 100644
index 000000000..bd73353b3
--- /dev/null
+++ b/jdbc/composite-ids/pom.xml
@@ -0,0 +1,25 @@
+
+ 4.0.0
+
+ spring-data-jdbc-composite-ids
+
+
+ org.springframework.data.examples
+ spring-data-jdbc-examples
+ 4.0.0-SNAPSHOT
+ ../pom.xml
+
+
+ Spring Data JDBC - Examples using composite ids
+ Sample project demonstrating Spring Data JDBCs support for custom ids
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
diff --git a/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/CompositeConfiguration.java b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/CompositeConfiguration.java
new file mode 100644
index 000000000..776d4a65a
--- /dev/null
+++ b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/CompositeConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * 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.jdbc.compositeid;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jdbc.repository.config.AbstractJdbcConfiguration;
+import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
+import org.springframework.data.relational.core.mapping.event.BeforeConvertCallback;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+
+/**
+ * Configuration for the demonstration of composite ids.
+ *
+ * Registers a {@link BeforeConvertCallback} for generating ids.
+ *
+ * @author Jens Schauder
+ */
+@Configuration
+@EnableJdbcRepositories
+public class CompositeConfiguration extends AbstractJdbcConfiguration {
+
+ @Bean
+ BeforeConvertCallback idGeneration() {
+ return new BeforeConvertCallback<>() {
+ AtomicLong counter = new AtomicLong();
+
+ @Override
+ public Employee onBeforeConvert(Employee employee) {
+ if (employee.id == null) {
+ employee.id = new EmployeeId(Organization.RND, counter.addAndGet(1));
+ }
+ return employee;
+ }
+ };
+ }
+}
diff --git a/geode/queries/src/main/java/example/springdata/geode/client/queries/EmailAddress.java b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/Employee.java
old mode 100755
new mode 100644
similarity index 55%
rename from geode/queries/src/main/java/example/springdata/geode/client/queries/EmailAddress.java
rename to jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/Employee.java
index e7d803743..070614f6e
--- a/geode/queries/src/main/java/example/springdata/geode/client/queries/EmailAddress.java
+++ b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/Employee.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 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.
@@ -13,25 +13,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package example.springdata.geode.client.queries;
+package example.springdata.jdbc.compositeid;
-import lombok.Data;
-
-import java.io.Serializable;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.PersistenceCreator;
/**
- * Value object to represent email addresses.
+ * A simple entity sporting a compostite id.
*
- * @author Udo Kohlmeyer
- * @author Patrick Johnson
+ * @author Jens Schauder
*/
-@Data
-public class EmailAddress implements Serializable {
+class Employee {
+
+ @Id
+ EmployeeId id;
- private String value;
+ String name;
- public EmailAddress(String value) {
+ @PersistenceCreator
+ Employee(EmployeeId id, String name) {
+
+ this.id = id;
+ this.name = name;
+ }
- this.value = value;
+ Employee(String name) {
+ this.name = name;
}
}
diff --git a/geode/events/src/main/java/example/springdata/geode/server/events/ProductRepository.java b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/EmployeeId.java
old mode 100755
new mode 100644
similarity index 68%
rename from geode/events/src/main/java/example/springdata/geode/server/events/ProductRepository.java
rename to jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/EmployeeId.java
index 12bf841b8..835ae6a62
--- a/geode/events/src/main/java/example/springdata/geode/server/events/ProductRepository.java
+++ b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/EmployeeId.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 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.
@@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package example.springdata.geode.server.events;
-
-import org.springframework.data.repository.CrudRepository;
+package example.springdata.jdbc.compositeid;
/**
- * @author Patrick Johnson
+ * Composite id for {@link Employee} instances.
+ *
+ * @author Jens Schauder
*/
-public interface ProductRepository extends CrudRepository {}
+record EmployeeId(
+ Organization organization,
+ Long employeeNumber) {
+}
diff --git a/geode/expiration-eviction/src/main/java/example/springdata/geode/server/expiration/eviction/EmailAddress.java b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/EmployeeRepository.java
old mode 100755
new mode 100644
similarity index 56%
rename from geode/expiration-eviction/src/main/java/example/springdata/geode/server/expiration/eviction/EmailAddress.java
rename to jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/EmployeeRepository.java
index f0a0fba96..066208a58
--- a/geode/expiration-eviction/src/main/java/example/springdata/geode/server/expiration/eviction/EmailAddress.java
+++ b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/EmployeeRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 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.
@@ -13,25 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package example.springdata.geode.server.expiration.eviction;
-import lombok.Data;
+package example.springdata.jdbc.compositeid;
+
+import org.springframework.data.repository.Repository;
-import java.io.Serializable;
/**
- * Value object to represent email addresses.
+ * Repositories for {@link Employee} instances.
*
- * @author Udo Kohlmeyer
- * @author Patrick Johnson
+ * @author Jens Schauder
+ * @see InsertRepository
+ * @see InsertRepositoryImpl
*/
-@Data
-public class EmailAddress implements Serializable {
-
- private String value;
-
- public EmailAddress(String value) {
+interface EmployeeRepository extends Repository, InsertRepository {
+ Employee findById(EmployeeId id);
- this.value = value;
- }
+ Employee save(Employee employee);
}
diff --git a/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/InsertRepository.java b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/InsertRepository.java
new file mode 100644
index 000000000..562b26ffb
--- /dev/null
+++ b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/InsertRepository.java
@@ -0,0 +1,27 @@
+/*
+ * 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.jdbc.compositeid;
+
+
+/**
+ * Interface for repositories supporting an {@literal insert} operation, that always performs an insert on the database
+ * and does not check the instance.
+ *
+ * @author Jens Schauder
+ */
+interface InsertRepository {
+ E insert(E employee);
+}
diff --git a/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/InsertRepositoryImpl.java b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/InsertRepositoryImpl.java
new file mode 100644
index 000000000..2735a6024
--- /dev/null
+++ b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/InsertRepositoryImpl.java
@@ -0,0 +1,38 @@
+/*
+ * 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.jdbc.compositeid;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.jdbc.core.JdbcAggregateTemplate;
+
+/**
+ * Fragment implementing the {@literal insert} operation using a {@link JdbcAggregateTemplate}.
+ *
+ * @author Jens Schauder
+ */
+class InsertRepositoryImpl implements InsertRepository {
+
+ private JdbcAggregateTemplate template;
+
+ InsertRepositoryImpl(JdbcAggregateTemplate template) {
+ this.template = template;
+ }
+
+ @Override
+ public E insert(E employee) {
+ return template.insert(employee);
+ }
+}
diff --git a/geode/storage/src/main/java/example/springdata/geode/server/storage/CustomerRepository.java b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/Organization.java
old mode 100755
new mode 100644
similarity index 67%
rename from geode/storage/src/main/java/example/springdata/geode/server/storage/CustomerRepository.java
rename to jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/Organization.java
index 8a55e832a..d53191357
--- a/geode/storage/src/main/java/example/springdata/geode/server/storage/CustomerRepository.java
+++ b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/Organization.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 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.
@@ -13,12 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package example.springdata.geode.server.storage;
-
-import org.springframework.data.repository.CrudRepository;
+package example.springdata.jdbc.compositeid;
/**
- * @author Patrick Johnson
+ * Just an enum to be part of the composite id, to demonstrate that one may use various datatypes.
+ *
+ * @author Jens Schauder
*/
-public interface CustomerRepository extends CrudRepository {
+enum Organization {
+ RND,
+ SALES,
+ MARKETING,
+ PURCHASING
}
diff --git a/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/package-info.java b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/package-info.java
new file mode 100644
index 000000000..b7ef233b4
--- /dev/null
+++ b/jdbc/composite-ids/src/main/java/example/springdata/jdbc/compositeid/package-info.java
@@ -0,0 +1,4 @@
+@NonNullApi
+package example.springdata.jdbc.compositeid;
+
+import org.springframework.lang.NonNullApi;
\ No newline at end of file
diff --git a/jdbc/composite-ids/src/main/resources/application.properties b/jdbc/composite-ids/src/main/resources/application.properties
new file mode 100644
index 000000000..2804353df
--- /dev/null
+++ b/jdbc/composite-ids/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+logging.level.org.springframework.data=INFO
+logging.level.org.springframework.jdbc.core.JdbcTemplate=DEBUG
\ No newline at end of file
diff --git a/jdbc/composite-ids/src/main/resources/schema.sql b/jdbc/composite-ids/src/main/resources/schema.sql
new file mode 100644
index 000000000..73e9ee996
--- /dev/null
+++ b/jdbc/composite-ids/src/main/resources/schema.sql
@@ -0,0 +1,6 @@
+create table employee
+(
+ organization varchar(20),
+ employee_number int,
+ name varchar(100)
+);
diff --git a/jdbc/composite-ids/src/test/java/example/springdata/jdbc/compositeid/EmployeeTests.java b/jdbc/composite-ids/src/test/java/example/springdata/jdbc/compositeid/EmployeeTests.java
new file mode 100644
index 000000000..c59e95c32
--- /dev/null
+++ b/jdbc/composite-ids/src/test/java/example/springdata/jdbc/compositeid/EmployeeTests.java
@@ -0,0 +1,55 @@
+/*
+ * 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.jdbc.compositeid;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.jupiter.api.Test;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.data.jdbc.test.autoconfigure.AutoConfigureDataJdbc;
+import org.springframework.boot.test.context.SpringBootTest;
+
+/**
+ * Test demonstrating the use of composite ids.
+ *
+ * @author Jens Schauder
+ */
+@SpringBootTest(classes = CompositeConfiguration.class)
+@AutoConfigureDataJdbc
+class EmployeeTests {
+
+ @Autowired
+ EmployeeRepository repository;
+
+ @Test
+ void employeeDirectInsert() {
+
+ Employee employee = repository.insert(new Employee(new EmployeeId(Organization.RND, 23L), "Jens Schauder"));
+
+ Employee reloaded = repository.findById(employee.id);
+
+ assertThat(reloaded.name).isEqualTo(employee.name);
+ }
+
+ @Test
+ void employeeIdGeneration() {
+
+ Employee employee = repository.save(new Employee("Mark Paluch"));
+
+ assertThat(employee.id).isNotNull();
+ }
+}
diff --git a/jdbc/graalvm-native/README.adoc b/jdbc/graalvm-native/README.adoc
new file mode 100644
index 000000000..3aa10ed9b
--- /dev/null
+++ b/jdbc/graalvm-native/README.adoc
@@ -0,0 +1,47 @@
+== Spring Data JDBC - GraalVM native image
+
+This example compiles a basic Spring Data JDBC application into a GraalVM native image.
+
+=== Install GraalVM & native image tooling
+
+Download and install GraalVM using https://sdkman.io/[SDKMAN!].
+
+```
+$> sdk install java .r17-grl
+$> gu install native-image
+```
+
+=== Compile to native image
+
+The maven build uses a dedicated profile `native` to trigger the native image creation.
+
+```
+$> maven clean package -P native
+```
+
+This will create the native executable in the target folder.
+
+=== Run the image
+
+Run the image directly from your console as shown below.
+This will print results of crud functions invoked via a `CommandLineRunner`.
+
+```
+$> ./target/spring-data-jdbc-graalvm-native
+
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v3.0.0-SNAPSHOT)
+
+INFO 82562 --- [ main] e.s.j.g.GraalvmNativeApplication : Starting GraalvmNativeApplication using Java 17.0.4 with PID 82562
+INFO 82562 --- [ main] e.s.j.g.GraalvmNativeApplication : Started GraalvmNativeApplication in 0.042 seconds (process running for 0.061)
+insertAuthors(): author1 = Author{name='Josh Long'}
+insertAuthors(): author2 = Author{name='Martin Kleppmann'}
+listAllAuthors(): author = Author{name='Josh Long'}
+ Book{title='Reactive Spring'}
+...
+```
diff --git a/jdbc/graalvm-native/pom.xml b/jdbc/graalvm-native/pom.xml
new file mode 100644
index 000000000..4450cd3dc
--- /dev/null
+++ b/jdbc/graalvm-native/pom.xml
@@ -0,0 +1,54 @@
+
+ 4.0.0
+
+ spring-data-jdbc-graalvm-native
+
+
+ org.springframework.data.examples
+ spring-data-examples
+ 4.0.0-SNAPSHOT
+ ../../pom.xml
+
+
+ Spring Data JDBC - GraalVM native sample
+ Sample project demonstrating Spring Data JDBC features running as GraalVM native image
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jdbc
+
+
+
+ com.h2database
+ h2
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+
+ native
+
+
+
+ org.graalvm.buildtools
+ native-maven-plugin
+
+
+
+
+
+
+
diff --git a/geode/expiration-eviction/src/main/java/example/springdata/geode/server/expiration/eviction/Address.java b/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/AuthorRepository.java
old mode 100755
new mode 100644
similarity index 50%
rename from geode/expiration-eviction/src/main/java/example/springdata/geode/server/expiration/eviction/Address.java
rename to jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/AuthorRepository.java
index d71862f03..e9b66bb4e
--- a/geode/expiration-eviction/src/main/java/example/springdata/geode/server/expiration/eviction/Address.java
+++ b/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/AuthorRepository.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2022 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.
@@ -13,29 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package example.springdata.geode.server.expiration.eviction;
+package example.springdata.jdbc.graalvmnative;
-import lombok.Data;
+import java.util.Optional;
-import java.io.Serializable;
+import example.springdata.jdbc.graalvmnative.model.Author;
+import org.springframework.data.jdbc.repository.query.Query;
+import org.springframework.data.repository.ListCrudRepository;
-/**
- * An address used in the examples.
- *
- * @author Oliver Gierke
- * @author Udo Kohlmeyer
- * @author Patrick Johnson
- */
-@Data
-public class Address implements Serializable {
+public interface AuthorRepository extends ListCrudRepository {
- private String street;
- private String city;
- private String country;
+ Optional findByNameContainingIgnoreCase(String partialName);
- public Address(String street, String city, String country) {
- this.street = street;
- this.city = city;
- this.country = country;
- }
+ @Query("SELECT * FROM author a WHERE a.name = :name LIMIT 1")
+ Optional queryFindByName(String name);
}
diff --git a/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/CLR.java b/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/CLR.java
new file mode 100644
index 000000000..785906499
--- /dev/null
+++ b/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/CLR.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2022 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.jdbc.graalvmnative;
+
+import java.util.List;
+import java.util.Set;
+
+import example.springdata.jdbc.graalvmnative.model.Author;
+import example.springdata.jdbc.graalvmnative.model.Book;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Christoph Strobl
+ * @since 2022/10
+ */
+@Component
+public class CLR implements CommandLineRunner {
+
+ private final AuthorRepository authorRepository;
+
+ CLR(AuthorRepository authorRepository) {
+ this.authorRepository = authorRepository;
+ }
+
+ @Override
+ public void run(String... args) {
+ insertAuthors();
+ listAllAuthors();
+ findById();
+ findByPartialName();
+ queryFindByName();
+ deleteAll();
+ }
+
+ private void deleteAll() {
+ this.authorRepository.deleteAll();
+ long count = this.authorRepository.count();
+ System.out.printf("deleteAll(): count = %d%n", count);
+ }
+
+ private void queryFindByName() {
+ Author author1 = this.authorRepository.queryFindByName("Josh Long").orElse(null);
+ Author author2 = this.authorRepository.queryFindByName("Martin Kleppmann").orElse(null);
+
+ System.out.printf("queryFindByName(): author1 = %s%n", author1);
+ System.out.printf("queryFindByName(): author2 = %s%n", author2);
+ }
+
+ private void findByPartialName() {
+ Author author1 = this.authorRepository.findByNameContainingIgnoreCase("sh lo").orElse(null);
+ Author author2 = this.authorRepository.findByNameContainingIgnoreCase("in kl").orElse(null);
+
+ System.out.printf("findByPartialName(): author1 = %s%n", author1);
+ System.out.printf("findByPartialName(): author2 = %s%n", author2);
+ }
+
+ private void findById() {
+ Author author1 = this.authorRepository.findById(1L).orElse(null);
+ Author author2 = this.authorRepository.findById(2L).orElse(null);
+
+ System.out.printf("findById(): author1 = %s%n", author1);
+ System.out.printf("findById(): author2 = %s%n", author2);
+ }
+
+ private void listAllAuthors() {
+ List authors = this.authorRepository.findAll();
+ for (Author author : authors) {
+ System.out.printf("listAllAuthors(): author = %s%n", author);
+ for (Book book : author.getBooks()) {
+ System.out.printf("\t%s%n", book);
+ }
+ }
+ }
+
+ private void insertAuthors() {
+ Author author1 = this.authorRepository.save(new Author(null, "Josh Long",
+ Set.of(new Book(null, "Reactive Spring"), new Book(null, "Cloud Native Java"))));
+ Author author2 = this.authorRepository.save(
+ new Author(null, "Martin Kleppmann", Set.of(new Book(null, "Designing Data Intensive Applications"))));
+
+ System.out.printf("insertAuthors(): author1 = %s%n", author1);
+ System.out.printf("insertAuthors(): author2 = %s%n", author2);
+ }
+}
diff --git a/geode/queries/src/main/java/example/springdata/geode/client/queries/server/QueryServer.java b/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/GraalvmNativeApplication.java
old mode 100755
new mode 100644
similarity index 64%
rename from geode/queries/src/main/java/example/springdata/geode/client/queries/server/QueryServer.java
rename to jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/GraalvmNativeApplication.java
index cbd501e62..f78bd031b
--- a/geode/queries/src/main/java/example/springdata/geode/client/queries/server/QueryServer.java
+++ b/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/GraalvmNativeApplication.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2020-2021 the original author or authors.
+ * Copyright 2022 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.
@@ -13,19 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package example.springdata.geode.client.queries.server;
+package example.springdata.jdbc.graalvmnative;
-import org.springframework.boot.WebApplicationType;
+import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.builder.SpringApplicationBuilder;
-/**
- * @author Patrick Johnson
- */
@SpringBootApplication
-public class QueryServer {
+public class GraalvmNativeApplication {
public static void main(String[] args) {
- new SpringApplicationBuilder(QueryServer.class).web(WebApplicationType.NONE).build().run(args);
+ SpringApplication.run(GraalvmNativeApplication.class, args);
}
}
diff --git a/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/model/Author.java b/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/model/Author.java
new file mode 100644
index 000000000..29f476511
--- /dev/null
+++ b/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/model/Author.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2022 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.jdbc.graalvmnative.model;
+
+import java.util.Objects;
+import java.util.Set;
+
+import org.springframework.data.annotation.Id;
+
+public class Author {
+
+ @Id
+ private final Long id;
+
+ private final String name;
+
+ private final Set books;
+
+ public Author(Long id, String name, Set books) {
+ this.id = id;
+ this.name = name;
+ this.books = books;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Set getBooks() {
+ return books;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Author author = (Author) o;
+ return Objects.equals(id, author.id) && Objects.equals(name, author.name)
+ && Objects.equals(books, author.books);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, name, books);
+ }
+
+ @Override
+ public String toString() {
+ return "Author{" + "name='" + name + '\'' + '}';
+ }
+}
diff --git a/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/model/Book.java b/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/model/Book.java
new file mode 100644
index 000000000..ea3d59163
--- /dev/null
+++ b/jdbc/graalvm-native/src/main/java/example/springdata/jdbc/graalvmnative/model/Book.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2022 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.jdbc.graalvmnative.model;
+
+import java.util.Objects;
+
+import org.springframework.data.annotation.Id;
+
+public class Book {
+
+ @Id
+ private final Long id;
+
+ private final String title;
+
+ public Book(Long id, String title) {
+ this.id = id;
+ this.title = title;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Book book = (Book) o;
+ return Objects.equals(id, book.id) && Objects.equals(title, book.title);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, title);
+ }
+
+ @Override
+ public String toString() {
+ return "Book{" + "title='" + title + '\'' + '}';
+ }
+}
diff --git a/jdbc/graalvm-native/src/main/resources/application.properties b/jdbc/graalvm-native/src/main/resources/application.properties
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/jdbc/graalvm-native/src/main/resources/application.properties
@@ -0,0 +1 @@
+
diff --git a/jdbc/graalvm-native/src/main/resources/schema.sql b/jdbc/graalvm-native/src/main/resources/schema.sql
new file mode 100644
index 000000000..14e51639f
--- /dev/null
+++ b/jdbc/graalvm-native/src/main/resources/schema.sql
@@ -0,0 +1,12 @@
+create table author
+(
+ id bigint auto_increment primary key,
+ name varchar not null
+);
+
+create table book
+(
+ id bigint auto_increment primary key,
+ author bigint not null references author (id),
+ title varchar not null
+);
diff --git a/jdbc/graalvm-native/src/test/java/example/springdata/jdbc/graalvmnative/GraalvmNativeApplicationTests.java b/jdbc/graalvm-native/src/test/java/example/springdata/jdbc/graalvmnative/GraalvmNativeApplicationTests.java
new file mode 100644
index 000000000..90520e4ad
--- /dev/null
+++ b/jdbc/graalvm-native/src/test/java/example/springdata/jdbc/graalvmnative/GraalvmNativeApplicationTests.java
@@ -0,0 +1,13 @@
+package example.springdata.jdbc.graalvmnative;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class GraalvmNativeApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/jdbc/howto/bidirectionalexternal/pom.xml b/jdbc/howto/bidirectionalexternal/pom.xml
index 0a66d24c8..8f4c77d81 100644
--- a/jdbc/howto/bidirectionalexternal/pom.xml
+++ b/jdbc/howto/bidirectionalexternal/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data.examples
spring-data-jdbc-how-to
- 2.0.0.BUILD-SNAPSHOT
+ 4.0.0-SNAPSHOT
../pom.xml
@@ -16,6 +16,6 @@
Spring Data JDBC - How to model bidirectional relationships between aggregates
Sample project for Spring Data JDBC demonstrating how to model bidirectional relationships between aggregates.
It serves as a source code repository for a How-To article on the Spring Blog
- https://projects.spring.io/spring-data-jdbc
+ https://spring.io/spring-data-jdbc
2021