diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilder.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilder.java index c27d9f880..69baedf0d 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilder.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilder.java @@ -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 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() { diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/AbstractAuditable.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/AbstractAuditable.java index 8f93ab0fc..0b394d047 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/AbstractAuditable.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/AbstractAuditable.java @@ -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 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 extends AbstractPersistable implements Auditable { -// @Nullable @ManyToOne // private U createdBy; -// @Nullable private Instant createdDate; -// @Nullable @ManyToOne // private U lastModifiedBy; -// @Nullable - private Instant lastModifiedDate; + private Instant lastModifiedDate; @Override public Optional getCreatedBy() { diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/AbstractPersistable.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/AbstractPersistable.java index 0d645c151..19153d70c 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/AbstractPersistable.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/AbstractPersistable.java @@ -39,16 +39,13 @@ import org.springframework.data.util.ProxyUtils; * @param 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 implements Persistable { @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; } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/DeleteSpecification.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/DeleteSpecification.java index bd6911df9..32278c7ba 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/DeleteSpecification.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/DeleteSpecification.java @@ -151,6 +151,7 @@ public interface DeleteSpecification extends Serializable { * @param spec can be {@literal null}. * @return guaranteed to be not {@literal null}. */ + @Contract("_ -> new") static DeleteSpecification not(DeleteSpecification spec) { Assert.notNull(spec, "Specification must not be null"); diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/JpaSort.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/JpaSort.java index 4fc0f813a..2f55c0bf0 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/JpaSort.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/domain/JpaSort.java @@ -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 , U> Path 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

, U> Path 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"); diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java index 851c40a55..2d75b3970 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java @@ -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 applyHints(T query, JpaQueryMethod method) { List hints = method.getHints(); diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EscapeCharacter.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EscapeCharacter.java index 448b80bad..d6ef5c321 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EscapeCharacter.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EscapeCharacter.java @@ -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 // diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java index afc0e0b98..25f50b9f2 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java @@ -165,7 +165,6 @@ public class JpaQueryMethod extends QueryMethod { } @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) public JpaEntityMetadata getEntityInformation() { return this.entityMetadata.get(); } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryBuilder.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryBuilder.java index a3e8d70ed..45c804e12 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryBuilder.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryBuilder.java @@ -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 paths) { return instantiate(resultType.getName(), paths); } @@ -436,6 +442,7 @@ public final class JpqlQueryBuilder { * @param paths * @return */ + @CheckReturnValue Select instantiate(String resultType, Collection paths); /** @@ -444,6 +451,7 @@ public final class JpqlQueryBuilder { * @param paths * @return */ + @CheckReturnValue Select select(Collection 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;