Skip to content

Apply Nullability to spring-integration-jpa #10157

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/**
* Provides parser classes to provide Xml namespace support for the Jpa components.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.integration.jpa.config.xml;
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@

package org.springframework.integration.jpa.core;

import java.util.Objects;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.jspecify.annotations.Nullable;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.orm.jpa.SharedEntityManagerCreator;
Expand All @@ -32,17 +35,17 @@
*/
abstract class AbstractJpaOperations implements JpaOperations, InitializingBean {

private EntityManager entityManager;
private @Nullable EntityManager entityManager;

private EntityManagerFactory entityManagerFactory;
private @Nullable EntityManagerFactory entityManagerFactory;

public void setEntityManager(EntityManager entityManager) {
Assert.notNull(entityManager, "The provided entityManager must not be null.");
this.entityManager = entityManager;
}

protected EntityManager getEntityManager() {
return this.entityManager;
return Objects.requireNonNull(this.entityManager);
}

public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
Expand Down Expand Up @@ -72,7 +75,7 @@ protected void onInit() {

@Override
public void flush() {
this.entityManager.flush();
Objects.requireNonNull(this.entityManager).flush();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
import jakarta.persistence.EntityManager;
import jakarta.persistence.Parameter;
import jakarta.persistence.Query;
import org.jspecify.annotations.Nullable;

import org.springframework.core.log.LogAccessor;
import org.springframework.integration.jpa.support.JpaUtils;
import org.springframework.integration.jpa.support.parametersource.ParameterSource;
import org.springframework.integration.jpa.support.parametersource.PositionSupportingParameterSource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

Expand Down Expand Up @@ -74,7 +74,7 @@ public void deleteInBatch(Iterable<?> entities) {
}
}
}

Assert.state(entityClass != null, "'entityClass' must not be null");
EntityManager entityManager = getEntityManager();
final String entityName = JpaUtils.getEntityName(entityManager, entityClass);
final String queryString = JpaUtils.getQueryString(JpaUtils.DELETE_ALL_QUERY_STRING, entityName);
Expand All @@ -85,21 +85,21 @@ public void deleteInBatch(Iterable<?> entities) {
}

@Override
public int executeUpdate(String updateQuery, ParameterSource source) {
public int executeUpdate(String updateQuery, @Nullable ParameterSource source) {
Query query = getEntityManager().createQuery(updateQuery);
setParametersIfRequired(updateQuery, source, query);
return query.executeUpdate();
}

@Override
public int executeUpdateWithNamedQuery(String updateQuery, ParameterSource source) {
public int executeUpdateWithNamedQuery(String updateQuery, @Nullable ParameterSource source) {
Query query = getEntityManager().createNamedQuery(updateQuery);
setParametersIfRequired(updateQuery, source, query);
return query.executeUpdate();
}

@Override
public int executeUpdateWithNativeQuery(String updateQuery, ParameterSource source) {
public int executeUpdateWithNativeQuery(String updateQuery, @Nullable ParameterSource source) {
Query query = getEntityManager().createNativeQuery(updateQuery);
setParametersIfRequired(updateQuery, source, query);
return query.executeUpdate();
Expand All @@ -110,7 +110,7 @@ public <T> T find(Class<T> entityType, Object id) {
return getEntityManager().find(entityType, id);
}

private Query getQuery(String queryString, ParameterSource source) {
private Query getQuery(String queryString, @Nullable ParameterSource source) {
Query query = getEntityManager().createQuery(queryString);
setParametersIfRequired(queryString, source, query);
return query;
Expand All @@ -134,7 +134,7 @@ public List<?> getResultListForClass(Class<?> entityClass, int firstResult, int

@Override
public List<?> getResultListForNamedQuery(String selectNamedQuery,
ParameterSource parameterSource, int firstResult, int maxNumberOfResults) {
@Nullable ParameterSource parameterSource, int firstResult, int maxNumberOfResults) {

final Query query = getEntityManager().createNamedQuery(selectNamedQuery);
setParametersIfRequired(selectNamedQuery, parameterSource, query);
Expand All @@ -152,7 +152,7 @@ public List<?> getResultListForNamedQuery(String selectNamedQuery,

@Override
public List<?> getResultListForNativeQuery(String selectQuery, @Nullable Class<?> entityClass,
ParameterSource parameterSource, int firstResult, int maxNumberOfResults) {
@Nullable ParameterSource parameterSource, int firstResult, int maxNumberOfResults) {

final Query query;

Expand Down Expand Up @@ -181,7 +181,7 @@ public List<?> getResultListForQuery(String query, ParameterSource source) {
}

@Override
public List<?> getResultListForQuery(String queryString, ParameterSource source,
public List<?> getResultListForQuery(String queryString, @Nullable ParameterSource source,
int firstResult, int maxNumberOfResults) {

Query query = getQuery(queryString, source);
Expand Down Expand Up @@ -266,7 +266,7 @@ private Object persistOrMergeIterable(Object entity, boolean isMerge, int flushS
List<Object> mergedEntities = new ArrayList<>();

EntityManager entityManager = getEntityManager();
for (Object iteratedEntity : entities) {
for (@Nullable Object iteratedEntity : entities) {
if (iteratedEntity == null) {
nullEntities.incrementAndGet();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.jspecify.annotations.Nullable;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
Expand All @@ -35,7 +36,6 @@
import org.springframework.integration.jpa.support.parametersource.ExpressionEvaluatingParameterSourceFactory;
import org.springframework.integration.jpa.support.parametersource.ParameterSource;
import org.springframework.integration.jpa.support.parametersource.ParameterSourceFactory;
import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
import org.springframework.util.Assert;
Expand Down Expand Up @@ -71,27 +71,27 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware {

private final JpaOperations jpaOperations;

private List<JpaParameter> jpaParameters;
private @Nullable List<JpaParameter> jpaParameters;

private Class<?> entityClass;
private @Nullable Class<?> entityClass;

private String jpaQuery;
private @Nullable String jpaQuery;

private String nativeQuery;
private @Nullable String nativeQuery;

private String namedQuery;
private @Nullable String namedQuery;

private Expression maxResultsExpression;
private @Nullable Expression maxResultsExpression;

private Expression firstResultExpression;
private @Nullable Expression firstResultExpression;

private Expression idExpression;
private @Nullable Expression idExpression;

private PersistMode persistMode = PersistMode.MERGE;

private ParameterSourceFactory parameterSourceFactory = null;
private @Nullable ParameterSourceFactory parameterSourceFactory = null;

private ParameterSource parameterSource;
private @Nullable ParameterSource parameterSource;

private boolean flush = false;

Expand All @@ -111,10 +111,12 @@ public class JpaExecutor implements InitializingBean, BeanFactoryAware {
* default a {@link BeanPropertyParameterSourceFactory} implementation is
* used for the sqlParameterSourceFactory property.
*/
private Boolean usePayloadAsParameterSource = null;
private @Nullable Boolean usePayloadAsParameterSource = null;

@SuppressWarnings("NullAway.Init")
private BeanFactory beanFactory;

@SuppressWarnings("NullAway.Init")
private EvaluationContext evaluationContext;

/**
Expand Down Expand Up @@ -157,6 +159,10 @@ public JpaExecutor(JpaOperations jpaOperations) {
this.jpaOperations = jpaOperations;
}

/**
* @deprecated in favor of the one obtained from the application context.
*/
@Deprecated(since = "7.0", forRemoval = true)
public void setIntegrationEvaluationContext(EvaluationContext evaluationContext) {
this.evaluationContext = evaluationContext;
}
Expand Down Expand Up @@ -398,10 +404,7 @@ public void afterPropertiesSet() {
else if (this.flush) {
this.flushSize = 1;
}

if (this.evaluationContext == null) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it harmful to remove in this version?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so.
This is major version, so we can have some breaking changes.
But I don't see how this one could be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, so instead of depredated method setIntegrationEvaluationContext(), can we simply remove that method?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. We never remove a public API in our classes just because.
Has to be deprecated first.

this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.beanFactory);
}
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.beanFactory);
}

/**
Expand All @@ -414,7 +417,7 @@ else if (this.flush) {
* @return Either the number of affected entities when using a JPQL query.
* When using a merge/persist the updated/inserted itself is returned.
*/
public Object executeOutboundJpaOperation(Message<?> message) {
public @Nullable Object executeOutboundJpaOperation(Message<?> message) {
ParameterSource paramSource = null;
if (this.jpaQuery != null || this.nativeQuery != null || this.namedQuery != null) {
paramSource = determineParameterSource(message);
Expand All @@ -433,7 +436,7 @@ else if (this.namedQuery != null) {
}
}

private Object executeOutboundJpaOperationOnPersistentMode(Message<?> message) {
private @Nullable Object executeOutboundJpaOperationOnPersistentMode(Message<?> message) {
Object payload = message.getPayload();
switch (this.persistMode) {
case PERSIST -> {
Expand Down Expand Up @@ -511,8 +514,9 @@ public Object poll(@Nullable final Message<?> requestMessage) {
payload = result.iterator().next();
}
else {
throw new MessagingException(requestMessage, // NOSONAR
"The Jpa operation returned more than 1 result for expectSingleResult mode.");
String description = "The Jpa operation returned more than 1 result for expectSingleResult mode.";
throw requestMessage == null ? new MessagingException(description)
: new MessagingException(requestMessage, description);
}
}
else {
Expand Down Expand Up @@ -546,7 +550,7 @@ private void checkDelete(@Nullable Object payload) {
}
}

protected List<?> doPoll(ParameterSource jpaQLParameterSource, int firstResult, int maxNumberOfResults) {
protected List<?> doPoll(@Nullable ParameterSource jpaQLParameterSource, int firstResult, int maxNumberOfResults) {
List<?> payload;
if (this.jpaQuery != null) {
payload =
Expand Down Expand Up @@ -609,7 +613,8 @@ else if (evaluationResult instanceof String) {
}

private ParameterSource determineParameterSource(final Message<?> requestMessage) {
if (this.usePayloadAsParameterSource) {
Assert.state(this.parameterSourceFactory != null, "'parameterSourceFactory' must not be null");
if (Boolean.TRUE.equals(this.usePayloadAsParameterSource)) {
return this.parameterSourceFactory.createParameterSource(requestMessage.getPayload());
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@

import java.util.List;

import org.jspecify.annotations.Nullable;

import org.springframework.integration.jpa.support.parametersource.ParameterSource;
import org.springframework.lang.Nullable;

/**
* The Interface containing all the JpaOperations those will be executed by
Expand Down Expand Up @@ -51,26 +52,26 @@ public interface JpaOperations {
* Executes the given update statement and uses the given parameter source to
* set the required query parameters.
* @param updateQuery Must Not be empty.
* @param source Must Not be null.
* @param source Can be null.
* @return The number of entities updated
*/
int executeUpdate(String updateQuery, ParameterSource source);
int executeUpdate(String updateQuery, @Nullable ParameterSource source);

/**
*
* @param updateQuery The update query.
* @param source The parameter source.
* @return The number of entities updated.
*/
int executeUpdateWithNamedQuery(String updateQuery, ParameterSource source);
int executeUpdateWithNamedQuery(String updateQuery, @Nullable ParameterSource source);

/**
*
* @param updateQuery The update query.
* @param source The parameter source.
* @return The number of entities updated
*/
int executeUpdateWithNativeQuery(String updateQuery, ParameterSource source);
int executeUpdateWithNativeQuery(String updateQuery, @Nullable ParameterSource source);

/**
* Find an Entity of given type with the given primary key type.
Expand Down Expand Up @@ -100,7 +101,7 @@ List<?> getResultListForClass(Class<?> entityClass,
* @param maxNumberOfResults The number of objects to return.
* @return The list of found entities.
*/
List<?> getResultListForNamedQuery(String selectNamedQuery, ParameterSource jpaQLParameterSource,
List<?> getResultListForNamedQuery(String selectNamedQuery, @Nullable ParameterSource jpaQLParameterSource,
int firstResult,
int maxNumberOfResults);

Expand All @@ -115,7 +116,7 @@ List<?> getResultListForNamedQuery(String selectNamedQuery, ParameterSource jpaQ
*/
List<?> getResultListForNativeQuery(String selectQuery,
@Nullable Class<?> entityClass,
ParameterSource jpaQLParameterSource,
@Nullable ParameterSource jpaQLParameterSource,
int firstResult,
int maxNumberOfResults);

Expand All @@ -135,7 +136,8 @@ List<?> getResultListForNativeQuery(String selectQuery,
* @param source the Parameter source for this query to be executed, if none then set null.
* @return The list of found entities.
*/
List<?> getResultListForQuery(String query, ParameterSource source, int firstResult, int maxNumberOfResults);
List<?> getResultListForQuery(String query, @Nullable ParameterSource source, int firstResult,
int maxNumberOfResults);

/**
* Execute the provided query to return a single element.
Expand All @@ -155,7 +157,7 @@ List<?> getResultListForNativeQuery(String selectQuery,
* @param entity Must not be null.
* @return The merged managed instance of the entity.
*/
Object merge(Object entity);
@Nullable Object merge(Object entity);

/**
* The entity to be merged with the {@link jakarta.persistence.EntityManager}.
Expand All @@ -174,7 +176,7 @@ List<?> getResultListForNativeQuery(String selectQuery,
* @return The merged object.
*/

Object merge(Object entity, int flushSize, boolean clearOnFlush);
@Nullable Object merge(Object entity, int flushSize, boolean clearOnFlush);

/**
* Persists the entity. The provided object can also be an {@link Iterable}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Provides core classes of the JPA module.
*/
@org.springframework.lang.NonNullApi
@org.jspecify.annotations.NullMarked
package org.springframework.integration.jpa.core;
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/**
* Provides JPA Components support for Java DSL.
*/
@org.springframework.lang.NonNullApi
@org.springframework.lang.NonNullFields
@org.jspecify.annotations.NullMarked
package org.springframework.integration.jpa.dsl;
Loading