GH-2332 - Move to jSpecify for nullability verification.

This commit is contained in:
Oliver Drotbohm
2025-05-30 17:16:15 +02:00
parent c77993ba91
commit d996dd48d0
171 changed files with 560 additions and 415 deletions

10
.mvn/jvm.config Normal file
View File

@@ -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

55
pom.xml
View File

@@ -72,6 +72,7 @@
<artifactory-maven-plugin.version>3.6.2</artifactory-maven-plugin.version>
<assertj.version>3.27.3</assertj.version>
<spring-asciidoctor-backends.version>0.0.7</spring-asciidoctor-backends.version>
<errorprone.version>2.36.0</errorprone.version>
<evo.version>1.3</evo.version>
<logback.version>1.5.18</logback.version>
<jacoco>0.8.12</jacoco>
@@ -81,6 +82,7 @@
<jsonpath.version>2.9.0</jsonpath.version>
<junit.version>5.12.2</junit.version>
<lombok.version>1.18.38</lombok.version>
<nullaway.version>0.12.7</nullaway.version>
<reactor-bom.version>2024.0.6</reactor-bom.version>
<slf4j.version>2.0.17</slf4j.version>
<spring.version>7.0.0-M5</spring.version>
@@ -149,6 +151,54 @@
</profile>
<profile>
<id>nullaway</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<showWarnings>true</showWarnings>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>${errorprone.version}</version>
</path>
<path>
<groupId>com.uber.nullaway</groupId>
<artifactId>nullaway</artifactId>
<version>${nullaway.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-XDcompilePolicy=simple</arg>
<arg>--should-stop=ifError=FLOW</arg>
<arg>-Xplugin:ErrorProne -XepDisableAllChecks -Xep:NullAway:ERROR -XepOpt:NullAway:OnlyNullMarked=true -XepOpt:NullAway:CustomContractAnnotations=org.springframework.lang.Contract</arg>
</compilerArgs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>artifactory</id>
<properties>
@@ -469,6 +519,11 @@
<artifactId>kotlinx-coroutines-reactor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>

View File

@@ -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<AffordanceModel> {
/**
* 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<AffordanceModel> {
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 extends AffordanceModel> 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()

View File

@@ -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;
/**

View File

@@ -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<T> extends RepresentationModel<CollectionModel<T>>
private final Collection<T> content;
private final @Nullable ResolvableType fallbackType;
private ResolvableType fullType;
private @Nullable ResolvableType fullType;
/**
* Creates an empty {@link CollectionModel} instance.

View File

@@ -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<T> extends RepresentationModel<EntityModel<T>> {
private T content;
private @Nullable T content;
/**
* Creates an empty {@link EntityModel}.
@@ -118,19 +119,17 @@ public class EntityModel<T> extends RepresentationModel<EntityModel<T>> {
*
* @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<Map<String, Object>>
@Nullable
@JsonAnyGetter
@SuppressWarnings("unchecked")
private Map<String, Object> getMapContent() {
private @Nullable Map<String, Object> getMapContent() {
return Map.class.isInstance(content) ? (Map<String, Object>) content : null;
}

View File

@@ -22,8 +22,6 @@ import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.hateoas.mediatype.html.HtmlInputType;
/**
* Annotation to declare a dedicated input type for a property of an representation model. Input types are usually
* derived from the property's type or JSR-303 validation annotations. Use this annotation to override the type.

View File

@@ -23,7 +23,7 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -184,7 +184,10 @@ public class Link implements Serializable {
* Empty constructor required by the marshaling framework.
*/
protected Link() {
this.affordances = new ArrayList<>();
this.rel = LinkRelation.of("__synthetic__");
this.href = "__synthetic__";
}
/**

View File

@@ -28,7 +28,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

View File

@@ -21,8 +21,6 @@ import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Annotation to be used in combination with {@link RequestParam} to indicate that collection based values are supposed
* to be rendered as non-composite values, i.e. like {@code param=value1,value2,value3} rather than

View File

@@ -23,9 +23,9 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -41,7 +41,7 @@ public class PagedModel<T> extends CollectionModel<T> {
public static PagedModel<?> NO_PAGE = new PagedModel<>();
private final PageMetadata metadata;
private final @Nullable PageMetadata metadata;
private final @Nullable ResolvableType fallbackType;
/**
@@ -273,8 +273,7 @@ public class PagedModel<T> extends CollectionModel<T> {
* @return the metadata
*/
@JsonProperty("page")
@Nullable
public PageMetadata getMetadata() {
public @Nullable PageMetadata getMetadata() {
return metadata;
}

View File

@@ -18,10 +18,10 @@ package org.springframework.hateoas;
import java.util.Objects;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestParam;

View File

@@ -25,7 +25,7 @@ import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonProperty;

View File

@@ -23,9 +23,9 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -42,7 +42,7 @@ public class SlicedModel<T> extends CollectionModel<T> {
public static SlicedModel<?> NO_SLICE = new SlicedModel<>();
private final SliceMetadata metadata;
private final @Nullable SliceMetadata metadata;
private final @Nullable ResolvableType fallbackType;
/**
@@ -290,9 +290,8 @@ public class SlicedModel<T> extends CollectionModel<T> {
*
* @return the metadata can be {@literal null}.
*/
@Nullable
@JsonProperty("page")
public SliceMetadata getMetadata() {
public @Nullable SliceMetadata getMetadata() {
return metadata;
}

View File

@@ -20,7 +20,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonCreator;

View File

@@ -28,7 +28,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriUtils;
@@ -498,6 +498,7 @@ public final class TemplateVariable implements Serializable, UriTemplate.Expanda
/**
* @deprecated since 1.4. Use the actual type and call {@link TemplateVariable#composite()}.
*/
@Deprecated
COMPOSITE_PARAM("*", "", true);
private static final EnumSet<VariableType> COMBINABLE_TYPES = EnumSet.of(REQUEST_PARAM, REQUEST_PARAM_CONTINUED);

View File

@@ -27,8 +27,8 @@ import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.TemplateVariable.VariableType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -29,8 +29,8 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.TemplateVariable.VariableType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.hateoas.aot;
import static java.util.Objects.*;
import static org.springframework.hateoas.aot.AotUtils.*;
import java.lang.annotation.Annotation;
@@ -23,6 +24,7 @@ import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.function.Predicate;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopConfigException;
@@ -36,9 +38,7 @@ import org.springframework.beans.factory.aot.BeanRegistrationCode;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.hateoas.server.core.DummyInvocationUtils;
import org.springframework.hateoas.server.core.LastInvocationAware;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -176,8 +176,8 @@ public class ControllerMethodReturnTypeAotProcessor implements BeanRegistrationA
reflection.registerType(result, MemberCategory.INVOKE_DECLARED_METHODS);
reflection.registerField(ReflectionUtils.findField(result, "CGLIB$FACTORY_DATA"));
reflection.registerField(ReflectionUtils.findField(result, "CGLIB$CALLBACK_FILTER"));
reflection.registerField(requireNonNull(ReflectionUtils.findField(result, "CGLIB$FACTORY_DATA")));
reflection.registerField(requireNonNull(ReflectionUtils.findField(result, "CGLIB$CALLBACK_FILTER")));
}
return result;

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.hateoas.aot;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.hateoas.RepresentationModel;
@@ -31,7 +32,7 @@ class HateoasTypesRuntimeHints implements RuntimeHintsRegistrar {
* @see org.springframework.aot.hint.RuntimeHintsRegistrar#registerHints(org.springframework.aot.hint.RuntimeHints, java.lang.ClassLoader)
*/
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
var packageName = RepresentationModel.class.getPackageName();
var reflection = hints.reflection();

View File

@@ -21,6 +21,7 @@ import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
@@ -46,7 +47,7 @@ class HypermediaTypeAotProcessor implements BeanRegistrationAotProcessor {
* @see org.springframework.beans.factory.aot.BeanRegistrationAotProcessor#processAheadOfTime(org.springframework.beans.factory.support.RegisteredBean)
*/
@Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
public @Nullable BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
EnableHypermediaSupport annotation = AnnotatedElementUtils.findMergedAnnotation(registeredBean.getBeanClass(),
EnableHypermediaSupport.class);

View File

@@ -18,6 +18,7 @@ package org.springframework.hateoas.aot;
import java.io.IOException;
import java.util.function.Predicate;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.core.annotation.MergedAnnotation;
@@ -56,7 +57,7 @@ class HypermediaTypesRuntimeHints implements RuntimeHintsRegistrar {
* @see org.springframework.aot.hint.RuntimeHintsRegistrar#registerHints(org.springframework.aot.hint.RuntimeHints, java.lang.ClassLoader)
*/
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
AotUtils.registerTypesForReflection(hypermediaPackage, hints.reflection(),
HAS_JACKSON_SUPER_TYPE_FILTER, IS_JACKSON_ANNOTATION_PRESENT_FILTER);

View File

@@ -17,11 +17,10 @@ package org.springframework.hateoas.aot;
import static org.springframework.hateoas.aot.AotUtils.*;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.aot.BeanRegistrationAotContribution;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.support.RegisteredBean;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.RepresentationModelAssembler;
/**
@@ -38,11 +37,11 @@ class RepresentationModelAssemblerAotProcessor implements BeanRegistrationAotPro
* @see org.springframework.beans.factory.aot.BeanRegistrationAotProcessor#processAheadOfTime(org.springframework.beans.factory.support.RegisteredBean)
*/
@Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
public @Nullable BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
var beanClass = registeredBean.getBeanClass();
if (!RepresentationModelAssembler.class.isAssignableFrom(beanClass)) {
if (beanClass == null || !RepresentationModelAssembler.class.isAssignableFrom(beanClass)) {
return null;
}

View File

@@ -0,0 +1,8 @@
/**
* AOT support.
*
* @author Christoph Strobl
* @author Oliver Drotbohm
*/
@org.jspecify.annotations.NullMarked
package org.springframework.hateoas.aot;

View File

@@ -20,8 +20,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -24,11 +24,11 @@ import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import org.jspecify.annotations.NonNull;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.Links;
import org.springframework.http.MediaType;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import com.jayway.jsonpath.InvalidPathException;

View File

@@ -17,7 +17,6 @@ package org.springframework.hateoas.client;
import java.util.Optional;
import org.springframework.hateoas.MediaTypes;
import org.springframework.http.MediaType;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.util.Assert;

View File

@@ -17,9 +17,9 @@ package org.springframework.hateoas.client;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.Link;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.jayway.jsonpath.JsonPath;

View File

@@ -27,18 +27,17 @@ import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.UriTemplate;
import org.springframework.hateoas.client.Rels.Rel;
import org.springframework.hateoas.mediatype.hal.HalLinkDiscoverer;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.util.Assert;
import org.springframework.web.client.RestOperations;
@@ -109,9 +108,8 @@ public class Traverson {
this.mediaTypes = mediaTypes;
this.baseUri = baseUri;
setLinkDiscoverers(DEFAULTS.getLinkDiscoverers(mediaTypes));
setRestOperations(createDefaultTemplate(this.mediaTypes));
this.discoverers = defaultLinkDiscoverers(DEFAULTS.getLinkDiscoverers(mediaTypes));
this.operations = createDefaultTemplate(this.mediaTypes);
}
/**
@@ -141,27 +139,21 @@ public class Traverson {
*/
public Traverson setRestOperations(@Nullable RestOperations operations) {
this.operations = operations == null //
? createDefaultTemplate(this.mediaTypes) //
: operations;
this.operations = defaultRestOperations(operations);
return this;
}
/**
* Sets the {@link LinkDiscoverers} to use. By default a single {@link HalLinkDiscoverer} is registered. If
* {@literal null} is provided the default is reapplied.
* {@literal null} is provided the default is re-applied.
*
* @param discoverer can be {@literal null}.
* @return
*/
public Traverson setLinkDiscoverers(@Nullable List<? extends LinkDiscoverer> discoverer) {
List<? extends LinkDiscoverer> defaultedDiscoverers = discoverer == null //
? DEFAULTS.getLinkDiscoverers(mediaTypes) //
: discoverer;
this.discoverers = new LinkDiscoverers(PluginRegistry.of(defaultedDiscoverers));
this.discoverers = defaultLinkDiscoverers(discoverer);
return this;
}
@@ -187,6 +179,17 @@ public class Traverson {
return new TraversalBuilder().follow(hop);
}
private RestOperations defaultRestOperations(@Nullable RestOperations operations) {
return operations == null ? createDefaultTemplate(this.mediaTypes) : operations;
}
private LinkDiscoverers defaultLinkDiscoverers(@Nullable List<? extends LinkDiscoverer> discoverer) {
var defaultedDiscoverers = discoverer == null ? DEFAULTS.getLinkDiscoverers(mediaTypes) : discoverer;
return new LinkDiscoverers(PluginRegistry.of(defaultedDiscoverers));
}
private HttpEntity<?> prepareRequest(HttpHeaders headers) {
HttpHeaders toSend = new HttpHeaders();

View File

@@ -1,5 +1,5 @@
/**
* Client side support.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.hateoas.client;

View File

@@ -24,6 +24,7 @@ import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
@@ -45,7 +46,6 @@ import org.springframework.hateoas.server.core.DefaultLinkRelationProvider;
import org.springframework.hateoas.server.core.DelegatingLinkRelationProvider;
import org.springframework.hateoas.server.core.EvoInflectorLinkRelationProvider;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.plugin.core.OrderAwarePluginRegistry;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.plugin.core.config.EnablePluginRegistries;

View File

@@ -22,6 +22,7 @@ import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
@@ -46,8 +47,8 @@ class HypermediaConfigurationImportSelector implements ImportSelector, ResourceL
public static final String SPRING_TEST = "org.springframework.test.web.reactive.server.WebTestClient";
private ResourceLoader resourceLoader;
private ConfigurableBeanFactory beanFactory;
private @Nullable ResourceLoader resourceLoader;
private @Nullable ConfigurableBeanFactory beanFactory;
/*
* (non-Javadoc)
@@ -74,6 +75,10 @@ class HypermediaConfigurationImportSelector implements ImportSelector, ResourceL
@Override
public String[] selectImports(AnnotationMetadata metadata) {
if (beanFactory == null || resourceLoader == null) {
return new String[0];
}
Map<String, Object> attributes = metadata.getAnnotationAttributes(EnableHypermediaSupport.class.getName());
List<MediaType> types = attributes == null //

View File

@@ -18,9 +18,9 @@ package org.springframework.hateoas.config;
import java.util.List;
import java.util.Optional;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.Module;

View File

@@ -18,8 +18,8 @@ package org.springframework.hateoas.config;
import java.util.Comparator;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -15,12 +15,8 @@
*/
package org.springframework.hateoas.config;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.web.reactive.function.client.WebClient;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Assembles {@link Jackson2JsonEncoder}s and {@link Jackson2JsonDecoder}s needed to wire a {@link WebClient} with
* hypermedia support.

View File

@@ -18,11 +18,11 @@ package org.springframework.hateoas.config;
import java.util.List;
import java.util.function.Consumer;
import org.jspecify.annotations.Nullable;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.codec.ClientCodecConfigurer;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.lang.Nullable;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.reactive.server.WebTestClientConfigurer;
import org.springframework.util.Assert;

View File

@@ -15,13 +15,13 @@
*/
package org.springframework.hateoas.config;
import org.jspecify.annotations.NonNull;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.lang.NonNull;
import org.springframework.web.client.RestTemplate;
/**

View File

@@ -17,6 +17,7 @@ package org.springframework.hateoas.config;
import java.util.List;
import org.jspecify.annotations.NonNull;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.ObjectProvider;
@@ -24,7 +25,6 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.lang.NonNull;
import org.springframework.web.reactive.function.client.WebClient;
import com.fasterxml.jackson.databind.ObjectMapper;

View File

@@ -18,7 +18,6 @@ package org.springframework.hateoas.config;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.hateoas.server.EntityLinks;
import org.springframework.hateoas.server.core.ControllerEntityLinksFactoryBean;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilderFactory;
import org.springframework.stereotype.Controller;

View File

@@ -22,6 +22,8 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.BeanPostProcessor;
@@ -35,7 +37,6 @@ import org.springframework.hateoas.server.mvc.RepresentationModelProcessorInvoke
import org.springframework.hateoas.server.mvc.UriComponentsContributor;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilderFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.NonNull;
import org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@@ -162,8 +163,8 @@ class WebMvcHateoasConfiguration {
* @see org.springframework.web.servlet.HandlerInterceptor#afterCompletion(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) {
DummyInvocationUtils.resetCache();
}

View File

@@ -48,7 +48,7 @@ class WebStackImportSelector implements ImportSelector {
WebStack[] stacks = (WebStack[]) attributes.get("stacks");
if (stacks.length == 0) {
if (stacks == null || stacks.length == 0) {
throw new IllegalStateException(String.format(WEB_STACK_MISSING, metadata.getClassName()));
}

View File

@@ -19,9 +19,9 @@ import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.http.MediaType;
import org.springframework.http.codec.json.Jackson2CodecSupport;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.databind.ObjectMapper;

View File

@@ -1,5 +1,5 @@
/**
* Spring container configuration support.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.hateoas.config;

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.hateoas.mediatype;
import org.springframework.hateoas.Affordance;
import org.springframework.hateoas.Link;
/**

View File

@@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.hateoas.Affordance;
@@ -32,7 +33,6 @@ import org.springframework.hateoas.Link;
import org.springframework.hateoas.QueryParameter;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -17,14 +17,13 @@ package org.springframework.hateoas.mediatype;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.core.ResolvableType;
import org.springframework.hateoas.Affordance;
import org.springframework.hateoas.AffordanceModel.PayloadMetadata;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.QueryParameter;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
/**
* An affordance in creation. API to build up affordances manually to clearly distinguish between building the

View File

@@ -18,8 +18,8 @@ package org.springframework.hateoas.mediatype;
import java.util.HashMap;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.databind.DeserializationConfig;

View File

@@ -17,8 +17,6 @@ package org.springframework.hateoas.mediatype;
import java.util.List;
import org.springframework.hateoas.Affordance;
import org.springframework.hateoas.AffordanceModel;
import org.springframework.hateoas.AffordanceModel.InputPayloadMetadata;
import org.springframework.hateoas.AffordanceModel.PayloadMetadata;
import org.springframework.hateoas.Link;

View File

@@ -15,8 +15,8 @@
*/
package org.springframework.hateoas.mediatype;
import org.jspecify.annotations.Nullable;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.lang.Nullable;
/**
* {@link MessageResolver} to always resort to the {@link MessageSourceResolvable}'s default message.

View File

@@ -15,8 +15,7 @@
*/
package org.springframework.hateoas.mediatype;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* SPI interface for components that can derive an input type from a {@link ResolvableType}. Primary usage to enable to

View File

@@ -18,6 +18,7 @@ package org.springframework.hateoas.mediatype;
import java.util.function.Supplier;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.util.Assert;
@@ -33,7 +34,7 @@ public class MediaTypeConfigurationFactory<T, S extends MediaTypeConfigurationCu
private final Supplier<T> supplier;
private final Supplier<Stream<S>> customizers;
private T resolved;
private @Nullable T resolved;
/**
* Creates a new {@link MediaTypeConfigurationFactory} for the given supplier of the original instance and all

View File

@@ -15,10 +15,9 @@
*/
package org.springframework.hateoas.mediatype;
import org.jspecify.annotations.Nullable;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.lang.Nullable;
/**
* A simplified variant of {@link MessageSourceAccessor} to allow more direct replacement with a no-op implementation in

View File

@@ -15,10 +15,10 @@
*/
package org.springframework.hateoas.mediatype;
import org.jspecify.annotations.Nullable;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

View File

@@ -36,6 +36,7 @@ import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.reactivestreams.Publisher;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
@@ -51,7 +52,6 @@ import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.InputType;
import org.springframework.http.HttpEntity;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ConcurrentReferenceHashMap;
@@ -703,14 +703,14 @@ public class PropertyUtils {
.map(BigDecimal::new);
}
private String cacheAndReturn(String value) {
private @Nullable String cacheAndReturn(@Nullable String value) {
this.inputType = Optional.ofNullable(value);
return value;
}
private String lookupFromTypeMap() {
private @Nullable String lookupFromTypeMap() {
return TYPE_MAP.entrySet().stream() //
.flatMap(it -> {

View File

@@ -24,11 +24,11 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jspecify.annotations.NonNull;
import org.springframework.hateoas.AffordanceModel.InputPayloadMetadata;
import org.springframework.hateoas.AffordanceModel.Named;
import org.springframework.hateoas.AffordanceModel.PropertyMetadata;
import org.springframework.http.MediaType;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
/**

View File

@@ -18,6 +18,9 @@ package org.springframework.hateoas.mediatype.alps;
import java.util.List;
import java.util.Objects;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.NullUnmarked;
import org.springframework.hateoas.mediatype.alps.Descriptor.DescriptorBuilder;
import org.springframework.hateoas.mediatype.alps.Doc.DocBuilder;
import org.springframework.hateoas.mediatype.alps.Ext.ExtBuilder;
@@ -29,7 +32,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
/**
* An ALPS document.
*
*
* @author Oliver Gierke
* @author Greg Turnquist
* @since 0.15
@@ -38,6 +41,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
*/
@JsonPropertyOrder({ "version", "doc", "descriptor" })
@JsonInclude(JsonInclude.Include.NON_NULL)
@NullUnmarked
public final class Alps {
private final String version;
@@ -58,13 +62,13 @@ public final class Alps {
*
* @return
*/
public static AlpsBuilder alps() {
public static @NullMarked AlpsBuilder alps() {
return new AlpsBuilder();
}
/**
* Returns a new {@link DescriptorBuilder}.
*
*
* @return
*/
public static DescriptorBuilder descriptor() {
@@ -73,7 +77,7 @@ public final class Alps {
/**
* Returns a new {@link DocBuilder}.
*
*
* @return
*/
public static DocBuilder doc() {
@@ -82,7 +86,7 @@ public final class Alps {
/**
* Returns a new {@link ExtBuilder}.
*
*
* @return
*/
public static ExtBuilder ext() {
@@ -104,13 +108,17 @@ public final class Alps {
@Override
public boolean equals(Object o) {
if (this == o)
if (this == o) {
return true;
if (o == null || getClass() != o.getClass())
}
if (!(o instanceof Alps that)) {
return false;
Alps alps = (Alps) o;
return Objects.equals(this.version, alps.version) && Objects.equals(this.doc, alps.doc)
&& Objects.equals(this.descriptor, alps.descriptor);
}
return Objects.equals(this.version, that.version)
&& Objects.equals(this.doc, that.doc)
&& Objects.equals(this.descriptor, that.descriptor);
}
@Override
@@ -118,6 +126,7 @@ public final class Alps {
return Objects.hash(this.version, this.doc, this.descriptor);
}
@Override
public String toString() {
return "Alps(version=" + this.version + ", doc=" + this.doc + ", descriptor=" + this.descriptor + ")";
}
@@ -130,28 +139,29 @@ public final class Alps {
AlpsBuilder() {}
public Alps.AlpsBuilder version(String version) {
public Alps.AlpsBuilder version(@NonNull String version) {
this.version = version;
return this;
}
public Alps.AlpsBuilder doc(Doc doc) {
public Alps.AlpsBuilder doc(@NonNull Doc doc) {
this.doc = doc;
return this;
}
public Alps.AlpsBuilder descriptor(List<Descriptor> descriptor) {
public Alps.AlpsBuilder descriptor(@NonNull List<Descriptor> descriptor) {
this.descriptor = descriptor;
return this;
}
public Alps build() {
public @NonNull Alps build() {
return new Alps(this.version, this.doc, this.descriptor);
}
@Override
public String toString() {
return "Alps.AlpsBuilder(version=" + this.version + ", doc=" + this.doc + ", descriptor=" + this.descriptor + ")";
}

View File

@@ -17,7 +17,6 @@ package org.springframework.hateoas.mediatype.alps;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.client.JsonPathLinkDiscoverer;
import org.springframework.hateoas.client.LinkDiscoverer;
/**
* {@link LinkDiscoverer} implementation to find ALPS-based links.

View File

@@ -18,6 +18,10 @@ package org.springframework.hateoas.mediatype.alps;
import java.util.List;
import java.util.Objects;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -25,7 +29,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
/**
* A value object for an ALPS descriptor.
*
*
* @author Oliver Gierke
* @author Greg Turnquist
* @since 0.15
@@ -33,6 +37,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
*/
@JsonPropertyOrder({ "id", "href", "name", "type", "doc", "descriptor", "ext" })
@JsonInclude(JsonInclude.Include.NON_NULL)
@NullUnmarked
public final class Descriptor {
private final String id;
@@ -60,49 +65,51 @@ public final class Descriptor {
this.descriptor = descriptor;
}
public static DescriptorBuilder builder() {
public static @NonNull DescriptorBuilder builder() {
return new DescriptorBuilder();
}
public String getId() {
public @Nullable String getId() {
return this.id;
}
public String getHref() {
public @Nullable String getHref() {
return this.href;
}
public String getName() {
public @Nullable String getName() {
return this.name;
}
public Doc getDoc() {
public @Nullable Doc getDoc() {
return this.doc;
}
public Type getType() {
public @Nullable Type getType() {
return this.type;
}
public Ext getExt() {
public @Nullable Ext getExt() {
return this.ext;
}
public String getRt() {
public @Nullable String getRt() {
return this.rt;
}
public List<Descriptor> getDescriptor() {
public @Nullable List<Descriptor> getDescriptor() {
return this.descriptor;
}
@Override
public boolean equals(Object o) {
if (this == o)
if (this == o) {
return true;
if (o == null || getClass() != o.getClass())
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Descriptor that = (Descriptor) o;
return Objects.equals(this.id, that.id) && Objects.equals(this.href, that.href)
&& Objects.equals(this.name, that.name) && Objects.equals(this.doc, that.doc) && this.type == that.type
@@ -115,6 +122,7 @@ public final class Descriptor {
return Objects.hash(this.id, this.href, this.name, this.doc, this.type, this.ext, this.rt, this.descriptor);
}
@Override
public String toString() {
return "Descriptor(id=" + this.id + ", href=" + this.href + ", name=" + this.name + ", doc=" + this.doc + ", type="
@@ -134,49 +142,49 @@ public final class Descriptor {
DescriptorBuilder() {}
public Descriptor.DescriptorBuilder id(String id) {
public Descriptor.DescriptorBuilder id(@Nullable String id) {
this.id = id;
return this;
}
public Descriptor.DescriptorBuilder href(String href) {
public Descriptor.DescriptorBuilder href(@Nullable String href) {
this.href = href;
return this;
}
public Descriptor.DescriptorBuilder name(String name) {
public Descriptor.DescriptorBuilder name(@Nullable String name) {
this.name = name;
return this;
}
public Descriptor.DescriptorBuilder doc(Doc doc) {
public Descriptor.DescriptorBuilder doc(@Nullable Doc doc) {
this.doc = doc;
return this;
}
public Descriptor.DescriptorBuilder type(Type type) {
public Descriptor.DescriptorBuilder type(@Nullable Type type) {
this.type = type;
return this;
}
public Descriptor.DescriptorBuilder ext(Ext ext) {
public Descriptor.DescriptorBuilder ext(@Nullable Ext ext) {
this.ext = ext;
return this;
}
public Descriptor.DescriptorBuilder rt(String rt) {
public Descriptor.DescriptorBuilder rt(@Nullable String rt) {
this.rt = rt;
return this;
}
public Descriptor.DescriptorBuilder descriptor(List<Descriptor> descriptor) {
public Descriptor.DescriptorBuilder descriptor(@Nullable List<Descriptor> descriptor) {
this.descriptor = descriptor;
return this;
@@ -186,6 +194,7 @@ public final class Descriptor {
return new Descriptor(this.id, this.href, this.name, this.doc, this.type, this.ext, this.rt, this.descriptor);
}
@Override
public String toString() {
return "Descriptor.DescriptorBuilder(id=" + this.id + ", href=" + this.href + ", name=" + this.name + ", doc="

View File

@@ -17,6 +17,8 @@ package org.springframework.hateoas.mediatype.alps;
import java.util.Objects;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.NullUnmarked;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonCreator;
@@ -26,7 +28,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
/**
* A value object for an ALPS doc element.
*
*
* @author Oliver Gierke
* @author Greg Turnquist
* @since 0.15
@@ -34,6 +36,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
*/
@JsonPropertyOrder({ "format", "href", "value" })
@JsonInclude(JsonInclude.Include.NON_NULL)
@NullUnmarked
public final class Doc {
private final String href;
@@ -42,11 +45,11 @@ public final class Doc {
/**
* Creates a new {@link Doc} instance with the given value and {@link Format}.
*
*
* @param value must not be {@literal null} or empty.
* @param format must not be {@literal null}.
*/
public Doc(String value, Format format) {
public Doc(@NonNull String value, @NonNull Format format) {
Assert.hasText(value, "Value must not be null or empty!");
Assert.notNull(format, "Format must not be null!");
@@ -82,14 +85,17 @@ public final class Doc {
}
@Override
public boolean equals(Object o) {
public boolean equals(Object obj) {
if (this == o)
if (this == obj) {
return true;
if (o == null || getClass() != o.getClass())
}
if (!(obj instanceof Doc that)) {
return false;
Doc doc = (Doc) o;
return Objects.equals(this.href, doc.href) && Objects.equals(this.value, doc.value) && this.format == doc.format;
}
return Objects.equals(this.href, that.href) && Objects.equals(this.value, that.value) && this.format == that.format;
}
@Override
@@ -97,6 +103,7 @@ public final class Doc {
return Objects.hash(this.href, this.value, this.format);
}
@Override
public String toString() {
return "Doc(href=" + this.href + ", value=" + this.value + ", format=" + this.format + ")";
}
@@ -109,19 +116,19 @@ public final class Doc {
DocBuilder() {}
public Doc.DocBuilder href(String href) {
public Doc.DocBuilder href(@NonNull String href) {
this.href = href;
return this;
}
public Doc.DocBuilder value(String value) {
public Doc.DocBuilder value(@NonNull String value) {
this.value = value;
return this;
}
public Doc.DocBuilder format(Format format) {
public Doc.DocBuilder format(@NonNull Format format) {
this.format = format;
return this;
@@ -131,6 +138,7 @@ public final class Doc {
return new Doc(this.href, this.value, this.format);
}
@Override
public String toString() {
return "Doc.DocBuilder(href=" + this.href + ", value=" + this.value + ", format=" + this.format + ")";
}

View File

@@ -17,19 +17,23 @@ package org.springframework.hateoas.mediatype.alps;
import java.util.Objects;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.NullUnmarked;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
/**
* A value object for an ALPS ext element.
*
*
* @author Oliver Gierke
* @author Greg Turnquist
* @since 0.15
* @see http://alps.io/spec/#prop-ext
*/
@JsonPropertyOrder({ "id", "href", "value" })
@NullUnmarked
public final class Ext {
private final String id;
@@ -44,7 +48,7 @@ public final class Ext {
this.value = value;
}
public static ExtBuilder builder() {
public static @NonNull ExtBuilder builder() {
return new ExtBuilder();
}
@@ -63,10 +67,12 @@ public final class Ext {
@Override
public boolean equals(Object o) {
if (this == o)
if (this == o) {
return true;
if (o == null || getClass() != o.getClass())
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Ext ext = (Ext) o;
return Objects.equals(this.id, ext.id) && Objects.equals(this.href, ext.href)
&& Objects.equals(this.value, ext.value);
@@ -77,6 +83,7 @@ public final class Ext {
return Objects.hash(this.id, this.href, this.value);
}
@Override
public String toString() {
return "Ext(id=" + this.id + ", href=" + this.href + ", value=" + this.value + ")";
}
@@ -89,19 +96,19 @@ public final class Ext {
ExtBuilder() {}
public Ext.ExtBuilder id(String id) {
public Ext.ExtBuilder id(@NonNull String id) {
this.id = id;
return this;
}
public Ext.ExtBuilder href(String href) {
public Ext.ExtBuilder href(@NonNull String href) {
this.href = href;
return this;
}
public Ext.ExtBuilder value(String value) {
public Ext.ExtBuilder value(@NonNull String value) {
this.value = value;
return this;
@@ -111,6 +118,7 @@ public final class Ext {
return new Ext(this.id, this.href, this.value);
}
@Override
public String toString() {
return "Ext.ExtBuilder(id=" + this.id + ", href=" + this.href + ", value=" + this.value + ")";
}

View File

@@ -3,5 +3,5 @@
*
* @see https://alps.io
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.hateoas.mediatype.alps;

View File

@@ -20,10 +20,10 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.Links.MergeMode;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;

View File

@@ -21,12 +21,10 @@ import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.hateoas.Affordance;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.AffordanceModel;
import org.springframework.hateoas.QueryParameter;
import org.springframework.hateoas.mediatype.ConfiguredAffordance;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
/**
* {@link AffordanceModel} for Collection+JSON.

View File

@@ -17,7 +17,7 @@ package org.springframework.hateoas.mediatype.collectionjson;
import java.util.Objects;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;

View File

@@ -17,7 +17,8 @@ package org.springframework.hateoas.mediatype.collectionjson;
import java.util.Objects;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -25,6 +26,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
/**
* @author Greg Turnquist
*/
@NullUnmarked
final class CollectionJsonError {
private final String title;
@@ -89,10 +91,12 @@ final class CollectionJsonError {
@Override
public boolean equals(Object o) {
if (this == o)
if (this == o) {
return true;
if (o == null || getClass() != o.getClass())
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CollectionJsonError that = (CollectionJsonError) o;
return Objects.equals(this.title, that.title) && Objects.equals(this.code, that.code)
&& Objects.equals(this.message, that.message);
@@ -103,6 +107,7 @@ final class CollectionJsonError {
return Objects.hash(this.title, this.code, this.message);
}
@Override
public String toString() {
return "CollectionJsonError(title=" + this.title + ", code=" + this.code + ", message=" + this.message + ")";
}

View File

@@ -21,11 +21,12 @@ import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.Links.MergeMode;
import org.springframework.hateoas.mediatype.PropertyUtils;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -39,6 +40,7 @@ import com.fasterxml.jackson.databind.JavaType;
*
* @author Greg Turnquist
*/
@NullUnmarked
final class CollectionJsonItem<T> {
private @Nullable final String href;
@@ -86,7 +88,7 @@ final class CollectionJsonItem<T> {
/**
* Create new {@link CollectionJsonItem} by copying attributes and replacing the {@link Links}.
*
*
* @param links
* @return
*/
@@ -97,7 +99,7 @@ final class CollectionJsonItem<T> {
/**
* Create new {@link CollectionJsonItem} by copying attributes and replacing the {@literal links} with a
* {@literal self} link.
*
*
* @return
*/
CollectionJsonItem<T> withOwnSelfLink() {
@@ -210,10 +212,12 @@ final class CollectionJsonItem<T> {
@Override
public boolean equals(Object o) {
if (this == o)
if (this == o) {
return true;
if (o == null || getClass() != o.getClass())
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CollectionJsonItem<?> that = (CollectionJsonItem<?>) o;
return Objects.equals(this.href, that.href) && Objects.equals(this.data, that.data)
&& Objects.equals(this.links, that.links) && Objects.equals(this.rawData, that.rawData);
@@ -224,6 +228,7 @@ final class CollectionJsonItem<T> {
return Objects.hash(this.href, this.data, this.links, this.rawData);
}
@Override
public String toString() {
return "CollectionJsonItem(href=" + this.href + ", data=" + this.data + ", links=" + this.links + ", rawData="

View File

@@ -24,7 +24,6 @@ import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.client.JsonPathLinkDiscoverer;
import org.springframework.hateoas.client.LinkDiscoverer;
import org.springframework.util.Assert;
/**

View File

@@ -17,13 +17,13 @@ package org.springframework.hateoas.mediatype.collectionjson;
import java.util.List;
import org.jspecify.annotations.NonNull;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.hateoas.client.LinkDiscoverer;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.hateoas.config.HypermediaMappingInformation;
import org.springframework.http.MediaType;
import org.springframework.lang.NonNull;
import com.fasterxml.jackson.databind.Module;

View File

@@ -18,7 +18,8 @@ package org.springframework.hateoas.mediatype.collectionjson;
import java.util.List;
import java.util.Objects;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
@@ -28,6 +29,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
/**
* @author Greg Turnquist
*/
@NullUnmarked
final class CollectionJsonQuery {
private @JsonInclude(Include.NON_NULL) final String rel;
@@ -108,10 +110,12 @@ final class CollectionJsonQuery {
@Override
public boolean equals(Object o) {
if (this == o)
if (this == o) {
return true;
if (o == null || getClass() != o.getClass())
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CollectionJsonQuery that = (CollectionJsonQuery) o;
return Objects.equals(this.rel, that.rel) && Objects.equals(this.href, that.href)
&& Objects.equals(this.prompt, that.prompt) && Objects.equals(this.data, that.data);
@@ -122,6 +126,7 @@ final class CollectionJsonQuery {
return Objects.hash(this.rel, this.href, this.prompt, this.data);
}
@Override
public String toString() {
return "CollectionJsonQuery(rel=" + this.rel + ", href=" + this.href + ", prompt=" + this.prompt + ", data="

View File

@@ -18,7 +18,8 @@ package org.springframework.hateoas.mediatype.collectionjson;
import java.util.List;
import java.util.Objects;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -26,6 +27,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
/**
* @author Greg Turnquist
*/
@NullUnmarked
final class CollectionJsonTemplate {
private final List<CollectionJsonData> data;
@@ -48,13 +50,15 @@ final class CollectionJsonTemplate {
}
@Override
public boolean equals(Object o) {
public boolean equals(Object obj) {
if (this == o)
if (this == obj) {
return true;
if (o == null || getClass() != o.getClass())
}
if (obj == null || getClass() != obj.getClass()) {
return false;
CollectionJsonTemplate that = (CollectionJsonTemplate) o;
}
CollectionJsonTemplate that = (CollectionJsonTemplate) obj;
return Objects.equals(this.data, that.data);
}
@@ -63,6 +67,7 @@ final class CollectionJsonTemplate {
return Objects.hash(this.data);
}
@Override
public String toString() {
return "CollectionJsonTemplate(data=" + this.data + ")";
}

View File

@@ -23,7 +23,7 @@ import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.hateoas.Affordance;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.IanaLinkRelations;
@@ -36,7 +36,6 @@ import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.JacksonHelper;
import org.springframework.hateoas.mediatype.PropertyUtils;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.core.JsonGenerator;
@@ -170,7 +169,7 @@ public class Jackson2CollectionJsonModule extends SimpleModule {
private static final long serialVersionUID = 6127711241993352699L;
private final BeanProperty property;
private final @Nullable BeanProperty property;
CollectionJsonResourceSupportSerializer() {
this(null);
@@ -272,7 +271,7 @@ public class Jackson2CollectionJsonModule extends SimpleModule {
private static final long serialVersionUID = 2212535956767860364L;
private final BeanProperty property;
private final @Nullable BeanProperty property;
CollectionJsonResourceSerializer() {
this(null);
@@ -453,7 +452,7 @@ public class Jackson2CollectionJsonModule extends SimpleModule {
private static final long serialVersionUID = -6703190072925382402L;
private final BeanProperty property;
private final @Nullable BeanProperty property;
CollectionJsonPagedResourcesSerializer() {
this(null);

View File

@@ -1,5 +1,5 @@
/**
* Value objects to build Collection+JSON representations.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.hateoas.mediatype.collectionjson;

View File

@@ -20,12 +20,12 @@ import java.util.Collections;
import java.util.Map;
import java.util.stream.Collectors;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.UriTemplate;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
@@ -41,7 +41,7 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
public class DefaultCurieProvider implements CurieProvider {
private final Map<String, UriTemplate> curies;
private final String defaultCurie;
private final @Nullable String defaultCurie;
/**
* Creates a new {@link DefaultCurieProvider} for the given name and {@link UriTemplate}. The curie will be used to

View File

@@ -23,12 +23,11 @@ import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.springframework.hateoas.EntityModel;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.server.LinkRelationProvider;
import org.springframework.hateoas.server.core.EmbeddedWrapper;
import org.springframework.hateoas.server.core.EmbeddedWrappers;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -88,6 +87,10 @@ class HalEmbeddedBuilder {
*/
void add(@Nullable Object source) {
if (source == null) {
return;
}
EmbeddedWrapper wrapper = wrappers.wrap(source);
if (wrapper == null) {
@@ -160,7 +163,7 @@ class HalEmbeddedBuilder {
/**
* Create new {@link HalEmbeddedBuilder} by copying attributes and replacing the {@literal relationTransformer}.
*
*
* @param relationTransformer
* @return
*/

View File

@@ -22,6 +22,7 @@ import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.client.JsonPathLinkDiscoverer;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
/**
* {@link org.springframework.hateoas.client.LinkDiscoverer} implementation based on HAL link structure.
@@ -54,9 +55,12 @@ public class HalLinkDiscoverer extends JsonPathLinkDiscoverer {
return super.extractLink(element, rel);
}
Map<String, String> json = (Map<String, String>) element;
var json = (Map<String, String>) element;
var href = json.get("href");
return Link.of(json.get("href"), rel) //
Assert.state(href != null, "No href found in link data!");
return Link.of(href, rel) //
.withHreflang(json.get("hreflang")) //
.withMedia(json.get("media")) //
.withTitle(json.get("title")) //

View File

@@ -19,11 +19,12 @@ import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Stream;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.IanaUriSchemes;
import org.springframework.hateoas.LinkRelation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonCreator;
@@ -184,8 +185,7 @@ public class HalLinkRelation implements LinkRelation, MessageSourceResolvable {
* @see org.springframework.context.MessageSourceResolvable#getCodes()
*/
@Override
@org.springframework.lang.NonNull
public String[] getCodes() {
public String @NonNull[] getCodes() {
return Stream.of(value(), localPart) //
.map(it -> String.format(RELATION_MESSAGE_TEMPLATE, it)) //
@@ -197,7 +197,7 @@ public class HalLinkRelation implements LinkRelation, MessageSourceResolvable {
* @see org.springframework.context.MessageSourceResolvable#getDefaultMessage()
*/
@Override
@org.springframework.lang.NonNull
@NonNull
public String getDefaultMessage() {
return "";
}

View File

@@ -21,15 +21,14 @@ import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.core.EmbeddedWrappers;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
@@ -47,7 +46,7 @@ public class HalModelBuilder {
private final EmbeddedWrappers wrappers;
private Object model;
private @Nullable Object model;
private Links links = Links.NONE;
private final List<Object> embeddeds = new ArrayList<>();
@@ -358,7 +357,10 @@ public class HalModelBuilder {
*/
@SuppressWarnings("unchecked")
public <T extends RepresentationModel<T>> RepresentationModel<T> build() {
return (T) new HalRepresentationModel<>(model, embeddeds, links);
return model == null
? (T) new EmbedsOnlyHalRepresentationModel(embeddeds, links)
: (T) new HalRepresentationModel<>(model, embeddeds, links);
}
/**
@@ -377,19 +379,28 @@ public class HalModelBuilder {
return this;
}
private static class EmbedsOnlyHalRepresentationModel extends CollectionModel<Object> {
public EmbedsOnlyHalRepresentationModel(List<Object> embeddeds, Links links) {
super(embeddeds);
add(links);
}
}
private static class HalRepresentationModel<T> extends EntityModel<T> {
private final @Nullable T entity;
private final T entity;
private final List<Object> embeddeds;
public HalRepresentationModel(@Nullable T entity, List<Object> embeddeds, Links links) {
public HalRepresentationModel(T entity, List<Object> embeddeds, Links links) {
this(entity, embeddeds);
add(links);
}
private HalRepresentationModel(@Nullable T entity, List<Object> embeddeds) {
private HalRepresentationModel(T entity, List<Object> embeddeds) {
Assert.notNull(embeddeds, "Embedds must not be null!");
@@ -401,7 +412,6 @@ public class HalModelBuilder {
* (non-Javadoc)
* @see org.springframework.hateoas.EntityModel#getContent()
*/
@Nullable
@Override
public T getContent() {
return entity;

View File

@@ -26,10 +26,10 @@ import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.LinkRelation;
import org.springframework.hateoas.Links;
@@ -39,7 +39,6 @@ import org.springframework.hateoas.mediatype.MessageResolver;
import org.springframework.hateoas.mediatype.MessageSourceResolvableSerializer;
import org.springframework.hateoas.mediatype.hal.HalConfiguration.RenderSingleLinks;
import org.springframework.hateoas.server.LinkRelationProvider;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
@@ -293,7 +292,7 @@ public class Jackson2HalModule extends SimpleModule {
private final EmbeddedMapper embeddedMapper;
private final HalConfiguration configuration;
private final BeanProperty property;
private final @Nullable BeanProperty property;
public HalResourcesSerializer(EmbeddedMapper embeddedMapper, HalConfiguration configuration) {
this(embeddedMapper, configuration, null);
@@ -617,7 +616,7 @@ public class Jackson2HalModule extends SimpleModule {
private static final long serialVersionUID = 4755806754621032622L;
private JavaType contentType;
private @Nullable JavaType contentType;
public HalResourcesDeserializer() {
this(TypeFactory.defaultInstance().constructCollectionLikeType(List.class, Object.class), null);
@@ -905,7 +904,7 @@ public class Jackson2HalModule extends SimpleModule {
static class HalLink {
private final Link link;
private final String title;
private final @Nullable String title;
public HalLink(Link link, @Nullable String title) {

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.hateoas.mediatype.hal;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.Links;
import org.springframework.hateoas.RepresentationModel;

View File

@@ -17,7 +17,6 @@ package org.springframework.hateoas.mediatype.hal.forms;
import org.springframework.hateoas.AffordanceModel;
import org.springframework.hateoas.mediatype.ConfiguredAffordance;
import org.springframework.http.MediaType;
/**
* {@link AffordanceModel} for a HAL-FORMS {@link MediaType}.

View File

@@ -24,13 +24,13 @@ import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.springframework.core.ResolvableType;
import org.springframework.hateoas.AffordanceModel.PropertyMetadata;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.mediatype.hal.HalConfiguration;
import org.springframework.http.MediaType;
import org.springframework.lang.Contract;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.databind.ObjectMapper;

View File

@@ -19,8 +19,8 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;

View File

@@ -19,13 +19,13 @@ import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.databind.ObjectMapper;

View File

@@ -16,7 +16,6 @@
package org.springframework.hateoas.mediatype.hal.forms;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.client.JsonPathLinkDiscoverer;
import org.springframework.hateoas.mediatype.hal.HalLinkDiscoverer;
/**

View File

@@ -18,8 +18,8 @@ package org.springframework.hateoas.mediatype.hal.forms;
import java.util.Arrays;
import java.util.Collection;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.Link;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

View File

@@ -19,9 +19,9 @@ import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.AffordanceModel.PayloadMetadata;
import org.springframework.hateoas.AffordanceModel.PropertyMetadata;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -18,8 +18,9 @@ package org.springframework.hateoas.mediatype.hal.forms;
import java.util.Objects;
import java.util.Optional;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.AffordanceModel.Named;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -35,6 +36,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* @see https://mamund.site44.com/misc/hal-forms/
*/
@JsonInclude(Include.NON_DEFAULT)
@NullUnmarked
final class HalFormsProperty implements Named {
private final String name, prompt, regex, placeholder;

View File

@@ -24,13 +24,13 @@ import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.hateoas.AffordanceModel.InputPayloadMetadata;
import org.springframework.hateoas.AffordanceModel.PropertyMetadata;
import org.springframework.hateoas.mediatype.MessageResolver;
import org.springframework.http.HttpMethod;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -157,13 +157,13 @@ class HalFormsPropertyFactory {
return "";
}
/*
* (non-Javadoc)
* @see org.springframework.context.MessageSourceResolvable#getCodes()
*/
@NonNull
@Override
public String[] getCodes() {
public String @NonNull[] getCodes() {
String globalCode = String.format(template, property.getName());

View File

@@ -21,9 +21,10 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
@@ -43,6 +44,7 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonAutoDetect(getterVisibility = Visibility.NON_PRIVATE)
@JsonIgnoreProperties({ "httpMethod", "contentTypes" })
@JsonPropertyOrder({ "title", "method", "contentType", "properties" })
@NullUnmarked
final class HalFormsTemplate {
static final String DEFAULT_KEY = "default";

View File

@@ -20,6 +20,8 @@ import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.hateoas.AffordanceModel.InputPayloadMetadata;
import org.springframework.hateoas.IanaLinkRelations;
@@ -28,8 +30,6 @@ import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.MessageResolver;
import org.springframework.http.HttpMethod;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -112,13 +112,13 @@ class HalFormsTemplateBuilder {
return new TemplateTitle(affordance, soleTemplate);
}
/*
* (non-Javadoc)
* @see org.springframework.context.MessageSourceResolvable#getCodes()
*/
@NonNull
@Override
public String[] getCodes() {
public String @NonNull[] getCodes() {
Stream<String> seed = Stream.concat(//
Stream.of(affordance.getName()), //

View File

@@ -1,7 +1,5 @@
/**
* HAL-FORMS extension media type.
*/
@NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.hateoas.mediatype.hal.forms;
import org.springframework.lang.NonNullApi;

View File

@@ -3,5 +3,5 @@
*
* @see http://stateless.co/hal_specification.html
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.hateoas.mediatype.hal;

View File

@@ -24,10 +24,9 @@ import java.time.LocalTime;
import java.util.Arrays;
import java.util.Collection;
import org.jspecify.annotations.Nullable;
import org.springframework.core.Constants;
import org.springframework.core.Constants.ConstantException;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonValue;

View File

@@ -15,8 +15,8 @@
*/
package org.springframework.hateoas.mediatype.html;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.mediatype.InputTypeFactory;
import org.springframework.lang.Nullable;
/**
* An {@link InputTypeFactory} based on {@link HtmlInputType}.

View File

@@ -1,5 +1,5 @@
/**
* Support for HTML media type.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.hateoas.mediatype.html;

View File

@@ -1,5 +1,5 @@
/**
* Spring container configuration support.
* General media type support.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.hateoas.mediatype;

View File

@@ -22,8 +22,9 @@ import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
@@ -43,6 +44,7 @@ import com.fasterxml.jackson.annotation.JsonUnwrapped;
* @author Oliver Drotbohm
*/
@JsonInclude(Include.NON_NULL)
@NullUnmarked
public class Problem {
private static Problem EMPTY = new Problem();
@@ -242,10 +244,12 @@ public class Problem {
@Override
public boolean equals(Object o) {
if (this == o)
if (this == o) {
return true;
if (!(o instanceof Problem))
}
if (!(o instanceof Problem)) {
return false;
}
Problem problem = (Problem) o;
return Objects.equals(this.type, problem.type) && Objects.equals(this.title, problem.title)
&& this.status == problem.status && Objects.equals(this.detail, problem.detail)
@@ -257,6 +261,7 @@ public class Problem {
return Objects.hash(this.type, this.title, this.status, this.detail, this.instance);
}
@Override
public String toString() {
return "Problem(type=" + this.type + ", title=" + this.title + ", status=" + this.status + ", detail=" + this.detail
+ ", instance=" + this.instance + ")";
@@ -386,12 +391,15 @@ public class Problem {
@Override
public boolean equals(Object o) {
if (this == o)
if (this == o) {
return true;
if (!(o instanceof ExtendedProblem))
}
if (!(o instanceof ExtendedProblem)) {
return false;
if (!super.equals(o))
}
if (!super.equals(o)) {
return false;
}
ExtendedProblem<?> that = (ExtendedProblem<?>) o;
return Objects.equals(this.extendedProperties, that.extendedProperties);
}
@@ -401,6 +409,7 @@ public class Problem {
return Objects.hash(super.hashCode(), extendedProperties);
}
@Override
public String toString() {
return "Problem.ExtendedProblem(extendedProperties=" + this.extendedProperties + ")";
}

View File

@@ -1,5 +1,5 @@
/**
* Value objects to build Problem representations.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.hateoas.mediatype.problem;

View File

@@ -27,6 +27,7 @@ import java.util.Optional;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
@@ -37,7 +38,6 @@ import org.springframework.hateoas.PagedModel.PageMetadata;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.mediatype.JacksonHelper;
import org.springframework.hateoas.mediatype.PropertyUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.core.JsonGenerator;
@@ -129,7 +129,7 @@ public class Jackson2UberModule extends SimpleModule {
implements ContextualSerializer {
private static final long serialVersionUID = -572866287910993300L;
private final BeanProperty property;
private final @Nullable BeanProperty property;
UberRepresentationModelSerializer(@Nullable BeanProperty property) {
@@ -220,7 +220,7 @@ public class Jackson2UberModule extends SimpleModule {
private static final long serialVersionUID = -5538560800604582741L;
private final BeanProperty property;
private final @Nullable BeanProperty property;
UberEntityModelSerializer(@Nullable BeanProperty property) {
@@ -310,7 +310,7 @@ public class Jackson2UberModule extends SimpleModule {
private static final long serialVersionUID = 3422019794262694127L;
private BeanProperty property;
private @Nullable BeanProperty property;
UberCollectionModelSerializer(@Nullable BeanProperty property) {
@@ -400,7 +400,7 @@ public class Jackson2UberModule extends SimpleModule {
private static final long serialVersionUID = -7892297813593085984L;
private BeanProperty property;
private @Nullable BeanProperty property;
UberPagedModelSerializer(@Nullable BeanProperty property) {

View File

@@ -18,8 +18,9 @@ package org.springframework.hateoas.mediatype.uber;
import java.util.List;
import java.util.Objects;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
import org.springframework.hateoas.Links;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -34,6 +35,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* @since 1.0
*/
@JsonInclude(Include.NON_NULL)
@NullUnmarked
final class Uber {
private final String version;
@@ -118,10 +120,12 @@ final class Uber {
@Override
public boolean equals(Object o) {
if (this == o)
if (this == o) {
return true;
if (!(o instanceof Uber))
}
if (!(o instanceof Uber)) {
return false;
}
Uber uber = (Uber) o;
return Objects.equals(this.version, uber.version) && Objects.equals(this.data, uber.data)
&& Objects.equals(this.error, uber.error);

Some files were not shown because too many files have changed in this diff Show More