Migrate to JSpecify annotations for nullability constraints.

Closes #3745
Original pull request: #3781
This commit is contained in:
Christoph Strobl
2025-02-17 11:22:46 +01:00
committed by Mark Paluch
parent e90f2fea91
commit c40c90bc84
142 changed files with 674 additions and 504 deletions

View File

@@ -48,14 +48,18 @@ ParserFile(file, parser, namedActions, contextSuperClass) ::= <<
package <file.genPackage>;
<endif>
<namedActions.header>
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.misc.*;
import org.antlr.v4.runtime.tree.*;
import org.jspecify.annotations.NullUnmarked;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;
import jakarta.annotation.Generated;
<parser>
>>
@@ -67,11 +71,15 @@ package <file.genPackage>;
<endif>
<header>
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.jspecify.annotations.NullUnmarked;
import jakarta.annotation.Generated;
/**
* This interface defines a complete listener for a parse tree produced by
* {@link <file.parserName>}.
*/
@NullUnmarked
@Generated("<file.grammarName>Listener")
interface <file.grammarName>Listener extends ParseTreeListener {
<file.listenerNames:{lname |
/**
@@ -103,17 +111,20 @@ BaseListenerFile(file, header, namedActions) ::= <<
package <file.genPackage>;
<endif>
<header>
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.jspecify.annotations.NullUnmarked;
import jakarta.annotation.Generated;
/**
* This class provides an empty implementation of {@link <file.grammarName>Listener},
* which can be extended to create a listener which only needs to handle a subset
* of the available methods.
*/
@SuppressWarnings("CheckReturnValue")
@NullUnmarked
@Generated("<file.grammarName>BaseListener")
@SuppressWarnings({ "CheckReturnValue", "NullAway" })
class <file.grammarName>BaseListener implements <file.grammarName>Listener {
<file.listenerNames:{lname |
/**
@@ -163,6 +174,8 @@ package <file.genPackage>;
<endif>
<header>
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
import org.jspecify.annotations.NullUnmarked;
import jakarta.annotation.Generated;
/**
* This interface defines a complete generic visitor for a parse tree produced
@@ -171,6 +184,8 @@ import org.antlr.v4.runtime.tree.ParseTreeVisitor;
* @param \<T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
@NullUnmarked
@Generated("<file.grammarName>Visitor")
interface <file.grammarName>Visitor\<T> extends ParseTreeVisitor\<T> {
<file.visitorNames:{lname |
/**
@@ -194,6 +209,8 @@ package <file.genPackage>;
<endif>
<header>
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
import org.jspecify.annotations.NullUnmarked;
import jakarta.annotation.Generated;
/**
* This class provides an empty implementation of {@link <file.grammarName>Visitor},
@@ -203,7 +220,9 @@ import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
* @param \<T> The return type of the visit operation. Use {@link Void} for
* operations with no return type.
*/
@SuppressWarnings("CheckReturnValue")
@NullUnmarked
@Generated("<file.grammarName>BaseVisitor")
@SuppressWarnings({ "CheckReturnValue", "NullAway" })
class <file.grammarName>BaseVisitor\<T> extends AbstractParseTreeVisitor\<T> implements <file.grammarName>Visitor\<T> {
<file.visitorNames:{lname |
/**
@@ -225,7 +244,9 @@ Parser(parser, funcs, atn, sempredFuncs, superClass) ::= <<
>>
Parser_(parser, funcs, atn, sempredFuncs, ctor, superClass) ::= <<
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"})
@NullUnmarked
@Generated("<parser.name>")
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "NullAway"})
class <parser.name> extends <superClass; null="Parser"> {
// Customization: Suppress version check
// static { RuntimeMetaData.checkVersion("<file.ANTLRVersion>", RuntimeMetaData.VERSION); }
@@ -895,12 +916,16 @@ import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.misc.*;
import org.jspecify.annotations.NullUnmarked;
import jakarta.annotation.Generated;
<lexer>
>>
Lexer(lexer, atn, actionFuncs, sempredFuncs, superClass) ::= <<
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue"})
@NullUnmarked
@Generated("<lexer.name>")
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "NullAway"})
class <lexer.name> extends <superClass; null="Lexer"> {
// Customization: Suppress version check
// static { RuntimeMetaData.checkVersion("<lexerFile.ANTLRVersion>", RuntimeMetaData.VERSION); }

View File

@@ -1,5 +1,5 @@
/**
* Classes for Envers Repositories configuration support.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.envers.repository.config;

View File

@@ -21,6 +21,7 @@ import java.util.Optional;
import org.hibernate.envers.DefaultRevisionEntity;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
@@ -39,7 +40,7 @@ import org.springframework.data.repository.history.support.RevisionEntityInforma
public class EnversRevisionRepositoryFactoryBean<T extends RevisionRepository<S, ID, N>, S, ID, N extends Number & Comparable<N>>
extends JpaRepositoryFactoryBean<T, S, ID> {
private Class<?> revisionEntityClass;
private @Nullable Class<?> revisionEntityClass;
/**
* Creates a new {@link EnversRevisionRepositoryFactoryBean} for the given repository interface.
@@ -81,7 +82,7 @@ public class EnversRevisionRepositoryFactoryBean<T extends RevisionRepository<S,
* @param entityManager must not be {@literal null}.
* @param revisionEntityClass can be {@literal null}, will default to {@link DefaultRevisionEntity}.
*/
public RevisionRepositoryFactory(EntityManager entityManager, Class<?> revisionEntityClass) {
public RevisionRepositoryFactory(EntityManager entityManager, @Nullable Class<?> revisionEntityClass) {
super(entityManager);

View File

@@ -1,5 +1,5 @@
/**
* Spring Data JPA specific converter infrastructure.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.envers.repository.support;

View File

@@ -465,4 +465,89 @@
</profile>
</profiles>
<profiles>
<profile>
<id>nullaway</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl}</version>
<classifier>jakarta</classifier>
</path>
<path>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>${hibernate}</version>
</path>
<path>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate}</version>
</path>
<path>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh}</version>
</path>
<path>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>${jakarta-persistence-api}</version>
</path>
<path>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>${errorprone}</version>
</path>
<path>
<groupId>com.uber.nullaway</groupId>
<artifactId>nullaway</artifactId>
<version>${nullaway}</version>
</path>
</annotationProcessorPaths>
</configuration>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<compilerArgs>
<arg>-XDcompilePolicy=simple</arg>
<arg>--should-stop=ifError=FLOW</arg>
<arg>-Xplugin:ErrorProne -XepDisableAllChecks -Xep:NullAway:ERROR -XepOpt:NullAway:OnlyNullMarked=true -XepOpt:NullAway:TreatGeneratedAsUnannotated=true -XepOpt:NullAway:CustomContractAnnotations=org.springframework.lang.Contract</arg>
</compilerArgs>
</configuration>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -34,6 +34,8 @@ import java.util.Optional;
import java.util.Set;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.ExampleMatcher.MatchMode;
@@ -41,7 +43,6 @@ 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.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -81,8 +82,7 @@ public class QueryByExamplePredicateBuilder {
* @param example must not be {@literal null}.
* @return {@literal null} indicates no {@link Predicate}.
*/
@Nullable
public static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Example<T> example) {
public static <T> @Nullable Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Example<T> example) {
return getPredicate(root, cb, example, EscapeCharacter.DEFAULT);
}
@@ -95,8 +95,7 @@ public class QueryByExamplePredicateBuilder {
* @param escapeCharacter Must not be {@literal null}.
* @return {@literal null} indicates no constraints
*/
@Nullable
public static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Example<T> example,
public static <T> @Nullable Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Example<T> example,
EscapeCharacter escapeCharacter) {
Assert.notNull(root, "Root must not be null");

View File

@@ -1,5 +1,5 @@
/**
* Spring Data JPA specific converter infrastructure.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.jpa.convert;

View File

@@ -27,6 +27,9 @@ import java.time.ZoneId;
import java.util.Date;
import org.springframework.data.convert.Jsr310Converters.DateToLocalDateConverter;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.data.convert.Jsr310Converters.DateToLocalDateTimeConverter;
import org.springframework.data.convert.Jsr310Converters.DateToLocalTimeConverter;
import org.springframework.data.convert.Jsr310Converters.LocalDateTimeToDateConverter;
@@ -36,8 +39,6 @@ import org.springframework.data.convert.Jsr310Converters.StringToZoneIdConverter
import org.springframework.data.convert.Jsr310Converters.ZoneIdToStringConverter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
/**
@@ -53,81 +54,71 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
public class Jsr310JpaConverters {
@Converter(autoApply = true)
public static class LocalDateConverter implements AttributeConverter<LocalDate, Date> {
public static class LocalDateConverter implements AttributeConverter<@Nullable LocalDate, @Nullable Date> {
@Nullable
@Override
public Date convertToDatabaseColumn(LocalDate date) {
public @Nullable Date convertToDatabaseColumn(@Nullable LocalDate date) {
return date == null ? null : LocalDateToDateConverter.INSTANCE.convert(date);
}
@Nullable
@Override
public LocalDate convertToEntityAttribute(Date date) {
public @Nullable LocalDate convertToEntityAttribute(@Nullable Date date) {
return date == null ? null : DateToLocalDateConverter.INSTANCE.convert(date);
}
}
@Converter(autoApply = true)
public static class LocalTimeConverter implements AttributeConverter<LocalTime, Date> {
public static class LocalTimeConverter implements AttributeConverter<@Nullable LocalTime, @Nullable Date> {
@Nullable
@Override
public Date convertToDatabaseColumn(LocalTime time) {
public @Nullable Date convertToDatabaseColumn(@Nullable LocalTime time) {
return time == null ? null : LocalTimeToDateConverter.INSTANCE.convert(time);
}
@Nullable
@Override
public LocalTime convertToEntityAttribute(Date date) {
public @Nullable LocalTime convertToEntityAttribute(@Nullable Date date) {
return date == null ? null : DateToLocalTimeConverter.INSTANCE.convert(date);
}
}
@Converter(autoApply = true)
public static class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Date> {
public static class LocalDateTimeConverter implements AttributeConverter<@Nullable LocalDateTime, @Nullable Date> {
@Nullable
@Override
public Date convertToDatabaseColumn(LocalDateTime date) {
public @Nullable Date convertToDatabaseColumn(@Nullable LocalDateTime date) {
return date == null ? null : LocalDateTimeToDateConverter.INSTANCE.convert(date);
}
@Nullable
@Override
public LocalDateTime convertToEntityAttribute(Date date) {
public @Nullable LocalDateTime convertToEntityAttribute(@Nullable Date date) {
return date == null ? null : DateToLocalDateTimeConverter.INSTANCE.convert(date);
}
}
@Converter(autoApply = true)
public static class InstantConverter implements AttributeConverter<Instant, Timestamp> {
public static class InstantConverter implements AttributeConverter<@Nullable Instant, @Nullable Timestamp> {
@Nullable
@Override
public Timestamp convertToDatabaseColumn(Instant instant) {
public @Nullable Timestamp convertToDatabaseColumn(@Nullable Instant instant) {
return instant == null ? null : InstantToTimestampConverter.INSTANCE.convert(instant);
}
@Nullable
@Override
public Instant convertToEntityAttribute(Timestamp timestamp) {
public @Nullable Instant convertToEntityAttribute(@Nullable Timestamp timestamp) {
return timestamp == null ? null : TimestampToInstantConverter.INSTANCE.convert(timestamp);
}
}
@Converter(autoApply = true)
public static class ZoneIdConverter implements AttributeConverter<ZoneId, String> {
public static class ZoneIdConverter implements AttributeConverter<@Nullable ZoneId, @Nullable String> {
@Nullable
@Override
public String convertToDatabaseColumn(ZoneId zoneId) {
public @Nullable String convertToDatabaseColumn(@Nullable ZoneId zoneId) {
return zoneId == null ? null : ZoneIdToStringConverter.INSTANCE.convert(zoneId);
}
@Nullable
@Override
public ZoneId convertToEntityAttribute(String zoneId) {
public @Nullable ZoneId convertToEntityAttribute(@Nullable String zoneId) {
return zoneId == null ? null : StringToZoneIdConverter.INSTANCE.convert(zoneId);
}
}

View File

@@ -1,5 +1,5 @@
/**
* Spring Data JPA specific JSR-310 converters.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.jpa.convert.threeten;

View File

@@ -25,7 +25,8 @@ import java.time.ZoneId;
import java.util.Optional;
import org.springframework.data.domain.Auditable;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Abstract base class for auditable entities. Stores the audition values in persistent fields.
@@ -37,18 +38,23 @@ import org.springframework.lang.Nullable;
* @param <PK> the type of the auditing type's identifier.
*/
@MappedSuperclass
@SuppressWarnings("NullAway")
public abstract class AbstractAuditable<U, PK extends Serializable> extends AbstractPersistable<PK>
implements Auditable<U, PK, LocalDateTime> {
// @Nullable
@ManyToOne //
private @Nullable U createdBy;
private U createdBy;
private @Nullable Instant createdDate;
// @Nullable
private Instant createdDate;
// @Nullable
@ManyToOne //
private @Nullable U lastModifiedBy;
private U lastModifiedBy;
private @Nullable Instant lastModifiedDate;
// @Nullable
private Instant lastModifiedDate;
@Override
public Optional<U> getCreatedBy() {
@@ -56,7 +62,7 @@ public abstract class AbstractAuditable<U, PK extends Serializable> extends Abst
}
@Override
public void setCreatedBy(U createdBy) {
public void setCreatedBy(@Nullable U createdBy) {
this.createdBy = createdBy;
}
@@ -77,7 +83,7 @@ public abstract class AbstractAuditable<U, PK extends Serializable> extends Abst
}
@Override
public void setLastModifiedBy(U lastModifiedBy) {
public void setLastModifiedBy(@Nullable U lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}

View File

@@ -18,13 +18,14 @@ package org.springframework.data.jpa.domain;
import java.io.Serializable;
import jakarta.persistence.GeneratedValue;
import org.jspecify.annotations.Nullable;
import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.Transient;
import org.springframework.data.domain.Persistable;
import org.springframework.data.util.ProxyUtils;
import org.springframework.lang.Nullable;
/**
* Abstract base class for entities. Allows parameterization of id type, chooses auto-generation and implements
@@ -38,12 +39,16 @@ import org.springframework.lang.Nullable;
* @param <PK> the type of the identifier.
*/
@MappedSuperclass
public abstract class AbstractPersistable<PK extends Serializable> implements Persistable<PK> {
@Id @GeneratedValue private @Nullable PK id;
@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;
}
@@ -74,7 +79,7 @@ public abstract class AbstractPersistable<PK extends Serializable> implements Pe
}
@Override
public boolean equals(Object obj) {
public boolean equals(@Nullable Object obj) {
if (null == obj) {
return false;

View File

@@ -25,8 +25,9 @@ import java.util.Arrays;
import java.util.stream.StreamSupport;
import org.springframework.lang.CheckReturnValue;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Contract;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -26,7 +26,8 @@ import java.util.Collections;
import java.util.List;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -24,8 +24,9 @@ import java.util.Arrays;
import java.util.stream.StreamSupport;
import org.springframework.lang.CheckReturnValue;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Contract;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -26,8 +26,9 @@ import java.util.Arrays;
import java.util.stream.StreamSupport;
import org.springframework.lang.CheckReturnValue;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Contract;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -231,6 +232,6 @@ public interface Specification<T> extends Serializable {
* @return a {@link Predicate}, may be {@literal null}.
*/
@Nullable
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
Predicate toPredicate(Root<T> root, @Nullable CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);
}

View File

@@ -24,7 +24,8 @@ import jakarta.persistence.criteria.Root;
import java.io.Serializable;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Contract;
/**
* Helper class to support specification compositions.
@@ -39,7 +40,8 @@ import org.springframework.lang.Nullable;
class SpecificationComposition {
interface Combiner extends Serializable {
Predicate combine(CriteriaBuilder builder, @Nullable Predicate lhs, @Nullable Predicate rhs);
@Nullable
Predicate combine(CriteriaBuilder builder, Predicate lhs, Predicate rhs);
}
static <T> Specification<T> composed(@Nullable Specification<T> lhs, @Nullable Specification<T> rhs,
@@ -58,12 +60,13 @@ class SpecificationComposition {
};
}
@Nullable
private static <T> Predicate toPredicate(@Nullable Specification<T> specification, Root<T> root,
private static <T> @Nullable Predicate toPredicate(@Nullable Specification<T> specification, Root<T> root,
@Nullable CriteriaQuery<?> query, CriteriaBuilder builder) {
return specification == null ? null : specification.toPredicate(root, query, builder);
}
@Contract("_, _, !null -> new")
@SuppressWarnings("NullAway")
static <T> DeleteSpecification<T> composed(@Nullable DeleteSpecification<T> lhs, @Nullable DeleteSpecification<T> rhs,
Combiner combiner) {
@@ -80,10 +83,10 @@ class SpecificationComposition {
};
}
@Nullable
private static <T> Predicate toPredicate(@Nullable DeleteSpecification<T> specification, Root<T> root,
private static <T> @Nullable Predicate toPredicate(@Nullable DeleteSpecification<T> specification, Root<T> root,
@Nullable CriteriaDelete<T> delete, CriteriaBuilder builder) {
return specification == null ? null : specification.toPredicate(root, delete, builder);
return specification == null || delete == null ? null : specification.toPredicate(root, delete, builder);
}
static <T> UpdateSpecification<T> composed(@Nullable UpdateSpecification<T> lhs, @Nullable UpdateSpecification<T> rhs,
@@ -102,8 +105,8 @@ class SpecificationComposition {
};
}
@Nullable
private static <T> Predicate toPredicate(@Nullable UpdateSpecification<T> specification, Root<T> root,
private static <T> @Nullable Predicate toPredicate(@Nullable UpdateSpecification<T> specification, Root<T> root,
CriteriaUpdate<T> update, CriteriaBuilder builder) {
return specification == null ? null : specification.toPredicate(root, update, builder);
}
@@ -124,8 +127,7 @@ class SpecificationComposition {
};
}
@Nullable
private static <T> Predicate toPredicate(@Nullable PredicateSpecification<T> specification, Root<T> root,
private static <T> @Nullable Predicate toPredicate(@Nullable PredicateSpecification<T> specification, Root<T> root,
CriteriaBuilder builder) {
return specification == null ? null : specification.toPredicate(root, builder);
}

View File

@@ -25,8 +25,9 @@ import java.util.Arrays;
import java.util.stream.StreamSupport;
import org.springframework.lang.CheckReturnValue;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Contract;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -1,5 +1,5 @@
/**
* JPA specific support classes to implement domain classes.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.jpa.domain;

View File

@@ -19,10 +19,11 @@ import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import org.springframework.beans.factory.ObjectFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.data.auditing.AuditingHandler;
import org.springframework.data.domain.Auditable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -1,5 +1,5 @@
/**
* Implementation classes for auditing with JPA.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.jpa.domain.support;

View File

@@ -22,6 +22,8 @@ import java.util.Set;
import java.util.function.Predicate;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.util.JpaMetamodel;
import org.springframework.data.mapping.PersistentPropertyPaths;
import org.springframework.data.mapping.context.AbstractMappingContext;
@@ -29,7 +31,6 @@ import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -114,8 +115,7 @@ public class JpaMetamodelMappingContext
* @param type must not be {@literal null}.
* @return
*/
@Nullable
public JpaMetamodel getMetamodel(TypeInformation<?> type) {
public @Nullable JpaMetamodel getMetamodel(TypeInformation<?> type) {
Metamodel metamodel = getMetamodelFor(type.getType());
@@ -166,8 +166,7 @@ public class JpaMetamodelMappingContext
* @param type must not be {@literal null}.
* @return can be {@literal null}.
*/
@Nullable
private Metamodel getMetamodelFor(Class<?> type) {
private @Nullable Metamodel getMetamodelFor(Class<?> type) {
for (Metamodel model : metamodels) {

View File

@@ -17,6 +17,7 @@ package org.springframework.data.jpa.mapping;
import java.util.Comparator;
import org.jspecify.annotations.Nullable;
import org.springframework.data.annotation.Version;
import org.springframework.data.jpa.provider.ProxyIdAccessor;
import org.springframework.data.jpa.util.JpaMetamodel;
@@ -63,7 +64,7 @@ class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentP
}
@Override
protected JpaPersistentProperty returnPropertyIfBetterIdPropertyCandidateOrNull(JpaPersistentProperty property) {
protected @Nullable JpaPersistentProperty returnPropertyIfBetterIdPropertyCandidateOrNull(JpaPersistentProperty property) {
return property.isIdProperty() ? property : null;
}
@@ -117,7 +118,7 @@ class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentP
}
@Override
public Object getIdentifier() {
public @Nullable Object getIdentifier() {
return proxyIdAccessor.shouldUseAccessorFor(bean) //
? proxyIdAccessor.getIdentifierFrom(bean)//

View File

@@ -25,6 +25,8 @@ import java.util.HashSet;
import java.util.Set;
import org.springframework.core.annotation.AnnotationUtils;
import org.jspecify.annotations.Nullable;
import org.springframework.data.annotation.AccessType.Type;
import org.springframework.data.jpa.util.JpaMetamodel;
import org.springframework.data.mapping.Association;
@@ -34,7 +36,6 @@ import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.Lazy;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -170,7 +171,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPer
}
@Override
public TypeInformation<?> getAssociationTargetTypeInformation() {
public @Nullable TypeInformation<?> getAssociationTargetTypeInformation() {
if (!isAssociation()) {
return null;
@@ -193,8 +194,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPer
*
* @return
*/
@Nullable
private Boolean detectPropertyAccess() {
private @Nullable Boolean detectPropertyAccess() {
org.springframework.data.annotation.AccessType accessType = findAnnotation(
org.springframework.data.annotation.AccessType.class);
@@ -229,8 +229,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPer
*
* @return
*/
@Nullable
private TypeInformation<?> detectAssociationTargetType() {
private @Nullable TypeInformation<?> detectAssociationTargetType() {
if (!isAssociation()) {
return null;

View File

@@ -1,5 +1,5 @@
/**
* JPA specific support classes for the Spring Data mapping subsystem.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.jpa.mapping;

View File

@@ -1,5 +1,5 @@
/**
* JPA specific support projection support.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.jpa.projection;

View File

@@ -17,7 +17,7 @@ package org.springframework.data.jpa.provider;
import org.hibernate.query.Query;
import org.hibernate.query.spi.SqmQuery;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Utility functions to work with Hibernate. Mostly using reflection to make sure common functionality can be executed
@@ -41,8 +41,7 @@ public abstract class HibernateUtils {
* @param query
* @return
*/
@Nullable
public static String getHibernateQuery(Object query) {
public @Nullable static String getHibernateQuery(Object query) {
try {

View File

@@ -18,8 +18,9 @@ package org.springframework.data.jpa.provider;
import jakarta.persistence.EntityManager;
import jakarta.persistence.metamodel.Metamodel;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.jspecify.annotations.Nullable;
import org.springframework.util.ClassUtils;
/**

View File

@@ -36,8 +36,9 @@ import org.eclipse.persistence.queries.ScrollableCursor;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.proxy.HibernateProxy;
import org.jspecify.annotations.Nullable;
import org.springframework.data.util.CloseableIterator;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -68,7 +69,7 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
Collections.singletonList(HIBERNATE_JPA_METAMODEL_TYPE)) {
@Override
public String extractQueryString(Query query) {
public @Nullable String extractQueryString(Query query) {
return HibernateUtils.getHibernateQuery(query);
}
@@ -127,9 +128,8 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
return false;
}
@Nullable
@Override
public Object getIdentifierFrom(Object entity) {
public @Nullable Object getIdentifierFrom(Object entity) {
return null;
}
@@ -154,9 +154,8 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
*/
GENERIC_JPA(Collections.singleton(GENERIC_JPA_ENTITY_MANAGER_INTERFACE), Collections.emptySet()) {
@Nullable
@Override
public String extractQueryString(Query query) {
public @Nullable String extractQueryString(Query query) {
return null;
}
@@ -170,20 +169,18 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
return false;
}
@Nullable
@Override
public Object getIdentifierFrom(Object entity) {
public @Nullable Object getIdentifierFrom(Object entity) {
return null;
}
@Nullable
@Override
public String getCommentHintKey() {
public @Nullable String getCommentHintKey() {
return null;
}
};
private static final Class<?> typedParameterValueClass;
private static final @Nullable Class<?> typedParameterValueClass;
static {
@@ -334,8 +331,7 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor, Quer
* @return the original value or null.
* @since 3.0
*/
@Nullable
public static Object unwrapTypedParameterValue(@Nullable Object value) {
public static @Nullable Object unwrapTypedParameterValue(@Nullable Object value) {
return typedParameterValueClass != null && typedParameterValueClass.isInstance(value) //
? null //

View File

@@ -15,7 +15,7 @@
*/
package org.springframework.data.jpa.provider;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Interface for a persistence provider specific accessor of identifiers held in proxies.

View File

@@ -17,7 +17,7 @@ package org.springframework.data.jpa.provider;
import jakarta.persistence.Query;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Interface to hide different implementations of query hints that insert comments into a {@link Query}.

View File

@@ -17,7 +17,7 @@ package org.springframework.data.jpa.provider;
import jakarta.persistence.Query;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Interface to hide different implementations to extract the original JPA query string from a {@link Query}.

View File

@@ -1,5 +1,5 @@
/**
* JPA provider-specific utilities.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.jpa.provider;

View File

@@ -31,6 +31,8 @@ import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
@@ -40,7 +42,6 @@ import org.springframework.data.jpa.domain.PredicateSpecification;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.domain.UpdateSpecification;
import org.springframework.data.repository.query.FluentQuery;
import org.springframework.lang.Nullable;
/**
* Interface to allow execution of {@link Specification}s based on the JPA criteria API.

View File

@@ -22,6 +22,8 @@ import java.util.Collections;
import java.util.List;
import org.springframework.aot.hint.ExecutableMode;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
@@ -36,7 +38,6 @@ import org.springframework.data.jpa.repository.support.QuerydslJpaPredicateExecu
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.querydsl.QuerydslUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**

View File

@@ -1,5 +1,5 @@
/**
* CDI support for Spring Data JPA Repositories.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.jpa.repository.cdi;

View File

@@ -17,6 +17,7 @@ package org.springframework.data.jpa.repository.config;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
@@ -45,6 +46,7 @@ public class AuditingBeanDefinitionParser implements BeanDefinitionParser {
private final SpringConfiguredBeanDefinitionParser springConfiguredParser = new SpringConfiguredBeanDefinitionParser();
@Override
@SuppressWarnings("NullAway")
public BeanDefinition parse(Element element, ParserContext parser) {
springConfiguredParser.parse(element, parser);
@@ -90,7 +92,7 @@ public class AuditingBeanDefinitionParser implements BeanDefinitionParser {
private static final String BEAN_CONFIGURER_ASPECT_CLASS_NAME = "org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect";
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
public @Nullable BeanDefinition parse(Element element, ParserContext parserContext) {
if (!parserContext.getRegistry().containsBeanDefinition(BEAN_CONFIGURER_ASPECT_BEAN_NAME)) {

View File

@@ -23,6 +23,8 @@ import jakarta.persistence.metamodel.Metamodel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean;
@@ -32,7 +34,6 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
import org.springframework.data.util.StreamUtils;
import org.springframework.lang.Nullable;
/**
* {@link FactoryBean} to setup {@link JpaMetamodelMappingContext} instances from Spring configuration.

View File

@@ -34,6 +34,8 @@ import java.util.Optional;
import java.util.Set;
import org.springframework.aot.generate.GenerationContext;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
@@ -56,7 +58,6 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
import org.springframework.data.repository.config.RepositoryConfigurationSource;
import org.springframework.data.repository.config.RepositoryRegistrationAotProcessor;
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
import org.springframework.lang.Nullable;
import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -116,7 +117,9 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
Optional<String> transactionManagerRef = source.getAttribute("transactionManagerRef");
builder.addPropertyValue("transactionManager", transactionManagerRef.orElse(DEFAULT_TRANSACTION_MANAGER_BEAN_NAME));
builder.addPropertyReference("entityManager", entityManagerRefs.get(source));
if(entityManagerRefs.containsKey(source)) {
builder.addPropertyReference("entityManager", entityManagerRefs.get(source));
}
builder.addPropertyValue(ESCAPE_CHARACTER_PROPERTY, getEscapeCharacter(source).orElse('\\'));
builder.addPropertyReference("mappingContext", JPA_MAPPING_CONTEXT_BEAN_NAME);
}
@@ -228,13 +231,13 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
}
@Override
protected ClassLoader getConfigurationInspectionClassLoader(ResourceLoader loader) {
protected @Nullable ClassLoader getConfigurationInspectionClassLoader(ResourceLoader loader) {
ClassLoader classLoader = loader.getClassLoader();
return classLoader != null && LazyJvmAgent.isActive(loader.getClassLoader())
? new InspectionClassLoader(loader.getClassLoader())
: loader.getClassLoader();
? new InspectionClassLoader(classLoader)
: classLoader;
}
/**

View File

@@ -1,5 +1,5 @@
/**
* Classes for JPA namespace configuration.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.jpa.repository.config;

View File

@@ -1,5 +1,5 @@
/**
* Interfaces and annotations for JPA specific repositories.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.data.jpa.repository;

View File

@@ -35,6 +35,8 @@ import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import org.springframework.beans.BeanUtils;
import org.jspecify.annotations.Nullable;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.jpa.provider.PersistenceProvider;
@@ -55,7 +57,6 @@ 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.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -141,9 +142,8 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
return metamodel;
}
@Nullable
@Override
public Object execute(Object[] parameters) {
public @Nullable Object execute(Object[] parameters) {
return doExecute(getExecution(), parameters);
}
@@ -152,8 +152,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
* @param values
* @return
*/
@Nullable
private Object doExecute(JpaQueryExecution execution, Object[] values) {
private @Nullable Object doExecute(JpaQueryExecution execution, Object[] values) {
JpaParametersParameterAccessor accessor = obtainParameterAccessor(values);
Object result = execution.execute(this, accessor);
@@ -193,6 +192,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
* @param query
* @return
*/
@SuppressWarnings("NullAway")
protected <T extends Query> T applyHints(T query, JpaQueryMethod method) {
List<QueryHint> hints = method.getHints();
@@ -283,8 +283,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
* @return
* @since 2.0.5
*/
@Nullable
protected Class<?> getTypeToRead(ReturnedType returnedType) {
protected @Nullable Class<?> getTypeToRead(ReturnedType returnedType) {
if (PersistenceProvider.ECLIPSELINK.equals(provider)) {
return null;
@@ -525,8 +524,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
* @return the value of the backing {@link Tuple} for that key or {@code null}.
*/
@Override
@Nullable
public Object get(Object key) {
public @Nullable Object get(Object key) {
if (!(key instanceof String)) {
return null;

View File

@@ -24,6 +24,8 @@ import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.data.domain.Pageable;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.Sort;
import org.springframework.data.expression.ValueEvaluationContextProvider;
import org.springframework.data.jpa.repository.QueryRewriter;
@@ -33,7 +35,6 @@ import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.ValueExpressionDelegate;
import org.springframework.data.util.Lazy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentLruCache;
import org.springframework.util.StringUtils;
@@ -318,7 +319,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
static class UnsortedCachingQuerySortRewriter implements QuerySortRewriter {
private volatile String cachedQueryString;
private volatile @Nullable String cachedQueryString;
public String getSorted(DeclaredQuery query, Sort sort, ReturnedType returnedType) {
@@ -344,7 +345,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
private final ConcurrentLruCache<CachableQuery, String> queryCache = new ConcurrentLruCache<>(16,
AbstractStringBasedJpaQuery.this::applySorting);
private volatile String cachedQueryString;
private volatile @Nullable String cachedQueryString;
@Override
public String getSorted(DeclaredQuery query, Sort sort, ReturnedType returnedType) {

View File

@@ -15,8 +15,9 @@
*/
package org.springframework.data.jpa.repository.query;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.lang.Nullable;
/**
* An exception thrown if the JPQL query is invalid.
@@ -29,12 +30,12 @@ public class BadJpqlGrammarException extends InvalidDataAccessResourceUsageExcep
private final String jpql;
public BadJpqlGrammarException(String message, String jpql, @Nullable Throwable cause) {
public BadJpqlGrammarException(@Nullable String message, String jpql, @Nullable Throwable cause) {
this(message, jpql, "JPQL", cause);
}
BadJpqlGrammarException(String message, String grammar, String jpql, @Nullable Throwable cause) {
super(message + "; Bad " + grammar + " grammar [" + jpql + "]", cause);
BadJpqlGrammarException(@Nullable String message, String grammar, String jpql, @Nullable Throwable cause) {
super("%sBad %s grammar [%s]".formatted(message != null ? message + "; " : "", grammar, jpql), cause);
this.jpql = jpql;
}

View File

@@ -17,9 +17,10 @@ package org.springframework.data.jpa.repository.query;
import java.util.List;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.jspecify.annotations.Nullable;
/**
* A wrapper for a String representation of a query offering information about the query.
*

View File

@@ -18,7 +18,8 @@ package org.springframework.data.jpa.repository.query;
import java.util.Set;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* The implementation of the Regex-based {@link QueryEnhancer} using {@link QueryUtils}.
@@ -30,7 +31,7 @@ public class DefaultQueryEnhancer implements QueryEnhancer {
private final DeclaredQuery query;
private final boolean hasConstructorExpression;
private final String alias;
private final @Nullable String alias;
private final String projection;
private final Set<String> joinAliases;
@@ -68,7 +69,7 @@ public class DefaultQueryEnhancer implements QueryEnhancer {
}
@Override
public String detectAlias() {
public @Nullable String detectAlias() {
return this.alias;
}

View File

@@ -57,7 +57,7 @@ class DtoProjectionTransformerDelegate {
builder.appendInline(QueryTokenStream.concat(returnedType.getInputProperties(), property -> {
QueryRenderer.QueryRendererBuilder prop = QueryRenderer.builder();
prop.append(QueryTokens.token(selectionList.getFirst().value()));
prop.append(QueryTokens.token(selectionList.getRequiredFirst().value()));
prop.append(QueryTokens.TOKEN_DOT);
prop.append(QueryTokens.token(property));

View File

@@ -18,7 +18,7 @@ package org.springframework.data.jpa.repository.query;
import java.util.Collections;
import java.util.List;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* NULL-Object pattern implementation for {@link DeclaredQuery}.
@@ -44,7 +44,7 @@ class EmptyDeclaredQuery implements DeclaredQuery {
}
@Override
public String getAlias() {
public @Nullable String getAlias() {
return null;
}

View File

@@ -18,6 +18,8 @@ package org.springframework.data.jpa.repository.query;
import java.util.Collections;
import java.util.Iterator;
import org.jspecify.annotations.Nullable;
/**
* Empty QueryTokenStream.
*
@@ -31,12 +33,12 @@ class EmptyQueryTokenStream implements QueryTokenStream {
private EmptyQueryTokenStream() {}
@Override
public QueryToken getFirst() {
public @Nullable QueryToken getFirst() {
return null;
}
@Override
public QueryToken getLast() {
public @Nullable QueryToken getLast() {
return null;
}

View File

@@ -18,8 +18,9 @@ package org.springframework.data.jpa.repository.query;
import static org.springframework.data.jpa.repository.query.QueryTokens.*;
import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.repository.query.QueryTransformers.CountSelectionTokenStream;
import org.springframework.lang.Nullable;
/**
* An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that transforms a parsed EQL query into a
@@ -30,7 +31,7 @@ import org.springframework.lang.Nullable;
* @author Christoph Strobl
* @since 3.4
*/
@SuppressWarnings("ConstantValue")
@SuppressWarnings({ "ConstantValue", "NullAway" })
class EqlCountQueryTransformer extends EqlQueryRenderer {
private final @Nullable String countProjection;

View File

@@ -22,7 +22,8 @@ import java.util.Collections;
import java.util.List;
import org.springframework.data.jpa.repository.query.EqlParser.Range_variable_declarationContext;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* {@link ParsedQueryIntrospector} for EQL queries.

View File

@@ -20,9 +20,10 @@ import static org.springframework.data.jpa.repository.query.QueryTokens.*;
import java.util.List;
import org.springframework.data.domain.Sort;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

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

View File

@@ -18,6 +18,8 @@ package org.springframework.data.jpa.repository.query;
import java.util.Objects;
import java.util.regex.Pattern;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.data.expression.ValueEvaluationContext;
import org.springframework.data.expression.ValueExpression;
import org.springframework.data.expression.ValueExpressionParser;
@@ -52,6 +54,12 @@ class ExpressionBasedStringQuery extends StringQuery {
private static final String ENTITY_NAME_VARIABLE = "#" + ENTITY_NAME;
private static final String ENTITY_NAME_VARIABLE_EXPRESSION = "#{" + ENTITY_NAME_VARIABLE;
private static final Environment DEFAULT_ENVIRONMENT;
static {
DEFAULT_ENVIRONMENT = new StandardEnvironment();
}
/**
* Creates a new {@link ExpressionBasedStringQuery} for the given query and {@link EntityMetadata}.
*
@@ -102,7 +110,8 @@ class ExpressionBasedStringQuery extends StringQuery {
ValueExpression expr = parser.parse(query);
String result = Objects.toString(expr.evaluate(ValueEvaluationContext.of(null, evalContext)));
String result = Objects.toString(
expr.evaluate(ValueEvaluationContext.of(DEFAULT_ENVIRONMENT, evalContext)));
if (result == null) {
return query;

View File

@@ -21,10 +21,11 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.TypedParameterValue;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
import org.jspecify.annotations.Nullable;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.lang.Nullable;
/**
* {@link org.springframework.data.repository.query.ParameterAccessor} based on an {@link Parameters} instance. In
@@ -62,9 +63,8 @@ class HibernateJpaParametersParameterAccessor extends JpaParametersParameterAcce
}
@Override
@Nullable
@SuppressWarnings("unchecked")
public Object getValue(Parameter parameter) {
public @Nullable Object getValue(Parameter parameter) {
Object value = super.getValue(parameter.getIndex());

View File

@@ -17,7 +17,7 @@ package org.springframework.data.jpa.repository.query;
import java.util.List;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Hibernate-specific query details capturing common table expression details.

View File

@@ -18,9 +18,10 @@ package org.springframework.data.jpa.repository.query;
import static org.springframework.data.jpa.repository.query.QueryTokens.*;
import org.springframework.data.jpa.repository.query.HqlParser.SelectClauseContext;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder;
import org.springframework.data.jpa.repository.query.QueryTransformers.CountSelectionTokenStream;
import org.springframework.lang.Nullable;
/**
* An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that transforms a parsed HQL query into a

View File

@@ -45,6 +45,7 @@ import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.JpaSort;
import org.springframework.data.mapping.PropertyPath;
@@ -58,7 +59,7 @@ import org.springframework.util.Assert;
* @author Mark Paluch
* @since 4.0
*/
@SuppressWarnings({ "unchecked", "rawtypes", "ConstantValue" })
@SuppressWarnings({ "unchecked", "rawtypes", "ConstantValue", "NullAway" })
class HqlOrderExpressionVisitor extends HqlBaseVisitor<Expression<?>> {
private static final DateTimeFormatter DATE_TIME = new DateTimeFormatterBuilder().parseCaseInsensitive()
@@ -119,7 +120,7 @@ class HqlOrderExpressionVisitor extends HqlBaseVisitor<Expression<?>> {
}
@Override
public Expression<?> visitSortExpression(HqlParser.SortExpressionContext ctx) {
public @Nullable Expression<?> visitSortExpression(HqlParser.SortExpressionContext ctx) {
if (ctx.identifier() != null) {
HqlParser.IdentifierContext identifier = ctx.identifier();

View File

@@ -22,7 +22,8 @@ import java.util.Collections;
import java.util.List;
import org.springframework.data.jpa.repository.query.HqlParser.VariableContext;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* {@link ParsedQueryIntrospector} for HQL queries.

View File

@@ -20,9 +20,10 @@ import static org.springframework.data.jpa.repository.query.QueryTokens.*;
import java.util.List;
import org.springframework.data.domain.Sort;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

View File

@@ -38,6 +38,7 @@ import net.sf.jsqlparser.statement.select.SelectItem;
import net.sf.jsqlparser.statement.select.SetOperationList;
import net.sf.jsqlparser.statement.select.Values;
import net.sf.jsqlparser.statement.update.Update;
import org.jspecify.annotations.Nullable;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -53,9 +54,9 @@ import java.util.function.Supplier;
import org.springframework.data.domain.Sort;
import org.springframework.data.util.Predicates;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.SerializationUtils;
import org.springframework.util.StringUtils;
@@ -80,7 +81,7 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
private final String projection;
private final Set<String> joinAliases;
private final Set<String> selectAliases;
private final byte[] serialized;
private final byte @Nullable[] serialized;
/**
* @param query the query we want to enhance. Must not be {@literal null}.
@@ -96,6 +97,8 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
this.projection = detectProjection(this.statement);
this.selectAliases = Collections.unmodifiableSet(getSelectionAliases(this.statement));
this.joinAliases = Collections.unmodifiableSet(getJoinAliases(this.statement));
byte[] tmp = SerializationUtils.serialize(this.statement);
// this.serialized = tmp != null ? tmp : new byte[0];
this.serialized = SerializationUtils.serialize(this.statement);
}
@@ -135,8 +138,7 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
*
* @return Might return {@literal null}.
*/
@Nullable
private static String detectAlias(ParsedType parsedType, Statement statement) {
private static @Nullable String detectAlias(ParsedType parsedType, Statement statement) {
if (ParsedType.MERGE.equals(parsedType)) {
@@ -317,7 +319,7 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
}
@Override
public String detectAlias() {
public @Nullable String detectAlias() {
return this.primaryAlias;
}
@@ -363,10 +365,10 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
return queryString;
}
return applySorting((Select) deserialize(this.serialized), sort, alias);
return applySorting(deserializeRequired(this.serialized, Select.class), sort, alias);
}
private String applySorting(Select selectStatement, Sort sort, @Nullable String alias) {
private String applySorting(@Nullable Select selectStatement, Sort sort, @Nullable String alias) {
if (selectStatement instanceof SetOperationList setOperationList) {
return applySortingToSetOperationList(setOperationList, sort);
@@ -570,7 +572,10 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
* @param bytes a serialized object
* @return the result of deserializing the bytes
*/
private static Object deserialize(byte[] bytes) {
private static @Nullable Object deserialize(byte @Nullable[] bytes) {
if(ObjectUtils.isEmpty(bytes)) {
return null;
}
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
return ois.readObject();
} catch (IOException ex) {
@@ -580,4 +585,12 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
}
}
private static <T> T deserializeRequired(byte @Nullable[] bytes, Class<T> type) {
Object deserialize = deserialize(bytes);
if(deserialize != null) {
return type.cast(deserialize);
}
throw new IllegalStateException("Failed to deserialize object type");
}
}

View File

@@ -26,8 +26,9 @@ import java.util.Collections;
import java.util.List;
import org.springframework.data.jpa.repository.support.MutableQueryHints;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.repository.support.QueryHints;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -188,8 +189,7 @@ public class Jpa21Utils {
* @param parent
* @return {@literal null} if not found.
*/
@Nullable
private static AttributeNode<?> findAttributeNode(String attributeNodeName, EntityGraph<?> entityGraph,
private static @Nullable AttributeNode<?> findAttributeNode(String attributeNodeName, EntityGraph<?> entityGraph,
@Nullable Subgraph<?> parent) {
return findAttributeNode(attributeNodeName,
parent != null ? parent.getAttributeNodes() : entityGraph.getAttributeNodes());
@@ -203,8 +203,7 @@ public class Jpa21Utils {
* @param nodes
* @return {@literal null} if not found.
*/
@Nullable
private static AttributeNode<?> findAttributeNode(String attributeNodeName, List<AttributeNode<?>> nodes) {
private static @Nullable AttributeNode<?> findAttributeNode(String attributeNodeName, List<AttributeNode<?>> nodes) {
for (AttributeNode<?> node : nodes) {
if (ObjectUtils.nullSafeEquals(node.getAttributeName(), attributeNodeName)) {
@@ -223,8 +222,7 @@ public class Jpa21Utils {
* @param node
* @return
*/
@Nullable
private static Subgraph<?> getSubgraph(AttributeNode<?> node) {
private static @Nullable Subgraph<?> getSubgraph(AttributeNode<?> node) {
return node.getSubgraphs().isEmpty() ? null : node.getSubgraphs().values().iterator().next();
}
}

View File

@@ -18,8 +18,9 @@ package org.springframework.data.jpa.repository.query;
import java.util.List;
import org.springframework.data.jpa.repository.EntityGraph;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -56,7 +57,7 @@ public class JpaEntityGraph {
* @param attributePaths may be {@literal null}.
* @since 1.9
*/
public JpaEntityGraph(String name, EntityGraphType type, @Nullable String[] attributePaths) {
public JpaEntityGraph(String name, EntityGraphType type, String @Nullable[] attributePaths) {
Assert.hasText(name, "The name of an EntityGraph must not be null or empty");
Assert.notNull(type, "FetchGraphType must not be null");

View File

@@ -25,12 +25,13 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.springframework.data.domain.KeysetScrollPosition;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpqlQueryTemplates;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.lang.Nullable;
/**
* Extension to {@link JpaQueryCreator} to create queries considering {@link KeysetScrollPosition keyset scrolling}.
@@ -68,7 +69,7 @@ class JpaKeysetScrollQueryCreator extends JpaQueryCreator {
}
@Override
protected JpqlQueryBuilder.AbstractJpqlQuery createQuery(@Nullable JpqlQueryBuilder.Predicate predicate, Sort sort) {
protected JpqlQueryBuilder.AbstractJpqlQuery createQuery(JpqlQueryBuilder.@Nullable Predicate predicate, Sort sort) {
KeysetScrollSpecification<Object> keysetSpec = new KeysetScrollSpecification<>(scrollPosition, sort,
entityInformation);
@@ -90,9 +91,9 @@ class JpaKeysetScrollQueryCreator extends JpaQueryCreator {
return query;
}
@Nullable
private static JpqlQueryBuilder.Predicate getPredicate(@Nullable JpqlQueryBuilder.Predicate predicate,
@Nullable JpqlQueryBuilder.Predicate keysetPredicate) {
private static JpqlQueryBuilder.@Nullable Predicate getPredicate(JpqlQueryBuilder.@Nullable Predicate predicate,
JpqlQueryBuilder.@Nullable Predicate keysetPredicate) {
if (keysetPredicate != null) {
if (predicate != null) {

View File

@@ -23,13 +23,14 @@ import java.util.List;
import java.util.function.Function;
import org.springframework.core.MethodParameter;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.repository.Temporal;
import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.ParametersSource;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
/**
* Custom extension of {@link Parameters} discovering additional query parameter annotations.

View File

@@ -15,11 +15,12 @@
*/
package org.springframework.data.jpa.repository.query;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.lang.Nullable;
/**
* {@link org.springframework.data.repository.query.ParameterAccessor} based on an {@link Parameters} instance. It also
@@ -48,8 +49,7 @@ public class JpaParametersParameterAccessor extends ParametersParameterAccessor
return parameters;
}
@Nullable
public <T> T getValue(Parameter parameter) {
public <T> @Nullable T getValue(Parameter parameter) {
return super.getValue(parameter.getIndex());
}

View File

@@ -34,6 +34,8 @@ import java.util.List;
import java.util.stream.Collectors;
import org.springframework.data.domain.Sort;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.domain.JpaSort;
import org.springframework.data.jpa.repository.query.JpqlQueryBuilder.ParameterPlaceholder;
import org.springframework.data.jpa.repository.query.ParameterBinding.PartTreeParameterBinding;
@@ -45,7 +47,6 @@ import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.Part.Type;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -142,13 +143,13 @@ class JpaQueryCreator extends AbstractQueryCreator<String, JpqlQueryBuilder.Pred
* it the current {@link JpqlQueryBuilder.Predicate}.
*/
@Override
protected final String complete(@Nullable JpqlQueryBuilder.Predicate predicate, Sort sort) {
protected final String complete(JpqlQueryBuilder.@Nullable Predicate predicate, Sort sort) {
JpqlQueryBuilder.AbstractJpqlQuery query = createQuery(predicate, sort);
return query.render();
}
protected JpqlQueryBuilder.AbstractJpqlQuery createQuery(@Nullable JpqlQueryBuilder.Predicate predicate, Sort sort) {
protected JpqlQueryBuilder.AbstractJpqlQuery createQuery(JpqlQueryBuilder.@Nullable Predicate predicate, Sort sort) {
JpqlQueryBuilder.Select query = buildQuery(sort);

View File

@@ -32,10 +32,10 @@ import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.atn.PredictionMode;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -210,7 +210,7 @@ class JpaQueryEnhancer<Q extends QueryInformation> implements QueryEnhancer {
* already find the alias when generating sorted and count queries, this is mainly to serve test cases.
*/
@Override
public String detectAlias() {
public @Nullable String detectAlias() {
return this.queryInformation.getAlias();
}
@@ -267,7 +267,7 @@ class JpaQueryEnhancer<Q extends QueryInformation> implements QueryEnhancer {
* @return
*/
@Override
public String applySorting(Sort sort, String alias) {
public String applySorting(Sort sort, @Nullable String alias) {
return applySorting(sort);
}

View File

@@ -26,6 +26,8 @@ import java.util.Map;
import java.util.Optional;
import org.springframework.core.convert.ConversionService;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.dao.InvalidDataAccessApiUsageException;
@@ -39,7 +41,6 @@ import org.springframework.data.repository.core.support.SurroundingTransactionDe
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.data.util.CloseableIterator;
import org.springframework.data.util.StreamUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -80,8 +81,7 @@ public abstract class JpaQueryExecution {
* @param accessor must not be {@literal null}.
* @return
*/
@Nullable
public Object execute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
public @Nullable Object execute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
Assert.notNull(query, "AbstractJpaQuery must not be null");
Assert.notNull(accessor, "JpaParametersParameterAccessor must not be null");
@@ -110,8 +110,7 @@ public abstract class JpaQueryExecution {
* @param query must not be {@literal null}.
* @param accessor must not be {@literal null}.
*/
@Nullable
protected abstract Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor);
protected abstract @Nullable Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor);
/**
* Executes the query to return a simple collection of entities.
@@ -142,7 +141,7 @@ public abstract class JpaQueryExecution {
}
@Override
@SuppressWarnings("unchecked")
@SuppressWarnings("NullAway")
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
ScrollPosition scrollPosition = accessor.getScrollPosition();
@@ -212,7 +211,7 @@ public abstract class JpaQueryExecution {
static class SingleEntityExecution extends JpaQueryExecution {
@Override
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
protected @Nullable Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
return query.createQuery(accessor).getSingleResultOrNull();
}
@@ -327,7 +326,7 @@ public abstract class JpaQueryExecution {
}
@Override
protected Object doExecute(AbstractJpaQuery jpaQuery, JpaParametersParameterAccessor accessor) {
protected @Nullable Object doExecute(AbstractJpaQuery jpaQuery, JpaParametersParameterAccessor accessor) {
Assert.isInstanceOf(StoredProcedureJpaQuery.class, jpaQuery);
@@ -372,10 +371,10 @@ public abstract class JpaQueryExecution {
private static final String NO_SURROUNDING_TRANSACTION = "You're trying to execute a streaming query method without a surrounding transaction that keeps the connection open so that the Stream can actually be consumed; Make sure the code consuming the stream uses @Transactional or any other way of declaring a (read-only) transaction";
private static final Method streamMethod = ReflectionUtils.findMethod(Query.class, "getResultStream");
private static final @Nullable Method streamMethod = ReflectionUtils.findMethod(Query.class, "getResultStream");
@Override
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
protected @Nullable Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
if (!SurroundingTransactionDetectorMethodInterceptor.INSTANCE.isSurroundingTransactionActive()) {
throw new InvalidDataAccessApiUsageException(NO_SURROUNDING_TRANSACTION);

View File

@@ -18,10 +18,11 @@ package org.springframework.data.jpa.repository.query;
import jakarta.persistence.EntityManager;
import org.springframework.data.jpa.repository.QueryRewriter;
import org.jspecify.annotations.Nullable;
import org.springframework.data.repository.query.QueryCreationException;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ValueExpressionDelegate;
import org.springframework.lang.Nullable;
/**
* Factory to create the appropriate {@link RepositoryQuery} for a {@link JpaQueryMethod}.

View File

@@ -21,6 +21,7 @@ import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.QueryRewriter;
@@ -32,7 +33,6 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ValueExpressionDelegate;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -184,8 +184,7 @@ public final class JpaQueryLookupStrategy {
return query != null ? query : NO_QUERY;
}
@Nullable
private String getCountQuery(JpaQueryMethod method, NamedQueries namedQueries, EntityManager em) {
private @Nullable String getCountQuery(JpaQueryMethod method, NamedQueries namedQueries, EntityManager em) {
if (StringUtils.hasText(method.getCountQuery())) {
return method.getCountQuery();

View File

@@ -28,6 +28,8 @@ import java.util.Set;
import java.util.function.Function;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.jspecify.annotations.Nullable;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.jpa.repository.EntityGraph;
@@ -45,7 +47,6 @@ import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.util.QueryExecutionConverters;
import org.springframework.data.util.Lazy;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -301,8 +302,7 @@ public class JpaQueryMethod extends QueryMethod {
*
* @return
*/
@Nullable
public String getAnnotatedQuery() {
public @Nullable String getAnnotatedQuery() {
String query = getAnnotationValue("value", String.class);
return StringUtils.hasText(query) ? query : null;
@@ -340,8 +340,7 @@ public class JpaQueryMethod extends QueryMethod {
*
* @return
*/
@Nullable
public String getCountQuery() {
public @Nullable String getCountQuery() {
String countQuery = getAnnotationValue("countQuery", String.class);
return StringUtils.hasText(countQuery) ? countQuery : null;
@@ -418,7 +417,7 @@ public class JpaQueryMethod extends QueryMethod {
return getMergedOrDefaultAnnotationValue(attribute, Query.class, type);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@SuppressWarnings({ "rawtypes", "unchecked", "NullAway" })
private <T> T getMergedOrDefaultAnnotationValue(String attribute, Class annotationType, Class<T> targetType) {
Annotation annotation = AnnotatedElementUtils.findMergedAnnotation(method, annotationType);

View File

@@ -9,10 +9,11 @@ import java.util.Set;
import java.util.regex.Pattern;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.NullHandling;
import org.springframework.data.jpa.domain.JpaSort;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**

View File

@@ -22,9 +22,10 @@ import java.sql.Blob;
import java.sql.SQLException;
import org.springframework.core.convert.converter.Converter;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.CleanupFailureDataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils;
/**
@@ -50,9 +51,9 @@ final class JpaResultConverters {
INSTANCE;
@Nullable
@Override
public byte[] convert(@Nullable Blob source) {
public byte @Nullable[] convert(@Nullable Blob source) {
if (source == null) {
return null;

View File

@@ -18,8 +18,10 @@ package org.springframework.data.jpa.repository.query;
import static org.springframework.data.jpa.repository.query.QueryTokens.*;
import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.repository.query.QueryTransformers.CountSelectionTokenStream;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
* An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that transforms a parsed JPQL query into a
@@ -80,8 +82,10 @@ class JpqlCountQueryTransformer extends JpqlQueryRenderer {
if (usesDistinct) {
nested.append(QueryTokens.expression(ctx.DISTINCT()));
nested.append(getDistinctCountSelection(QueryTokenStream.concat(ctx.select_item(), this::visit, TOKEN_COMMA)));
} else {
} else if(StringUtils.hasText(primaryFromAlias)) {
nested.append(QueryTokens.token(primaryFromAlias));
} else {
throw new IllegalStateException("No primary alias present");
}
} else {
builder.append(QueryTokens.token(countProjection));

View File

@@ -29,9 +29,10 @@ import java.util.Objects;
import java.util.function.Supplier;
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.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -364,8 +365,7 @@ public final class JpqlQueryBuilder {
};
}
@Nullable
public static Predicate and(List<Predicate> intermediate) {
public static @Nullable Predicate and(List<Predicate> intermediate) {
Predicate predicate = null;
@@ -381,8 +381,7 @@ public final class JpqlQueryBuilder {
return predicate;
}
@Nullable
public static Predicate or(List<Predicate> intermediate) {
public static @Nullable Predicate or(List<Predicate> intermediate) {
Predicate predicate = null;
@@ -784,8 +783,7 @@ public final class JpqlQueryBuilder {
return this;
}
@Nullable
public Predicate getWhere() {
public @Nullable Predicate getWhere() {
return where;
}

View File

@@ -21,7 +21,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* {@link ParsedQueryIntrospector} for JPQL queries.

View File

@@ -20,9 +20,10 @@ import static org.springframework.data.jpa.repository.query.QueryTokens.*;
import java.util.List;
import org.springframework.data.domain.Sort;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**

View File

@@ -26,7 +26,8 @@ import jakarta.persistence.metamodel.PluralAttribute;
import java.util.Objects;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils;
/**
@@ -34,12 +35,12 @@ import org.springframework.util.StringUtils;
*/
class JpqlUtils {
static JpqlQueryBuilder.PathExpression toExpressionRecursively(Metamodel metamodel, JpqlQueryBuilder.Origin source,
static JpqlQueryBuilder.PathExpression toExpressionRecursively(@Nullable Metamodel metamodel, JpqlQueryBuilder.Origin source,
Bindable<?> from, PropertyPath property) {
return toExpressionRecursively(metamodel, source, from, property, false);
}
static JpqlQueryBuilder.PathExpression toExpressionRecursively(Metamodel metamodel, JpqlQueryBuilder.Origin source,
static JpqlQueryBuilder.PathExpression toExpressionRecursively(@Nullable Metamodel metamodel, JpqlQueryBuilder.Origin source,
Bindable<?> from, PropertyPath property, boolean isForSelection) {
return toExpressionRecursively(metamodel, source, from, property, isForSelection, false);
}
@@ -53,7 +54,7 @@ class JpqlUtils {
* @param hasRequiredOuterJoin has a parent already required an outer join?
* @return the expression
*/
static JpqlQueryBuilder.PathExpression toExpressionRecursively(Metamodel metamodel, JpqlQueryBuilder.Origin source,
static JpqlQueryBuilder.PathExpression toExpressionRecursively(@Nullable Metamodel metamodel, JpqlQueryBuilder.Origin source,
Bindable<?> from, PropertyPath property, boolean isForSelection, boolean hasRequiredOuterJoin) {
String segment = property.getSegment();
@@ -80,6 +81,10 @@ class JpqlUtils {
ManagedType<?> managedTypeForModel = QueryUtils.getManagedTypeForModel(from);
Attribute<?, ?> nextAttribute = getModelForPath(metamodel, property, managedTypeForModel, from);
if(nextAttribute == null) {
throw new IllegalStateException("Binding property is null");
}
return toExpressionRecursively(metamodel, joinSource, (Bindable<?>) nextAttribute, nextProperty, isForSelection,
requiresOuterJoin);
}
@@ -96,7 +101,7 @@ class JpqlUtils {
* @param hasRequiredOuterJoin
* @return
*/
static boolean requiresOuterJoin(Metamodel metamodel, Bindable<?> bindable, PropertyPath propertyPath,
static boolean requiresOuterJoin(@Nullable Metamodel metamodel, Bindable<?> bindable, PropertyPath propertyPath,
boolean isForSelection, boolean hasRequiredOuterJoin) {
ManagedType<?> managedType = QueryUtils.getManagedTypeForModel(bindable);
@@ -127,8 +132,7 @@ class JpqlUtils {
return hasRequiredOuterJoin || QueryUtils.getAnnotationProperty(attribute, "optional", true);
}
@Nullable
private static Attribute<?, ?> getModelForPath(Metamodel metamodel, PropertyPath path,
private static @Nullable Attribute<?, ?> getModelForPath(@Nullable Metamodel metamodel, PropertyPath path,
@Nullable ManagedType<?> managedType, Bindable<?> fallback) {
String segment = path.getSegment();
@@ -140,11 +144,14 @@ class JpqlUtils {
}
}
Class<?> fallbackType = fallback.getBindableJavaType();
try {
return metamodel.managedType(fallbackType).getAttribute(segment);
} catch (IllegalArgumentException e) {
if(metamodel != null) {
Class<?> fallbackType = fallback.getBindableJavaType();
try {
return metamodel.managedType(fallbackType).getAttribute(segment);
} catch (IllegalArgumentException e) {
// nothing to do here
}
}
return null;

View File

@@ -23,11 +23,12 @@ import java.util.List;
import java.util.Map;
import org.springframework.data.domain.KeysetScrollPosition;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.ScrollPosition.Direction;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.lang.Nullable;
/**
* Delegate for keyset scrolling.
@@ -69,8 +70,7 @@ public class KeysetScrollDelegate {
return properties;
}
@Nullable
public <E, P> P createPredicate(KeysetScrollPosition keyset, Sort sort, QueryStrategy<E, P> strategy) {
public <E, P> @Nullable P createPredicate(KeysetScrollPosition keyset, Sort sort, QueryStrategy<E, P> strategy) {
Map<String, Object> keysetValues = keyset.getKeys();
@@ -207,16 +207,16 @@ public class KeysetScrollDelegate {
*
* @param order must not be {@literal null}.
* @param propertyExpression must not be {@literal null}.
* @param value the value to compare with. Must not be {@literal null}.
* @param value the value to compare with. Can be {@literal null}.
* @return an object representing the comparison predicate.
*/
P compare(Order order, E propertyExpression, Object value);
P compare(Order order, E propertyExpression, @Nullable Object value);
/**
* Create an equals-comparison object.
*
* @param propertyExpression must not be {@literal null}.
* @param value the value to compare with. Must not be {@literal null}.
* @param value the value to compare with. Can be {@literal null}.
* @return an object representing the comparison predicate.
*/
P compare(E propertyExpression, @Nullable Object value);
@@ -227,7 +227,7 @@ public class KeysetScrollDelegate {
* @param intermediate the predicates to combine. Must not be {@literal null}.
* @return a single predicate.
*/
P and(List<P> intermediate);
@Nullable P and(List<P> intermediate);
/**
* OR-combine the {@code intermediate} predicates.
@@ -235,7 +235,7 @@ public class KeysetScrollDelegate {
* @param intermediate the predicates to combine. Must not be {@literal null}.
* @return a single predicate.
*/
P or(List<P> intermediate);
@Nullable P or(List<P> intermediate);
}
}

View File

@@ -27,13 +27,14 @@ import jakarta.persistence.metamodel.Metamodel;
import java.util.List;
import org.springframework.data.domain.KeysetScrollPosition;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.query.KeysetScrollDelegate.QueryStrategy;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.lang.Nullable;
/**
* {@link Specification} to create scroll queries using keyset-scrolling.
@@ -67,19 +68,18 @@ public record KeysetScrollSpecification<T>(KeysetScrollPosition position, Sort s
}
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
public @Nullable Predicate toPredicate(Root<T> root, @Nullable CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
return createPredicate(root, criteriaBuilder);
}
@Nullable
public Predicate createPredicate(Root<?> root, CriteriaBuilder criteriaBuilder) {
public @Nullable Predicate createPredicate(Root<?> root, CriteriaBuilder criteriaBuilder) {
KeysetScrollDelegate delegate = KeysetScrollDelegate.of(position.getDirection());
return delegate.createPredicate(position, sort, new CriteriaBuilderStrategy(root, criteriaBuilder));
}
@Nullable
public JpqlQueryBuilder.Predicate createJpqlPredicate(Bindable<?> from, JpqlQueryBuilder.Entity entity,
public JpqlQueryBuilder.@Nullable Predicate createJpqlPredicate(Bindable<?> from, JpqlQueryBuilder.Entity entity,
ParameterFactory factory) {
KeysetScrollDelegate delegate = KeysetScrollDelegate.of(position.getDirection());
@@ -106,10 +106,14 @@ public record KeysetScrollSpecification<T>(KeysetScrollPosition position, Sort s
}
@Override
public Predicate compare(Order order, Expression<Comparable> propertyExpression, Object value) {
public Predicate compare(Order order, Expression<Comparable> propertyExpression, @Nullable Object value) {
if(value instanceof Comparable compareValue) {
return order.isAscending() ? cb.greaterThan(propertyExpression, compareValue)
: cb.lessThan(propertyExpression, compareValue);
}
return order.isAscending() ? cb.isNull(propertyExpression) : cb.isNotNull(propertyExpression);
return order.isAscending() ? cb.greaterThan(propertyExpression, (Comparable) value)
: cb.lessThan(propertyExpression, (Comparable) value);
}
@Override
@@ -133,9 +137,9 @@ public record KeysetScrollSpecification<T>(KeysetScrollPosition position, Sort s
private final Bindable<?> from;
private final JpqlQueryBuilder.Entity entity;
private final ParameterFactory factory;
private final Metamodel metamodel;
private final @Nullable Metamodel metamodel;
public JpqlStrategy(Metamodel metamodel, Bindable<?> from, JpqlQueryBuilder.Entity entity, ParameterFactory factory) {
public JpqlStrategy(@Nullable Metamodel metamodel, Bindable<?> from, JpqlQueryBuilder.Entity entity, ParameterFactory factory) {
this.from = from;
this.entity = entity;
@@ -152,9 +156,12 @@ public record KeysetScrollSpecification<T>(KeysetScrollPosition position, Sort s
@Override
public JpqlQueryBuilder.Predicate compare(Order order, JpqlQueryBuilder.Expression propertyExpression,
Object value) {
@Nullable Object value) {
JpqlQueryBuilder.WhereStep where = JpqlQueryBuilder.where(propertyExpression);
if(value == null) {
return order.isAscending() ? where.isNull() : where.isNotNull();
}
return order.isAscending() ? where.gt(factory.capture(value)) : where.lt(factory.capture(value));
}
@@ -167,12 +174,12 @@ public record KeysetScrollSpecification<T>(KeysetScrollPosition position, Sort s
}
@Override
public JpqlQueryBuilder.Predicate and(List<JpqlQueryBuilder.Predicate> intermediate) {
public JpqlQueryBuilder.@Nullable Predicate and(List<JpqlQueryBuilder.Predicate> intermediate) {
return JpqlQueryBuilder.and(intermediate);
}
@Override
public JpqlQueryBuilder.Predicate or(List<JpqlQueryBuilder.Predicate> intermediate) {
public JpqlQueryBuilder.@Nullable Predicate or(List<JpqlQueryBuilder.Predicate> intermediate) {
return JpqlQueryBuilder.or(intermediate);
}
}

View File

@@ -19,8 +19,9 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils;
/**
@@ -69,8 +70,7 @@ public class Meta {
/**
* @return {@literal null} if not set.
*/
@Nullable
public String getComment() {
public @Nullable String getComment() {
return getValue(MetaKey.COMMENT.key);
}
@@ -106,9 +106,8 @@ public class Meta {
this.values.put(key, value);
}
@Nullable
@SuppressWarnings("unchecked")
private <T> T getValue(String key) {
private <T> @Nullable T getValue(String key) {
return (T) this.values.get(key);
}

View File

@@ -22,6 +22,7 @@ import jakarta.persistence.TypedQuery;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@@ -33,7 +34,6 @@ import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.util.Lazy;
import org.springframework.lang.Nullable;
/**
* Implementation of {@link RepositoryQuery} based on {@link jakarta.persistence.NamedQuery}s.
@@ -132,8 +132,8 @@ final class NamedQuery extends AbstractJpaQuery {
* @param em must not be {@literal null}.
* @param queryRewriter must not be {@literal null}.
*/
@Nullable
public static RepositoryQuery lookupFrom(JpaQueryMethod method, EntityManager em, QueryRewriter queryRewriter) {
public static @Nullable RepositoryQuery lookupFrom(JpaQueryMethod method, EntityManager em,
QueryRewriter queryRewriter) {
String queryName = method.getNamedQueryName();
@@ -198,7 +198,7 @@ final class NamedQuery extends AbstractJpaQuery {
}
@Override
protected Class<?> getTypeToRead(ReturnedType returnedType) {
protected @Nullable Class<?> getTypeToRead(ReturnedType returnedType) {
if (getQueryMethod().isNativeQuery()) {

View File

@@ -20,6 +20,8 @@ import jakarta.persistence.Query;
import jakarta.persistence.Tuple;
import org.springframework.core.annotation.MergedAnnotation;
import org.jspecify.annotations.Nullable;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
@@ -28,7 +30,6 @@ import org.springframework.data.jpa.repository.QueryRewriter;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.ValueExpressionDelegate;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
@@ -71,7 +72,7 @@ final class NativeJpaQuery extends AbstractStringBasedJpaQuery {
}
@Override
protected Query createJpaQuery(String queryString, Sort sort, Pageable pageable, ReturnedType returnedType) {
protected Query createJpaQuery(String queryString, Sort sort, @Nullable Pageable pageable, ReturnedType returnedType) {
EntityManager em = getEntityManager();
String query = potentiallyRewriteQuery(queryString, sort, pageable);
@@ -84,8 +85,7 @@ final class NativeJpaQuery extends AbstractStringBasedJpaQuery {
return type == null ? em.createNativeQuery(query) : em.createNativeQuery(query, type);
}
@Nullable
private Class<?> getTypeToQueryFor(ReturnedType returnedType) {
private @Nullable Class<?> getTypeToQueryFor(ReturnedType returnedType) {
Class<?> result = queryForEntity ? returnedType.getDomainType() : null;

View File

@@ -26,12 +26,14 @@ import java.util.List;
import java.util.stream.Collectors;
import org.springframework.data.expression.ValueExpression;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.repository.support.JpqlQueryTemplates;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.Part.Type;
import org.springframework.lang.Nullable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
@@ -75,8 +77,7 @@ class ParameterBinding {
/**
* @return the name if available or {@literal null}.
*/
@Nullable
public String getName() {
public @Nullable String getName() {
return identifier.hasName() ? identifier.getName() : null;
}
@@ -150,8 +151,7 @@ class ParameterBinding {
/**
* @param valueToBind value to prepare
*/
@Nullable
public Object prepare(@Nullable Object valueToBind) {
public @Nullable Object prepare(@Nullable Object valueToBind) {
return valueToBind;
}
@@ -234,7 +234,7 @@ class ParameterBinding {
}
@Override
public Object prepare(@Nullable Object value) {
public @Nullable Object prepare(@Nullable Object value) {
if (value == null || parameterType == null) {
return value;
@@ -255,9 +255,10 @@ class ParameterBinding {
: value;
}
@Nullable
@SuppressWarnings("unchecked")
private Collection<?> potentiallyIgnoreCase(boolean ignoreCase, @Nullable Collection<?> collection) {
@Contract("false, _ -> param2; _, null -> null; true, !null -> new)")
private @Nullable Collection<?> potentiallyIgnoreCase(boolean ignoreCase, @Nullable Collection<?> collection) {
if (!ignoreCase || CollectionUtils.isEmpty(collection)) {
return collection;
@@ -278,8 +279,7 @@ class ParameterBinding {
* @param value the value to be converted to a {@link Collection}.
* @return the object itself as a {@link Collection} or a {@link Collection} constructed from the value.
*/
@Nullable
private static Collection<?> toCollection(@Nullable Object value) {
private static @Nullable Collection<?> toCollection(@Nullable Object value) {
if (value == null) {
return null;
@@ -316,7 +316,7 @@ class ParameterBinding {
}
@Override
public Object prepare(@Nullable Object value) {
public @Nullable Object prepare(@Nullable Object value) {
if (!ObjectUtils.isArray(value)) {
return value;
@@ -378,9 +378,8 @@ class ParameterBinding {
/**
* Extracts the raw value properly.
*/
@Nullable
@Override
public Object prepare(@Nullable Object value) {
public @Nullable Object prepare(@Nullable Object value) {
Object unwrapped = PersistenceProvider.unwrapTypedParameterValue(value);
if (unwrapped == null) {
@@ -657,8 +656,10 @@ class ParameterBinding {
identifier = BindingIdentifier.of(name, position);
} else if (!ObjectUtils.isEmpty(name)) {
identifier = BindingIdentifier.of(name);
} else {
} else if (position != null) {
identifier = BindingIdentifier.of(position);
} else {
throw new IllegalStateException("Neither name nor position available for binding");
}
return ofParameter(identifier);

View File

@@ -28,6 +28,8 @@ import java.util.List;
import java.util.stream.Collectors;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.jspecify.annotations.Nullable;
import org.springframework.data.jpa.repository.support.JpqlQueryTemplates;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.Parameters;
@@ -36,7 +38,6 @@ import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.Part.IgnoreCaseType;
import org.springframework.data.repository.query.parser.Part.Type;
import org.springframework.expression.Expression;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
@@ -264,8 +265,7 @@ public class ParameterMetadataProvider {
*
* @param value can be {@literal null}.
*/
@Nullable
public Object prepare(@Nullable Object value) {
public @Nullable Object prepare(@Nullable Object value) {
if (value == null || parameterType == null) {
return value;
@@ -294,8 +294,7 @@ public class ParameterMetadataProvider {
* @param value the value to be converted to a {@link Collection}.
* @return the object itself as a {@link Collection} or a {@link Collection} constructed from the value.
*/
@Nullable
private static Collection<?> toCollection(@Nullable Object value) {
private static @Nullable Collection<?> toCollection(@Nullable Object value) {
if (value == null) {
return null;
@@ -314,9 +313,8 @@ public class ParameterMetadataProvider {
return Collections.singleton(value);
}
@Nullable
@SuppressWarnings("unchecked")
private Collection<?> potentiallyIgnoreCase(boolean ignoreCase, @Nullable Collection<?> collection) {
private @Nullable Collection<?> potentiallyIgnoreCase(boolean ignoreCase, @Nullable Collection<?> collection) {
if (!ignoreCase || CollectionUtils.isEmpty(collection)) {
return collection;

View File

@@ -24,6 +24,7 @@ import jakarta.persistence.criteria.CriteriaQuery;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -43,7 +44,6 @@ import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.Part.Type;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.data.util.Streamable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -246,7 +246,7 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
* Restricts the max results of the given {@link Query} if the current {@code tree} marks this {@code query} as
* limited.
*/
@SuppressWarnings("ConstantConditions")
@SuppressWarnings({ "ConstantConditions", "NullAway" })
private Query restrictMaxResultsIfNecessary(Query query, @Nullable ScrollPosition scrollPosition) {
if (scrollPosition instanceof OffsetScrollPosition offset && !offset.isInitial()) {

View File

@@ -22,7 +22,8 @@ import java.util.Map;
import java.util.Objects;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.ObjectUtils;
/**

View File

@@ -20,7 +20,7 @@ import jakarta.persistence.ParameterMode;
import java.util.Objects;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* This class represents a Stored Procedure Parameter and an instance of the annotation

View File

@@ -18,8 +18,9 @@ package org.springframework.data.jpa.repository.query;
import java.util.Set;
import org.springframework.data.domain.Sort;
import org.jspecify.annotations.Nullable;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.lang.Nullable;
/**
* This interface describes the API for enhancing a given Query.

View File

@@ -17,7 +17,7 @@ package org.springframework.data.jpa.repository.query;
import java.util.List;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* Value object capturing introspection details of a parsed query.
@@ -44,8 +44,7 @@ class QueryInformation {
*
* @return
*/
@Nullable
public String getAlias() {
public @Nullable String getAlias() {
return alias;
}

View File

@@ -29,8 +29,8 @@ import java.util.function.Function;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ErrorHandler;

View File

@@ -21,6 +21,8 @@ import jakarta.persistence.TemporalType;
import java.util.function.Function;
import org.springframework.data.expression.ValueEvaluationContext;
import org.jspecify.annotations.Nullable;
import org.springframework.data.expression.ValueEvaluationContextProvider;
import org.springframework.data.expression.ValueExpression;
import org.springframework.data.expression.ValueExpressionParser;
@@ -32,7 +34,6 @@ import org.springframework.data.repository.query.Parameters;
import org.springframework.data.spel.EvaluationContextProvider;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -53,8 +54,7 @@ abstract class QueryParameterSetterFactory {
* @param binding the parameter binding to create a {@link QueryParameterSetter} for.
* @return
*/
@Nullable
abstract QueryParameterSetter create(ParameterBinding binding);
abstract @Nullable QueryParameterSetter create(ParameterBinding binding);
/**
* Creates a new {@link QueryParameterSetterFactory} for the given {@link JpaParameters}.
@@ -109,7 +109,7 @@ abstract class QueryParameterSetterFactory {
* @param binding the binding of the query parameter to be set.
* @param parameter the method parameter to bind.
*/
private static QueryParameterSetter createSetter(Function<JpaParametersParameterAccessor, Object> valueExtractor,
private static QueryParameterSetter createSetter(Function<JpaParametersParameterAccessor, @Nullable Object> valueExtractor,
ParameterBinding binding, @Nullable JpaParameter parameter) {
TemporalType temporalType = parameter != null && parameter.isTemporalParameter() //
@@ -120,8 +120,7 @@ abstract class QueryParameterSetterFactory {
ParameterImpl.of(parameter, binding), temporalType);
}
@Nullable
static JpaParameter findParameterForBinding(Parameters<JpaParameters, JpaParameter> parameters, String name) {
static @Nullable JpaParameter findParameterForBinding(Parameters<JpaParameters, JpaParameter> parameters, String name) {
JpaParameters bindableParameters = parameters.getBindableParameters();
@@ -180,9 +179,8 @@ abstract class QueryParameterSetterFactory {
this.evaluationContextProvider = evaluationContextProvider;
}
@Nullable
@Override
public QueryParameterSetter create(ParameterBinding binding) {
public @Nullable QueryParameterSetter create(ParameterBinding binding) {
if (!(binding.getOrigin() instanceof ParameterBinding.Expression e)) {
return null;
@@ -198,8 +196,7 @@ abstract class QueryParameterSetterFactory {
* @param accessor must not be {@literal null}.
* @return the result of the evaluation.
*/
@Nullable
private Object evaluateExpression(ValueExpression expression, JpaParametersParameterAccessor accessor) {
private @Nullable Object evaluateExpression(ValueExpression expression, JpaParametersParameterAccessor accessor) {
ValueEvaluationContext evaluationContext = evaluationContextProvider.getEvaluationContext(accessor.getValues());
return expression.evaluate(evaluationContext);
@@ -215,7 +212,7 @@ abstract class QueryParameterSetterFactory {
private static class SyntheticParameterSetterFactory extends QueryParameterSetterFactory {
@Override
public QueryParameterSetter create(ParameterBinding binding) {
public @Nullable QueryParameterSetter create(ParameterBinding binding) {
if (!(binding.getOrigin() instanceof ParameterBinding.Synthetic s)) {
return null;
@@ -251,7 +248,7 @@ abstract class QueryParameterSetterFactory {
}
@Override
public QueryParameterSetter create(ParameterBinding binding) {
public @Nullable QueryParameterSetter create(ParameterBinding binding) {
Assert.notNull(binding, "Binding must not be null");
@@ -276,8 +273,7 @@ abstract class QueryParameterSetterFactory {
: createSetter(values -> getValue(values, parameter), binding, parameter);
}
@Nullable
protected Object getValue(JpaParametersParameterAccessor accessor, Parameter parameter) {
protected @Nullable Object getValue(JpaParametersParameterAccessor accessor, Parameter parameter) {
return accessor.getValue(parameter);
}
}
@@ -298,7 +294,7 @@ abstract class QueryParameterSetterFactory {
}
@Override
public QueryParameterSetter create(ParameterBinding binding) {
public @Nullable QueryParameterSetter create(ParameterBinding binding) {
if (!binding.getOrigin().isMethodArgument()) {
return null;
@@ -352,15 +348,13 @@ abstract class QueryParameterSetterFactory {
this.parameterType = parameterType;
}
@Nullable
@Override
public String getName() {
public @Nullable String getName() {
return identifier.hasName() ? identifier.getName() : null;
}
@Nullable
@Override
public Integer getPosition() {
public @Nullable Integer getPosition() {
return identifier.hasPosition() ? identifier.getPosition() : null;
}

View File

@@ -22,9 +22,10 @@ import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;
import org.springframework.lang.Nullable;
import org.springframework.util.CompositeIterator;
import org.jspecify.annotations.Nullable;
/**
* Abstraction to encapsulate query expressions and render a query.
* <p>
@@ -271,8 +272,7 @@ abstract class QueryRenderer implements QueryTokenStream {
}
@Override
@Nullable
public QueryToken getLast() {
public @Nullable QueryToken getLast() {
for (int i = nested.size() - 1; i > -1; i--) {
@@ -368,14 +368,12 @@ abstract class QueryRenderer implements QueryTokenStream {
}
@Override
@Nullable
public QueryToken getFirst() {
public @Nullable QueryToken getFirst() {
return tokens.isEmpty() ? null : tokens.get(0);
}
@Override
@Nullable
public QueryToken getLast() {
public @Nullable QueryToken getLast() {
return tokens.isEmpty() ? null : tokens.get(tokens.size() - 1);
}
@@ -438,14 +436,12 @@ abstract class QueryRenderer implements QueryTokenStream {
}
@Override
@Nullable
public QueryToken getFirst() {
public @Nullable QueryToken getFirst() {
return tokens.getFirst();
}
@Override
@Nullable
public QueryToken getLast() {
public @Nullable QueryToken getLast() {
return tokens.getLast();
}
@@ -574,14 +570,12 @@ abstract class QueryRenderer implements QueryTokenStream {
}
@Override
@Nullable
public QueryToken getFirst() {
public @Nullable QueryToken getFirst() {
return current.getFirst();
}
@Override
@Nullable
public QueryToken getLast() {
public @Nullable QueryToken getLast() {
return current.getLast();
}
@@ -645,14 +639,12 @@ abstract class QueryRenderer implements QueryTokenStream {
}
@Override
@Nullable
public QueryToken getFirst() {
public @Nullable QueryToken getFirst() {
return delegate.getFirst();
}
@Override
@Nullable
public QueryToken getLast() {
public @Nullable QueryToken getLast() {
return delegate.getLast();
}
@@ -701,14 +693,12 @@ abstract class QueryRenderer implements QueryTokenStream {
}
@Override
@Nullable
public QueryToken getFirst() {
public @Nullable QueryToken getFirst() {
return delegate.getFirst();
}
@Override
@Nullable
public QueryToken getLast() {
public @Nullable QueryToken getLast() {
return delegate.getLast();
}

View File

@@ -23,9 +23,9 @@ import java.util.function.Function;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.jspecify.annotations.Nullable;
import org.springframework.data.util.Streamable;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
/**
@@ -142,8 +142,7 @@ interface QueryTokenStream extends Streamable<QueryToken> {
/**
* @return the first query token or {@code null} if empty.
*/
@Nullable
default QueryToken getFirst() {
default @Nullable QueryToken getFirst() {
Iterator<QueryToken> it = iterator();
return it.hasNext() ? it.next() : null;
@@ -167,8 +166,7 @@ interface QueryTokenStream extends Streamable<QueryToken> {
/**
* @return the last query token or {@code null} if empty.
*/
@Nullable
default QueryToken getLast() {
default @Nullable QueryToken getLast() {
return CollectionUtils.lastElement(toList());
}

View File

@@ -47,13 +47,14 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.springframework.core.annotation.AnnotationUtils;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.JpaSort.JpaOrder;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.util.Streamable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -446,9 +447,8 @@ public abstract class QueryUtils {
* @return Might return {@literal null}.
* @deprecated use {@link DeclaredQuery#getAlias()} instead.
*/
@Nullable
@Deprecated
public static String detectAlias(String query) {
public static @Nullable String detectAlias(String query) {
String alias = null;
Matcher matcher = ALIAS_MATCH.matcher(removeSubqueries(query));
@@ -859,6 +859,7 @@ public abstract class QueryUtils {
return hasRequiredOuterJoin || getAnnotationProperty(attribute, "optional", true);
}
@SuppressWarnings("unchecked")
static <T> T getAnnotationProperty(Attribute<?, ?> attribute, String propertyName, T defaultValue) {
Class<? extends Annotation> associationAnnotation = ASSOCIATION_TYPES.get(attribute.getPersistentAttributeType());
@@ -874,7 +875,12 @@ public abstract class QueryUtils {
}
Annotation annotation = AnnotationUtils.getAnnotation(annotatedMember, associationAnnotation);
return annotation == null ? defaultValue : (T) AnnotationUtils.getValue(annotation, propertyName);
if(annotation == null) {
return defaultValue;
}
T value = (T) AnnotationUtils.getValue(annotation, propertyName);
return value != null ? value : defaultValue;
}
/**
@@ -962,8 +968,7 @@ public abstract class QueryUtils {
* @see <a href=
* "https://github.com/jakartaee/persistence/issues/562">https://github.com/jakartaee/persistence/issues/562</a>
*/
@Nullable
private static Bindable<?> getModelForPath(PropertyPath path, @Nullable ManagedType<?> managedType,
private static @Nullable Bindable<?> getModelForPath(PropertyPath path, @Nullable ManagedType<?> managedType,
Path<?> fallback) {
String segment = path.getSegment();
@@ -987,8 +992,7 @@ public abstract class QueryUtils {
* @param model
* @return
*/
@Nullable
static ManagedType<?> getManagedTypeForModel(Bindable<?> model) {
static @Nullable ManagedType<?> getManagedTypeForModel(Bindable<?> model) {
if (model instanceof ManagedType<?> managedType) {
return managedType;

View File

@@ -19,9 +19,10 @@ import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import org.springframework.data.jpa.repository.QueryRewriter;
import org.jspecify.annotations.Nullable;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ValueExpressionDelegate;
import org.springframework.lang.Nullable;
/**
* {@link RepositoryQuery} implementation that inspects a {@link org.springframework.data.repository.query.QueryMethod}

View File

@@ -27,7 +27,8 @@ import java.util.Collections;
import java.util.List;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -174,8 +175,7 @@ enum StoredProcedureAttributeSource {
* @param procedure must not be {@literal null}.
* @return
*/
@Nullable
private NamedStoredProcedureQuery tryFindAnnotatedNamedStoredProcedureQuery(Method method,
private @Nullable NamedStoredProcedureQuery tryFindAnnotatedNamedStoredProcedureQuery(Method method,
JpaEntityMetadata<?> entityMetadata, Procedure procedure) {
Assert.notNull(method, "Method must not be null");

View File

@@ -22,6 +22,7 @@ import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@@ -93,7 +94,7 @@ class StoredProcedureAttributes {
parameter.getType());
}
private String completeOutputParameterName(int i, String paramName) {
private String completeOutputParameterName(int i, @Nullable String paramName) {
return StringUtils.hasText(paramName) //
? paramName //

View File

@@ -26,9 +26,10 @@ import java.util.List;
import java.util.Map;
import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter;
import org.jspecify.annotations.Nullable;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

View File

@@ -30,6 +30,8 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.data.expression.ValueExpression;
import org.jspecify.annotations.Nullable;
import org.springframework.data.expression.ValueExpressionParser;
import org.springframework.data.jpa.repository.query.ParameterBinding.BindingIdentifier;
import org.springframework.data.jpa.repository.query.ParameterBinding.InParameterBinding;
@@ -38,7 +40,6 @@ import org.springframework.data.jpa.repository.query.ParameterBinding.MethodInvo
import org.springframework.data.jpa.repository.query.ParameterBinding.ParameterOrigin;
import org.springframework.data.repository.query.ValueExpressionQueryRewriter;
import org.springframework.data.repository.query.parser.Part.Type;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
@@ -168,8 +169,7 @@ class StringQuery implements DeclaredQuery {
}
@Override
@Nullable
public String getAlias() {
public @Nullable String getAlias() {
return queryEnhancer.detectAlias();
}
@@ -393,8 +393,10 @@ class StringQuery implements DeclaredQuery {
BindingIdentifier queryParameter;
if (parameterIndex != null) {
queryParameter = BindingIdentifier.of(parameterIndex);
} else {
} else if (parameterName != null) {
queryParameter = BindingIdentifier.of(parameterName);
} else {
throw new IllegalStateException("No bindable expression found");
}
ParameterOrigin origin = ObjectUtils.isEmpty(expression)
? ParameterOrigin.ofParameter(parameterName, parameterIndex)
@@ -458,8 +460,7 @@ class StringQuery implements DeclaredQuery {
return rewriter.parse(queryWithSpel);
}
@Nullable
private static Integer getParameterIndex(@Nullable String parameterIndexString) {
private static @Nullable Integer getParameterIndex(@Nullable String parameterIndexString) {
if (parameterIndexString == null || parameterIndexString.isEmpty()) {
return null;
@@ -519,8 +520,7 @@ class StringQuery implements DeclaredQuery {
*
* @return the keyword
*/
@Nullable
public String getKeyword() {
public @Nullable String getKeyword() {
return keyword;
}

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