diff --git a/ci/pipeline.properties b/ci/pipeline.properties
index cde4a8e881..b9297d8d2b 100644
--- a/ci/pipeline.properties
+++ b/ci/pipeline.properties
@@ -1,10 +1,10 @@
# Java versions
-java.main.tag=24.0.1_9-jdk-noble
-java.next.tag=24.0.1_9-jdk-noble
+java.main.tag=25
+java.next.tag=25-cds
# Docker container images - standard
-docker.java.main.image=library/eclipse-temurin:${java.main.tag}
-docker.java.next.image=library/eclipse-temurin:${java.next.tag}
+docker.java.main.image=bellsoft/liberica-openjdk-alpine:${java.main.tag}
+docker.java.next.image=bellsoft/liberica-openjdk-alpine:${java.next.tag}
# Supported versions of MongoDB
docker.mongodb.6.0.version=6.0.23
diff --git a/pom.xml b/pom.xml
index 13143c9f6f..f4bc430605 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-commons
- 4.0.0-SNAPSHOT
+ 4.0.0-STABLE-VALUE-SNAPSHOT
Spring Data Core
Core Spring concepts underpinning every Spring Data module.
@@ -341,18 +341,55 @@
+
org.apache.maven.plugins
maven-assembly-plugin
+
org.antora
antora-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+
+
+ default-jar
+
+
+
+ true
+
+
+
+
+
+
+
org.apache.maven.plugins
maven-compiler-plugin
+
+
+ jdk25
+
+ compile
+
+
+ true
+ 25
+
+ ${project.basedir}/src/main/java25
+
+
+ true
+
+
+
java-test-compile
@@ -366,8 +403,10 @@
+
+
diff --git a/src/main/java/org/springframework/data/util/Lazy.java b/src/main/java/org/springframework/data/util/Lazy.java
index 193726da60..f5208ce2c1 100644
--- a/src/main/java/org/springframework/data/util/Lazy.java
+++ b/src/main/java/org/springframework/data/util/Lazy.java
@@ -22,7 +22,6 @@
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
-import org.springframework.util.ObjectUtils;
/**
* Simple value type to delay the creation of an object using a {@link Supplier} returning the produced object for
@@ -40,30 +39,14 @@
*/
public class Lazy implements Supplier {
- private static final Lazy> EMPTY = new Lazy<>(() -> null, null, true);
- static final String UNRESOLVED = "[Unresolved]";
+ private static final Lazy> EMPTY = new Lazy<>(() -> null);
- private final Supplier extends @Nullable T> supplier;
+ static final String UNRESOLVED = "[Unresolved]";
- private @Nullable T value;
- private volatile boolean resolved;
+ private final LazyDelegate extends @Nullable T> adapter;
- private Lazy(Supplier extends @Nullable T> supplier) {
- this(supplier, null, false);
- }
-
- /**
- * Creates a new {@code Lazy} for the given {@link Supplier}, value and whether it has been resolved or not.
- *
- * @param supplier must not be {@literal null}.
- * @param value can be {@literal null}.
- * @param resolved whether the value handed into the constructor represents a resolved value.
- */
- private Lazy(Supplier extends @Nullable T> supplier, @Nullable T value, boolean resolved) {
-
- this.supplier = supplier;
- this.value = value;
- this.resolved = resolved;
+ private Lazy(Supplier extends @Nullable T> adapter) {
+ this.adapter = new LazyDelegate<>(adapter);
}
/**
@@ -128,16 +111,7 @@ public T get() {
*/
@Nullable
public T getNullable() {
-
- if (resolved) {
- return value;
- }
-
- T result = supplier.get();
- this.value = result;
- this.resolved = true;
-
- return result;
+ return adapter.getNullable();
}
/**
@@ -249,35 +223,22 @@ public boolean equals(@Nullable Object o) {
return false;
}
- if (resolved != lazy.resolved) {
- return false;
- }
-
- if (!ObjectUtils.nullSafeEquals(supplier, lazy.supplier)) {
- return false;
- }
-
- return ObjectUtils.nullSafeEquals(value, lazy.value);
+ return adapter.equals(lazy.adapter);
}
@Override
public int hashCode() {
-
- int result = ObjectUtils.nullSafeHashCode(supplier);
-
- result = 31 * result + ObjectUtils.nullSafeHashCode(value);
- result = 31 * result + (resolved ? 1 : 0);
-
- return result;
+ return adapter.hashCode();
}
@Override
public String toString() {
- if (!resolved) {
+ if (!adapter.isResolved()) {
return UNRESOLVED;
}
+ T value = getNullable();
return value == null ? "null" : value.toString();
}
@@ -293,6 +254,6 @@ public String toString(Supplier fallback) {
Assert.notNull(fallback, "Fallback must not be null!");
- return resolved ? toString() : fallback.get();
+ return adapter.isResolved() ? toString() : fallback.get();
}
}
diff --git a/src/main/java/org/springframework/data/util/LazyDelegate.java b/src/main/java/org/springframework/data/util/LazyDelegate.java
new file mode 100644
index 0000000000..e077b4069c
--- /dev/null
+++ b/src/main/java/org/springframework/data/util/LazyDelegate.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016-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 org.springframework.data.util;
+
+import java.util.function.Supplier;
+
+import org.jspecify.annotations.Nullable;
+
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Simple lazy implementation using lazy value resolution. Lazy evaluation not guarded with locks and can therefore lead
+ * to multiple invocations of the underlying {@link Supplier}.
+ *
+ * @author Oliver Gierke
+ * @author Mark Paluch
+ * @author Henning Rohlfs
+ * @author Johannes Englmeier
+ * @author Greg Turnquist
+ * @since 4.0
+ */
+class LazyDelegate {
+
+ private final Supplier supplier;
+
+ private @Nullable T value;
+ private volatile boolean resolved;
+
+ LazyDelegate(Supplier supplier) {
+ this.supplier = supplier;
+ }
+
+ /**
+ * Returns the value of the lazy evaluation.
+ *
+ * @return the value of the lazy evaluation, can be {@literal null}.
+ */
+ @Nullable
+ public T getNullable() {
+
+ if (resolved) {
+ return value;
+ }
+
+ T result = supplier.get();
+ this.value = result;
+ this.resolved = true;
+
+ return result;
+ }
+
+ public boolean isResolved() {
+ return resolved;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof LazyDelegate> lazy)) {
+ return false;
+ }
+
+ if (resolved != lazy.resolved) {
+ return false;
+ }
+
+ if (!ObjectUtils.nullSafeEquals(supplier, lazy.supplier)) {
+ return false;
+ }
+
+ return ObjectUtils.nullSafeEquals(value, lazy.value);
+ }
+
+ @Override
+ public int hashCode() {
+
+ int result = ObjectUtils.nullSafeHashCode(supplier);
+
+ result = 31 * result + ObjectUtils.nullSafeHashCode(value);
+ result = 31 * result + (resolved ? 1 : 0);
+
+ return result;
+ }
+
+}
diff --git a/src/main/java25/org/springframework/data/util/LazyDelegate.java b/src/main/java25/org/springframework/data/util/LazyDelegate.java
new file mode 100644
index 0000000000..73d9fd1ce7
--- /dev/null
+++ b/src/main/java25/org/springframework/data/util/LazyDelegate.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016-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 org.springframework.data.util;
+
+import java.util.function.Supplier;
+
+import org.jspecify.annotations.Nullable;
+
+import org.springframework.util.ObjectUtils;
+
+/**
+ * Lazy adapter using {@link StableValue}.
+ *
+ * @author Mark Paluch
+ * @since 4.0
+ */
+class LazyDelegate {
+
+ private final Supplier supplier;
+ private final StableValue value;
+
+ LazyDelegate(Supplier supplier) {
+
+ System.out.println("Stable");
+ this.supplier = supplier;
+ this.value = StableValue.of();
+ }
+
+ /**
+ * Returns the value of the lazy evaluation.
+ *
+ * @return the value of the lazy evaluation, can be {@literal null}.
+ */
+ @Nullable
+ public T getNullable() {
+ return value.orElseSet(supplier);
+ }
+
+ public boolean isResolved() {
+ return value.isSet();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof LazyDelegate> lazy)) {
+ return false;
+ }
+
+ return ObjectUtils.nullSafeEquals(value, lazy.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+}