Add contract annotations to public API.

See #3745
Original pull request: #3781
This commit is contained in:
Christoph Strobl
2025-02-19 08:56:11 +01:00
committed by Mark Paluch
parent c40c90bc84
commit 59e9f3459c
9 changed files with 42 additions and 15 deletions

View File

@@ -43,6 +43,7 @@ import org.springframework.data.domain.ExampleMatcher.PropertyValueTransformer;
import org.springframework.data.jpa.repository.query.EscapeCharacter;
import org.springframework.data.support.ExampleMatcherAccessor;
import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -242,7 +243,6 @@ public class QueryByExamplePredicateBuilder {
String name;
@Nullable PathNode parent;
List<PathNode> siblings = new ArrayList<>();
@Nullable Object value;
PathNode(String edge, @Nullable PathNode parent, @Nullable Object value) {
@@ -254,9 +254,7 @@ public class QueryByExamplePredicateBuilder {
PathNode add(String attribute, @Nullable Object value) {
PathNode node = new PathNode(attribute, this, value);
siblings.add(node);
return node;
return new PathNode(attribute, this, value);
}
boolean spansCycle() {

View File

@@ -24,6 +24,7 @@ import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Optional;
import org.jspecify.annotations.NullUnmarked;
import org.springframework.data.domain.Auditable;
import org.jspecify.annotations.Nullable;
@@ -38,23 +39,19 @@ import org.jspecify.annotations.Nullable;
* @param <PK> the type of the auditing type's identifier.
*/
@MappedSuperclass
@SuppressWarnings("NullAway")
@SuppressWarnings("NullAway") // querydsl does not work with jspecify -> 'Did not find type @org.jspecify.annotations.Nullable...'
public abstract class AbstractAuditable<U, PK extends Serializable> extends AbstractPersistable<PK>
implements Auditable<U, PK, LocalDateTime> {
// @Nullable
@ManyToOne //
private U createdBy;
// @Nullable
private Instant createdDate;
// @Nullable
@ManyToOne //
private U lastModifiedBy;
// @Nullable
private Instant lastModifiedDate;
private Instant lastModifiedDate;
@Override
public Optional<U> getCreatedBy() {

View File

@@ -39,16 +39,13 @@ import org.springframework.data.util.ProxyUtils;
* @param <PK> the type of the identifier.
*/
@MappedSuperclass
@SuppressWarnings("NullAway") // querydsl does not work with jspecify -> 'Did not find type @org.jspecify.annotations.Nullable...'
public abstract class AbstractPersistable<PK extends Serializable> implements Persistable<PK> {
@Nullable
@Id @GeneratedValue private PK id;
@Override
@SuppressWarnings("NullAway")
// TODO: Querydsl APT does not like @Nullable
// -> errors with cryptic 'Did not find type @org.jspecify.annotations.Nullable PK'
public PK getId() {
return id;
}

View File

@@ -151,6 +151,7 @@ public interface DeleteSpecification<T> extends Serializable {
* @param spec can be {@literal null}.
* @return guaranteed to be not {@literal null}.
*/
@Contract("_ -> new")
static <T> DeleteSpecification<T> not(DeleteSpecification<T> spec) {
Assert.notNull(spec, "Specification must not be null");

View File

@@ -28,6 +28,8 @@ import java.util.List;
import org.springframework.data.domain.Sort;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.CheckReturnValue;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
/**
@@ -104,6 +106,8 @@ public class JpaSort extends Sort {
* @param attributes must not be {@literal null}.
* @return
*/
@Contract("_, _ -> new")
@CheckReturnValue
public JpaSort and(@Nullable Direction direction, Attribute<?, ?>... attributes) {
Assert.notNull(attributes, "Attributes must not be null");
@@ -118,6 +122,8 @@ public class JpaSort extends Sort {
* @param paths must not be {@literal null}.
* @return
*/
@Contract("_, _ -> new")
@CheckReturnValue
public JpaSort and(@Nullable Direction direction, Path<?, ?>... paths) {
Assert.notNull(paths, "Paths must not be null");
@@ -138,6 +144,8 @@ public class JpaSort extends Sort {
* @param properties must not be {@literal null} or empty.
* @return
*/
@Contract("_, _ -> new")
@CheckReturnValue
public JpaSort andUnsafe(@Nullable Direction direction, String... properties) {
Assert.notEmpty(properties, "Properties must not be empty");
@@ -275,6 +283,8 @@ public class JpaSort extends Sort {
* @param attribute must not be {@literal null}.
* @return
*/
@Contract("_ -> new")
@CheckReturnValue
public <A extends Attribute<S, U>, U> Path<S, U> dot(A attribute) {
return new Path<>(add(attribute));
}
@@ -285,6 +295,8 @@ public class JpaSort extends Sort {
* @param attribute must not be {@literal null}.
* @return
*/
@Contract("_ -> new")
@CheckReturnValue
public <P extends PluralAttribute<S, ?, U>, U> Path<S, U> dot(P attribute) {
return new Path<>(add(attribute));
}
@@ -372,6 +384,8 @@ public class JpaSort extends Sort {
* @param properties must not be {@literal null}.
* @return
*/
@Contract("_ -> new")
@CheckReturnValue
public Sort withUnsafe(String... properties) {
Assert.notEmpty(properties, "Properties must not be empty");

View File

@@ -57,6 +57,7 @@ import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.util.Lazy;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -193,6 +194,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
* @return
*/
@SuppressWarnings("NullAway")
@Contract("_, _ -> param1")
protected <T extends Query> T applyHints(T query, JpaQueryMethod method) {
List<QueryHint> hints = method.getHints();

View File

@@ -20,6 +20,7 @@ import java.util.List;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Contract;
/**
* A value type encapsulating an escape character for LIKE queries and the actually usage of it in escaping
@@ -49,6 +50,7 @@ public final class EscapeCharacter {
* @param value may be {@literal null}.
* @return
*/
@Contract("null -> null")
public @Nullable String escape(@Nullable String value) {
return value == null //

View File

@@ -165,7 +165,6 @@ public class JpaQueryMethod extends QueryMethod {
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public JpaEntityMetadata<?> getEntityInformation() {
return this.entityMetadata.get();
}

View File

@@ -33,6 +33,8 @@ import org.springframework.data.domain.Sort;
import org.jspecify.annotations.Nullable;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.util.Predicates;
import org.springframework.lang.CheckReturnValue;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -405,16 +407,19 @@ public final class JpqlQueryBuilder {
/**
* Apply {@code DISTINCT}.
*/
@CheckReturnValue
SelectStep distinct();
/**
* Select the entity.
*/
@CheckReturnValue
Select entity();
/**
* Select the count.
*/
@CheckReturnValue
Select count();
/**
@@ -425,6 +430,7 @@ public final class JpqlQueryBuilder {
* @param paths
* @return
*/
@CheckReturnValue
default Select instantiate(Class<?> resultType, Collection<JpqlQueryBuilder.PathExpression> paths) {
return instantiate(resultType.getName(), paths);
}
@@ -436,6 +442,7 @@ public final class JpqlQueryBuilder {
* @param paths
* @return
*/
@CheckReturnValue
Select instantiate(String resultType, Collection<JpqlQueryBuilder.PathExpression> paths);
/**
@@ -444,6 +451,7 @@ public final class JpqlQueryBuilder {
* @param paths
* @return
*/
@CheckReturnValue
Select select(Collection<JpqlQueryBuilder.PathExpression> paths);
/**
@@ -452,6 +460,7 @@ public final class JpqlQueryBuilder {
* @param path
* @return
*/
@CheckReturnValue
default Select select(JpqlQueryBuilder.PathExpression path) {
return select(List.of(path));
}
@@ -626,6 +635,8 @@ public final class JpqlQueryBuilder {
* @param other
* @return a composed predicate combining this and {@code other} using the OR operator.
*/
@Contract("_ -> new")
@CheckReturnValue
default Predicate or(Predicate other) {
return new OrPredicate(this, other);
}
@@ -636,6 +647,8 @@ public final class JpqlQueryBuilder {
* @param other
* @return a composed predicate combining this and {@code other} using the AND operator.
*/
@Contract("_ -> new")
@CheckReturnValue
default Predicate and(Predicate other) { // don't like the structuring of this and the nest() thing
return new AndPredicate(this, other);
}
@@ -645,6 +658,8 @@ public final class JpqlQueryBuilder {
*
* @return a nested variant of this predicate.
*/
@Contract("-> new")
@CheckReturnValue
default Predicate nest() {
return new NestedPredicate(this);
}
@@ -700,6 +715,7 @@ public final class JpqlQueryBuilder {
* @param join
* @return
*/
@Contract("_ -> this")
public Select join(Join join) {
if (join.source() instanceof Join parent) {
@@ -716,6 +732,7 @@ public final class JpqlQueryBuilder {
* @param orderBy
* @return
*/
@Contract("_ -> this")
public Select orderBy(Expression orderBy) {
this.orderBy.add(orderBy);
return this;