diff --git a/.mvn/jvm.config b/.mvn/jvm.config
new file mode 100644
index 00000000..32599cef
--- /dev/null
+++ b/.mvn/jvm.config
@@ -0,0 +1,10 @@
+--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
+--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
+--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
diff --git a/pom.xml b/pom.xml
index b4d33f6f..2cd53a4b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -72,6 +72,7 @@
3.6.2
3.27.3
0.0.7
+ 2.36.0
1.3
1.5.18
0.8.12
@@ -81,6 +82,7 @@
2.9.0
5.12.2
1.18.38
+ 0.12.7
2024.0.6
2.0.17
7.0.0-M5
@@ -149,6 +151,54 @@
+
+ nullaway
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ true
+
+
+
+
+ default-compile
+ none
+
+
+ java-compile
+ compile
+
+ compile
+
+
+
+
+ com.google.errorprone
+ error_prone_core
+ ${errorprone.version}
+
+
+ com.uber.nullaway
+ nullaway
+ ${nullaway.version}
+
+
+
+ -XDcompilePolicy=simple
+ --should-stop=ifError=FLOW
+ -Xplugin:ErrorProne -XepDisableAllChecks -Xep:NullAway:ERROR -XepOpt:NullAway:OnlyNullMarked=true -XepOpt:NullAway:CustomContractAnnotations=org.springframework.lang.Contract
+
+
+
+
+
+
+
+
+
artifactory
@@ -469,6 +519,11 @@
kotlinx-coroutines-reactor
true
+
+ org.jspecify
+ jspecify
+ 1.0.0
+
org.jetbrains.kotlin
kotlin-test
diff --git a/src/main/java/org/springframework/hateoas/Affordance.java b/src/main/java/org/springframework/hateoas/Affordance.java
index 56a35465..2109c1c4 100644
--- a/src/main/java/org/springframework/hateoas/Affordance.java
+++ b/src/main/java/org/springframework/hateoas/Affordance.java
@@ -19,8 +19,9 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
+import org.jspecify.annotations.Nullable;
import org.springframework.http.MediaType;
-import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
/**
* Hold the {@link AffordanceModel}s for all supported media types.
@@ -42,8 +43,8 @@ public final class Affordance implements Iterable {
/**
* Look up the {@link AffordanceModel} for the requested {@link MediaType}.
*
- * @param mediaType
- * @return
+ * @param mediaType must not be {@literal null}.
+ * @return can be {@literal null}.
*/
@Nullable
@SuppressWarnings("unchecked")
@@ -51,6 +52,23 @@ public final class Affordance implements Iterable {
return (T) this.models.get(mediaType);
}
+ /**
+ * Look up the {@link AffordanceModel} for the requested {@link MediaType}.
+ *
+ * @param mediaType must not be {@literal null}.
+ * @return will never be {@literal null}.
+ * @since 3.0
+ */
+ @SuppressWarnings("unchecked")
+ public T getRequiredAffordanceModel(MediaType mediaType) {
+
+ var result = getAffordanceModel(mediaType);
+
+ Assert.notNull(result, () -> "No affordance model found for %s!".formatted(mediaType));
+
+ return (T) result;
+ }
+
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
diff --git a/src/main/java/org/springframework/hateoas/AffordanceModel.java b/src/main/java/org/springframework/hateoas/AffordanceModel.java
index 51d30549..35c86350 100644
--- a/src/main/java/org/springframework/hateoas/AffordanceModel.java
+++ b/src/main/java/org/springframework/hateoas/AffordanceModel.java
@@ -24,10 +24,10 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import org.jspecify.annotations.Nullable;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
-import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
diff --git a/src/main/java/org/springframework/hateoas/CollectionModel.java b/src/main/java/org/springframework/hateoas/CollectionModel.java
index a662813e..312dd27e 100644
--- a/src/main/java/org/springframework/hateoas/CollectionModel.java
+++ b/src/main/java/org/springframework/hateoas/CollectionModel.java
@@ -22,11 +22,11 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.Objects;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.core.ResolvableTypeProvider;
-import org.springframework.lang.NonNull;
-import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -44,7 +44,7 @@ public class CollectionModel extends RepresentationModel>
private final Collection content;
private final @Nullable ResolvableType fallbackType;
- private ResolvableType fullType;
+ private @Nullable ResolvableType fullType;
/**
* Creates an empty {@link CollectionModel} instance.
diff --git a/src/main/java/org/springframework/hateoas/EntityModel.java b/src/main/java/org/springframework/hateoas/EntityModel.java
index d74354ea..0fcc2adc 100644
--- a/src/main/java/org/springframework/hateoas/EntityModel.java
+++ b/src/main/java/org/springframework/hateoas/EntityModel.java
@@ -21,9 +21,10 @@ import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Objects;
-import org.springframework.lang.NonNull;
-import org.springframework.lang.Nullable;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
@@ -50,7 +51,7 @@ import com.fasterxml.jackson.databind.util.NameTransformer;
*/
public class EntityModel extends RepresentationModel> {
- private T content;
+ private @Nullable T content;
/**
* Creates an empty {@link EntityModel}.
@@ -118,19 +119,17 @@ public class EntityModel extends RepresentationModel> {
*
* @return the content
*/
- @Nullable
@JsonUnwrapped
@JsonSerialize(using = MapSuppressingUnwrappingSerializer.class)
public T getContent() {
- return content;
+ return Objects.requireNonNull(content);
}
// Hacks to allow deserialization into an EntityModel