Introduce null-safety of Spring Framework API

This commit introduces 2 new @Nullable and @NonNullApi
annotations that leverage JSR 305 (dormant but available via
Findbugs jsr305 dependency and already used by libraries
like OkHttp) meta-annotations to specify explicitly
null-safety of Spring Framework parameters and return values.

In order to avoid adding too much annotations, the
default is set at package level with @NonNullApi and
@Nullable annotations are added when needed at parameter or
return value level. These annotations are intended to be used
on Spring Framework itself but also by other Spring projects.

@Nullable annotations have been introduced based on Javadoc
and search of patterns like "return null;". It is expected that
nullability of Spring Framework API will be polished with
complementary commits.

In practice, this will make the whole Spring Framework API
null-safe for Kotlin projects (when KT-10942 will be fixed)
since Kotlin will be able to leverage these annotations to
know if a parameter or a return value is nullable or not. But
this is also useful for Java developers as well since IntelliJ
IDEA, for example, also understands these annotations to
generate warnings when unsafe nullable usages are detected.

Issue: SPR-15540
This commit is contained in:
Sebastien Deleuze
2017-05-27 08:14:59 +02:00
parent 2d37c966b2
commit 87598f48e4
1315 changed files with 4831 additions and 963 deletions

View File

@@ -19,6 +19,8 @@ package org.springframework.orm.hibernate5;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.springframework.lang.Nullable;
/**
* Callback interface for Hibernate code. To be used with {@link HibernateTemplate}'s
* execution methods, often as anonymous classes within a method implementation.
@@ -46,6 +48,7 @@ public interface HibernateCallback<T> {
* @throws HibernateException if thrown by the Hibernate API
* @see HibernateTemplate#execute
*/
@Nullable
T doInHibernate(Session session) throws HibernateException;
}

View File

@@ -27,6 +27,7 @@ import org.hibernate.ReplicationMode;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.dao.DataAccessException;
import org.springframework.lang.Nullable;
/**
* Interface that specifies a basic set of Hibernate operations,
@@ -64,6 +65,7 @@ public interface HibernateOperations {
* @see HibernateTransactionManager
* @see org.hibernate.Session
*/
@Nullable
<T> T execute(HibernateCallback<T> action) throws DataAccessException;
@@ -84,6 +86,7 @@ public interface HibernateOperations {
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#get(Class, Serializable)
*/
@Nullable
<T> T get(Class<T> entityClass, Serializable id) throws DataAccessException;
/**
@@ -101,6 +104,7 @@ public interface HibernateOperations {
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#get(Class, Serializable, LockMode)
*/
@Nullable
<T> T get(Class<T> entityClass, Serializable id, LockMode lockMode) throws DataAccessException;
/**
@@ -116,6 +120,7 @@ public interface HibernateOperations {
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#get(Class, Serializable)
*/
@Nullable
Object get(String entityName, Serializable id) throws DataAccessException;
/**
@@ -133,6 +138,7 @@ public interface HibernateOperations {
* @throws DataAccessException in case of Hibernate errors
* @see org.hibernate.Session#get(Class, Serializable, LockMode)
*/
@Nullable
Object get(String entityName, Serializable id, LockMode lockMode) throws DataAccessException;
/**

View File

@@ -24,6 +24,7 @@ import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.persistence.PersistenceException;
import org.apache.commons.logging.Log;
@@ -44,6 +45,7 @@ import org.hibernate.criterion.Example;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
@@ -170,6 +172,7 @@ public class HibernateTemplate implements HibernateOperations, InitializingBean
/**
* Return the names of Hibernate filters to be activated, if any.
*/
@Nullable
public String[] getFilterNames() {
return this.filterNames;
}
@@ -322,6 +325,7 @@ public class HibernateTemplate implements HibernateOperations, InitializingBean
* @return a result object returned by the action, or {@code null}
* @throws DataAccessException in case of Hibernate errors
*/
@Nullable
public <T> T executeWithNativeSession(HibernateCallback<T> action) {
return doExecute(action, true);
}
@@ -335,6 +339,7 @@ public class HibernateTemplate implements HibernateOperations, InitializingBean
* @throws DataAccessException in case of Hibernate errors
*/
@SuppressWarnings("deprecation")
@Nullable
protected <T> T doExecute(HibernateCallback<T> action, boolean enforceNativeSession) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");

View File

@@ -18,6 +18,7 @@ package org.springframework.orm.hibernate5;
import java.sql.Connection;
import java.sql.ResultSet;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
@@ -41,6 +42,7 @@ import org.springframework.jdbc.datasource.ConnectionHolder;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.lang.Nullable;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.IllegalTransactionStateException;
import org.springframework.transaction.InvalidIsolationLevelException;
@@ -313,6 +315,7 @@ public class HibernateTransactionManager extends AbstractPlatformTransactionMana
* @see #setEntityInterceptorBeanName
* @see #setBeanFactory
*/
@Nullable
public Interceptor getEntityInterceptor() throws IllegalStateException, BeansException {
if (this.entityInterceptor instanceof Interceptor) {
return (Interceptor) entityInterceptor;

View File

@@ -27,6 +27,7 @@ import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import javax.persistence.Embeddable;
@@ -58,6 +59,7 @@ import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.lang.Nullable;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -101,7 +103,7 @@ public class LocalSessionFactoryBuilder extends Configuration {
* @param dataSource the JDBC DataSource that the resulting Hibernate SessionFactory should be using
* (may be {@code null})
*/
public LocalSessionFactoryBuilder(DataSource dataSource) {
public LocalSessionFactoryBuilder(@Nullable DataSource dataSource) {
this(dataSource, new PathMatchingResourcePatternResolver());
}
@@ -111,7 +113,7 @@ public class LocalSessionFactoryBuilder extends Configuration {
* (may be {@code null})
* @param classLoader the ClassLoader to load application classes from
*/
public LocalSessionFactoryBuilder(DataSource dataSource, ClassLoader classLoader) {
public LocalSessionFactoryBuilder(@Nullable DataSource dataSource, ClassLoader classLoader) {
this(dataSource, new PathMatchingResourcePatternResolver(classLoader));
}
@@ -121,7 +123,7 @@ public class LocalSessionFactoryBuilder extends Configuration {
* (may be {@code null})
* @param resourceLoader the ResourceLoader to load application classes from
*/
public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader) {
public LocalSessionFactoryBuilder(@Nullable DataSource dataSource, ResourceLoader resourceLoader) {
this(dataSource, resourceLoader, new MetadataSources(
new BootstrapServiceRegistryBuilder().applyClassLoader(resourceLoader.getClassLoader()).build()));
}
@@ -134,7 +136,7 @@ public class LocalSessionFactoryBuilder extends Configuration {
* @param metadataSources the Hibernate MetadataSources service to use (e.g. reusing an existing one)
* @since 4.3
*/
public LocalSessionFactoryBuilder(DataSource dataSource, ResourceLoader resourceLoader, MetadataSources metadataSources) {
public LocalSessionFactoryBuilder(@Nullable DataSource dataSource, ResourceLoader resourceLoader, MetadataSources metadataSources) {
super(metadataSources);
getProperties().put(AvailableSettings.CURRENT_SESSION_CONTEXT_CLASS, SpringSessionContext.class.getName());

View File

@@ -18,6 +18,7 @@ package org.springframework.orm.hibernate5;
import java.lang.reflect.Method;
import java.util.Map;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
@@ -63,6 +64,7 @@ import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -161,7 +163,7 @@ public abstract class SessionFactoryUtils {
* @param session the Hibernate Session to close (may be {@code null})
* @see Session#close()
*/
public static void closeSession(Session session) {
public static void closeSession(@Nullable Session session) {
if (session != null) {
try {
session.close();
@@ -181,6 +183,7 @@ public abstract class SessionFactoryUtils {
* @return the DataSource, or {@code null} if none found
* @see ConnectionProvider
*/
@Nullable
public static DataSource getDataSource(SessionFactory sessionFactory) {
Method getProperties = ClassUtils.getMethodIfAvailable(sessionFactory.getClass(), "getProperties");
if (getProperties != null) {

View File

@@ -10,4 +10,7 @@
*
* <p><b>This package supports Hibernate 5.x only.</b>
*/
@NonNullApi
package org.springframework.orm.hibernate5;
import org.springframework.lang.NonNullApi;

View File

@@ -1,4 +1,7 @@
/**
* Classes supporting the {@code org.springframework.orm.hibernate5} package.
*/
@NonNullApi
package org.springframework.orm.hibernate5.support;
import org.springframework.lang.NonNullApi;

View File

@@ -33,6 +33,7 @@ import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceException;
@@ -55,6 +56,7 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
@@ -267,6 +269,7 @@ public abstract class AbstractEntityManagerFactoryBean implements
* Return the JpaVendorAdapter implementation for this
* EntityManagerFactory, or {@code null} if not known.
*/
@Nullable
public JpaVendorAdapter getJpaVendorAdapter() {
return this.jpaVendorAdapter;
}
@@ -291,6 +294,7 @@ public abstract class AbstractEntityManagerFactoryBean implements
* Return the asynchronous executor for background bootstrapping, if any.
* @since 4.3
*/
@Nullable
public AsyncTaskExecutor getBootstrapExecutor() {
return this.bootstrapExecutor;
}

View File

@@ -19,6 +19,7 @@ package org.springframework.orm.jpa;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
@@ -29,6 +30,7 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -85,6 +87,7 @@ public abstract class EntityManagerFactoryAccessor implements BeanFactoryAware {
/**
* Return the name of the persistence unit to access the EntityManagerFactory for, if any.
*/
@Nullable
public String getPersistenceUnitName() {
return this.persistenceUnitName;
}
@@ -106,7 +109,7 @@ public abstract class EntityManagerFactoryAccessor implements BeanFactoryAware {
* <p>Can be populated with a "map" or "props" element in XML bean definitions.
* @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
*/
public void setJpaPropertyMap(Map<String, Object> jpaProperties) {
public void setJpaPropertyMap(@Nullable Map<String, Object> jpaProperties) {
if (jpaProperties != null) {
this.jpaPropertyMap.putAll(jpaProperties);
}
@@ -161,6 +164,7 @@ public abstract class EntityManagerFactoryAccessor implements BeanFactoryAware {
* @see EntityManagerFactoryUtils#getTransactionalEntityManager(javax.persistence.EntityManagerFactory)
* @see EntityManagerFactoryUtils#getTransactionalEntityManager(javax.persistence.EntityManagerFactory, java.util.Map)
*/
@Nullable
protected EntityManager getTransactionalEntityManager() throws IllegalStateException{
EntityManagerFactory emf = getEntityManagerFactory();
Assert.state(emf != null, "No EntityManagerFactory specified");

View File

@@ -22,6 +22,8 @@ import javax.persistence.spi.PersistenceProvider;
import javax.persistence.spi.PersistenceUnitInfo;
import javax.sql.DataSource;
import org.springframework.lang.Nullable;
/**
* Metadata interface for a Spring-managed JPA {@link EntityManagerFactory}.
*
@@ -47,6 +49,7 @@ public interface EntityManagerFactoryInfo {
* or {@code null} if the standard JPA provider autodetection process
* was used to configure the EntityManagerFactory
*/
@Nullable
PersistenceProvider getPersistenceProvider();
/**
@@ -56,6 +59,7 @@ public interface EntityManagerFactoryInfo {
* or {@code null} if the in-container contract was not used to
* configure the EntityManagerFactory
*/
@Nullable
PersistenceUnitInfo getPersistenceUnitInfo();
/**
@@ -67,6 +71,7 @@ public interface EntityManagerFactoryInfo {
* @see #getPersistenceUnitInfo()
* @see javax.persistence.spi.PersistenceUnitInfo#getPersistenceUnitName()
*/
@Nullable
String getPersistenceUnitName();
/**
@@ -74,6 +79,7 @@ public interface EntityManagerFactoryInfo {
* obtains its JDBC Connections from.
* @return the JDBC DataSource, or {@code null} if not known
*/
@Nullable
DataSource getDataSource();
/**
@@ -83,12 +89,14 @@ public interface EntityManagerFactoryInfo {
* to happen: either based on a target {@code EntityManager} instance
* or simply defaulting to {@code javax.persistence.EntityManager}.
*/
@Nullable
Class<? extends EntityManager> getEntityManagerInterface();
/**
* Return the vendor-specific JpaDialect implementation for this
* EntityManagerFactory, or {@code null} if not known.
*/
@Nullable
JpaDialect getJpaDialect();
/**

View File

@@ -17,6 +17,7 @@
package org.springframework.orm.jpa;
import java.util.Map;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
@@ -48,6 +49,7 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.ResourceHolderSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
@@ -96,7 +98,7 @@ public abstract class EntityManagerFactoryUtils {
* @see EntityManagerFactoryInfo#getPersistenceUnitName()
*/
public static EntityManagerFactory findEntityManagerFactory(
ListableBeanFactory beanFactory, String unitName) throws NoSuchBeanDefinitionException {
ListableBeanFactory beanFactory, @Nullable String unitName) throws NoSuchBeanDefinitionException {
Assert.notNull(beanFactory, "ListableBeanFactory must not be null");
if (StringUtils.hasLength(unitName)) {
@@ -130,6 +132,7 @@ public abstract class EntityManagerFactoryUtils {
* @throws DataAccessResourceFailureException if the EntityManager couldn't be obtained
* @see JpaTransactionManager
*/
@Nullable
public static EntityManager getTransactionalEntityManager(EntityManagerFactory emf)
throws DataAccessResourceFailureException {
@@ -147,7 +150,8 @@ public abstract class EntityManagerFactoryUtils {
* @throws DataAccessResourceFailureException if the EntityManager couldn't be obtained
* @see JpaTransactionManager
*/
public static EntityManager getTransactionalEntityManager(EntityManagerFactory emf, Map<?, ?> properties)
@Nullable
public static EntityManager getTransactionalEntityManager(EntityManagerFactory emf, @Nullable Map<?, ?> properties)
throws DataAccessResourceFailureException {
try {
return doGetTransactionalEntityManager(emf, properties, true);
@@ -169,6 +173,7 @@ public abstract class EntityManagerFactoryUtils {
* @see #getTransactionalEntityManager(javax.persistence.EntityManagerFactory)
* @see JpaTransactionManager
*/
@Nullable
public static EntityManager doGetTransactionalEntityManager(EntityManagerFactory emf, Map<?, ?> properties)
throws PersistenceException {
@@ -189,8 +194,9 @@ public abstract class EntityManagerFactoryUtils {
* @see #getTransactionalEntityManager(javax.persistence.EntityManagerFactory)
* @see JpaTransactionManager
*/
@Nullable
public static EntityManager doGetTransactionalEntityManager(
EntityManagerFactory emf, Map<?, ?> properties, boolean synchronizedWithTransaction) throws PersistenceException {
EntityManagerFactory emf, @Nullable Map<?, ?> properties, boolean synchronizedWithTransaction) throws PersistenceException {
Assert.notNull(emf, "No EntityManagerFactory specified");
@@ -289,6 +295,7 @@ public abstract class EntityManagerFactoryUtils {
* (to be passed into cleanupTransaction)
* @see JpaDialect#prepareTransaction
*/
@Nullable
private static Object prepareTransaction(EntityManager em, EntityManagerFactory emf) {
if (emf instanceof EntityManagerFactoryInfo) {
EntityManagerFactoryInfo emfInfo = (EntityManagerFactoryInfo) emf;
@@ -350,6 +357,7 @@ public abstract class EntityManagerFactoryUtils {
* @return the corresponding DataAccessException instance,
* or {@code null} if the exception should not be translated
*/
@Nullable
public static DataAccessException convertJpaAccessExceptionIfPossible(RuntimeException ex) {
// Following the JPA specification, a persistence provider can also
// throw these two exceptions, besides PersistenceException.
@@ -406,7 +414,7 @@ public abstract class EntityManagerFactoryUtils {
* @param em the JPA EntityManager to close (may be {@code null})
* @see javax.persistence.EntityManager#close()
*/
public static void closeEntityManager(EntityManager em) {
public static void closeEntityManager(@Nullable EntityManager em) {
if (em != null) {
logger.debug("Closing JPA EntityManager");
try {

View File

@@ -24,6 +24,7 @@ import java.lang.reflect.Proxy;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
@@ -37,6 +38,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.Ordered;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.ResourceHolderSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
@@ -141,7 +143,7 @@ public abstract class ExtendedEntityManagerCreator {
* in any managed transaction
* @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
*/
public static EntityManager createContainerManagedEntityManager(EntityManagerFactory emf, Map<?, ?> properties) {
public static EntityManager createContainerManagedEntityManager(EntityManagerFactory emf, @Nullable Map<?, ?> properties) {
return createContainerManagedEntityManager(emf, properties, true);
}
@@ -160,7 +162,7 @@ public abstract class ExtendedEntityManagerCreator {
* @since 4.0
*/
public static EntityManager createContainerManagedEntityManager(
EntityManagerFactory emf, Map<?, ?> properties, boolean synchronizedWithTransaction) {
EntityManagerFactory emf, @Nullable Map<?, ?> properties, boolean synchronizedWithTransaction) {
Assert.notNull(emf, "EntityManagerFactory must not be null");
if (emf instanceof EntityManagerFactoryInfo) {
@@ -216,8 +218,8 @@ public abstract class ExtendedEntityManagerCreator {
* @return the EntityManager proxy
*/
private static EntityManager createProxy(
EntityManager rawEm, Class<? extends EntityManager> emIfc, ClassLoader cl,
PersistenceExceptionTranslator exceptionTranslator, Boolean jta,
EntityManager rawEm, @Nullable Class<? extends EntityManager> emIfc, @Nullable ClassLoader cl,
PersistenceExceptionTranslator exceptionTranslator, @Nullable Boolean jta,
boolean containerManaged, boolean synchronizedWithTransaction) {
Assert.notNull(rawEm, "EntityManager must not be null");
@@ -278,6 +280,7 @@ public abstract class ExtendedEntityManagerCreator {
}
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Invocation on EntityManager interface coming in...

View File

@@ -17,11 +17,13 @@
package org.springframework.orm.jpa;
import java.sql.SQLException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.jdbc.datasource.ConnectionHandle;
import org.springframework.lang.Nullable;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
@@ -78,6 +80,7 @@ public interface JpaDialect extends PersistenceExceptionTranslator {
* @see javax.persistence.EntityTransaction#begin
* @see org.springframework.jdbc.datasource.DataSourceUtils#prepareConnectionForTransaction
*/
@Nullable
Object beginTransaction(EntityManager entityManager, TransactionDefinition definition)
throws PersistenceException, SQLException, TransactionException;
@@ -100,6 +103,7 @@ public interface JpaDialect extends PersistenceExceptionTranslator {
* @throws javax.persistence.PersistenceException if thrown by JPA methods
* @see #cleanupTransaction
*/
@Nullable
Object prepareTransaction(EntityManager entityManager, boolean readOnly, String name)
throws PersistenceException;
@@ -114,7 +118,7 @@ public interface JpaDialect extends PersistenceExceptionTranslator {
* @see #beginTransaction
* @see org.springframework.jdbc.datasource.DataSourceUtils#resetConnectionAfterTransaction
*/
void cleanupTransaction(Object transactionData);
void cleanupTransaction(@Nullable Object transactionData);
/**
* Retrieve the JDBC Connection that the given JPA EntityManager uses underneath,
@@ -146,6 +150,7 @@ public interface JpaDialect extends PersistenceExceptionTranslator {
* @see org.springframework.jdbc.datasource.SimpleConnectionHandle
* @see JpaTransactionManager#setDataSource
*/
@Nullable
ConnectionHandle getJdbcConnection(EntityManager entityManager, boolean readOnly)
throws PersistenceException, SQLException;

View File

@@ -37,6 +37,7 @@ import org.springframework.jdbc.datasource.ConnectionHandle;
import org.springframework.jdbc.datasource.ConnectionHolder;
import org.springframework.jdbc.datasource.JdbcTransactionObjectSupport;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.lang.Nullable;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.IllegalTransactionStateException;
import org.springframework.transaction.NestedTransactionNotSupportedException;
@@ -175,6 +176,7 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
/**
* Return the name of the persistence unit to manage transactions for, if any.
*/
@Nullable
public String getPersistenceUnitName() {
return this.persistenceUnitName;
}
@@ -186,7 +188,7 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
* or a "props" element in XML bean definitions.
* @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
*/
public void setJpaProperties(Properties jpaProperties) {
public void setJpaProperties(@Nullable Properties jpaProperties) {
CollectionUtils.mergePropertiesIntoMap(jpaProperties, this.jpaPropertyMap);
}
@@ -196,7 +198,7 @@ public class JpaTransactionManager extends AbstractPlatformTransactionManager
* <p>Can be populated with a "map" or "props" element in XML bean definitions.
* @see javax.persistence.EntityManagerFactory#createEntityManager(java.util.Map)
*/
public void setJpaPropertyMap(Map<String, ?> jpaProperties) {
public void setJpaPropertyMap(@Nullable Map<String, ?> jpaProperties) {
if (jpaProperties != null) {
this.jpaPropertyMap.putAll(jpaProperties);
}

View File

@@ -17,10 +17,13 @@
package org.springframework.orm.jpa;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceProvider;
import org.springframework.lang.Nullable;
/**
* SPI interface that allows to plug in vendor-specific behavior
* into Spring's EntityManagerFactory creators. Serves as single
@@ -44,6 +47,7 @@ public interface JpaVendorAdapter {
* excluding provider classes from temporary class overriding.
* @since 2.5.2
*/
@Nullable
String getPersistenceProviderRootPackage();
/**
@@ -58,12 +62,14 @@ public interface JpaVendorAdapter {
* @see javax.persistence.Persistence#createEntityManagerFactory(String, java.util.Map)
* @see javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory(javax.persistence.spi.PersistenceUnitInfo, java.util.Map)
*/
@Nullable
Map<String, ?> getJpaPropertyMap();
/**
* Return the vendor-specific JpaDialect implementation for this
* provider, or {@code null} if there is none.
*/
@Nullable
JpaDialect getJpaDialect();
/**

View File

@@ -26,6 +26,7 @@ import java.lang.reflect.Proxy;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
@@ -34,6 +35,7 @@ import javax.persistence.TransactionRequiredException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
@@ -100,7 +102,7 @@ public abstract class SharedEntityManagerCreator {
* {@code createEntityManager} call (may be {@code null})
* @return a shareable transaction EntityManager proxy
*/
public static EntityManager createSharedEntityManager(EntityManagerFactory emf, Map<?, ?> properties) {
public static EntityManager createSharedEntityManager(EntityManagerFactory emf, @Nullable Map<?, ?> properties) {
return createSharedEntityManager(emf, properties, true);
}
@@ -115,7 +117,7 @@ public abstract class SharedEntityManagerCreator {
* @since 4.0
*/
public static EntityManager createSharedEntityManager(
EntityManagerFactory emf, Map<?, ?> properties, boolean synchronizedWithTransaction) {
EntityManagerFactory emf, @Nullable Map<?, ?> properties, boolean synchronizedWithTransaction) {
Class<?> emIfc = (emf instanceof EntityManagerFactoryInfo ?
((EntityManagerFactoryInfo) emf).getEntityManagerInterface() : EntityManager.class);
@@ -133,7 +135,7 @@ public abstract class SharedEntityManagerCreator {
* @return a shareable transactional EntityManager proxy
*/
public static EntityManager createSharedEntityManager(
EntityManagerFactory emf, Map<?, ?> properties, Class<?>... entityManagerInterfaces) {
EntityManagerFactory emf, @Nullable Map<?, ?> properties, Class<?>... entityManagerInterfaces) {
return createSharedEntityManager(emf, properties, true, entityManagerInterfaces);
}
@@ -150,7 +152,7 @@ public abstract class SharedEntityManagerCreator {
* @return a shareable transactional EntityManager proxy
* @since 4.0
*/
public static EntityManager createSharedEntityManager(EntityManagerFactory emf, Map<?, ?> properties,
public static EntityManager createSharedEntityManager(EntityManagerFactory emf, @Nullable Map<?, ?> properties,
boolean synchronizedWithTransaction, Class<?>... entityManagerInterfaces) {
ClassLoader cl = null;
@@ -202,6 +204,7 @@ public abstract class SharedEntityManagerCreator {
}
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Invocation on EntityManager interface coming in...

View File

@@ -3,4 +3,7 @@
* Contains EntityManagerFactory helper classes, a template plus callback for JPA access,
* and an implementation of Spring's transaction SPI for local JPA transactions.
*/
@NonNullApi
package org.springframework.orm.jpa;
import org.springframework.lang.NonNullApi;

View File

@@ -23,6 +23,7 @@ import javax.persistence.spi.ClassTransformer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -52,6 +53,7 @@ class ClassFileTransformerAdapter implements ClassFileTransformer {
@Override
@Nullable
public byte[] transform(
ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) {

View File

@@ -25,6 +25,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.Converter;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
@@ -58,6 +59,7 @@ import org.springframework.instrument.classloading.LoadTimeWeaver;
import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import org.springframework.jdbc.datasource.lookup.MapDataSourceLookup;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ResourceUtils;
@@ -610,6 +612,7 @@ public class DefaultPersistenceUnitManager
* @return the persistence unit root URL to pass to the JPA PersistenceProvider
* @see #setDefaultPersistenceUnitRootLocation
*/
@Nullable
private URL determineDefaultPersistenceUnitRootUrl() {
if (this.defaultPersistenceUnitRootLocation == null) {
return null;
@@ -629,6 +632,7 @@ public class DefaultPersistenceUnitManager
* <p>Checks whether a "META-INF/orm.xml" file exists in the classpath and uses it
* if it is not co-located with a "META-INF/persistence.xml" file.
*/
@Nullable
private Resource getOrmXmlForDefaultPersistenceUnit() {
Resource ormXml = this.resourcePatternResolver.getResource(
this.defaultPersistenceUnitRootLocation + DEFAULT_ORM_XML_RESOURCE);
@@ -657,6 +661,7 @@ public class DefaultPersistenceUnitManager
* @param persistenceUnitName the name of the desired persistence unit
* @return the PersistenceUnitInfo in mutable form, or {@code null} if not available
*/
@Nullable
protected final MutablePersistenceUnitInfo getPersistenceUnitInfo(String persistenceUnitName) {
PersistenceUnitInfo pui = this.persistenceUnitInfos.get(persistenceUnitName);
return (MutablePersistenceUnitInfo) pui;

View File

@@ -38,6 +38,7 @@ import org.xml.sax.SAXException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
@@ -332,6 +333,7 @@ final class PersistenceUnitReader {
* @return the corresponding persistence unit root URL
* @throws IOException if the checking failed
*/
@Nullable
static URL determinePersistenceUnitRootUrl(Resource resource) throws IOException {
URL originalURL = resource.getURL();

View File

@@ -1,4 +1,7 @@
/**
* Internal support for managing JPA persistence units.
*/
@NonNullApi
package org.springframework.orm.jpa.persistenceunit;
import org.springframework.lang.NonNullApi;

View File

@@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.lang.Nullable;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@@ -116,6 +117,7 @@ public class OpenEntityManagerInViewFilter extends OncePerRequestFilter {
/**
* Return the name of the persistence unit to access the EntityManagerFactory for, if any.
*/
@Nullable
protected String getPersistenceUnitName() {
return this.persistenceUnitName;
}

View File

@@ -27,6 +27,7 @@ import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
@@ -56,6 +57,7 @@ import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.jndi.JndiLocatorDelegate;
import org.springframework.jndi.JndiTemplate;
import org.springframework.lang.Nullable;
import org.springframework.orm.jpa.EntityManagerFactoryInfo;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.orm.jpa.EntityManagerProxy;
@@ -302,7 +304,7 @@ public class PersistenceAnnotationBeanPostProcessor
* such factories, either specify this default persistence unit name
* or explicitly refer to named persistence units in your annotations.
*/
public void setDefaultPersistenceUnitName(String unitName) {
public void setDefaultPersistenceUnitName(@Nullable String unitName) {
this.defaultPersistenceUnitName = (unitName != null ? unitName : "");
}
@@ -456,6 +458,7 @@ public class PersistenceAnnotationBeanPostProcessor
* or {@code null} if none found
* @see #setPersistenceUnits
*/
@Nullable
protected EntityManagerFactory getPersistenceUnit(String unitName) {
if (this.persistenceUnits != null) {
String unitNameForLookup = (unitName != null ? unitName : "");
@@ -487,6 +490,7 @@ public class PersistenceAnnotationBeanPostProcessor
* @see #setPersistenceContexts
* @see #setExtendedPersistenceContexts
*/
@Nullable
protected EntityManager getPersistenceContext(String unitName, boolean extended) {
Map<String, String> contexts = (extended ? this.extendedPersistenceContexts : this.persistenceContexts);
if (contexts != null) {
@@ -519,7 +523,7 @@ public class PersistenceAnnotationBeanPostProcessor
* @return the EntityManagerFactory
* @throws NoSuchBeanDefinitionException if there is no such EntityManagerFactory in the context
*/
protected EntityManagerFactory findEntityManagerFactory(String unitName, String requestingBeanName)
protected EntityManagerFactory findEntityManagerFactory(@Nullable String unitName, String requestingBeanName)
throws NoSuchBeanDefinitionException {
if (this.beanFactory == null) {

View File

@@ -1,4 +1,7 @@
/**
* Classes supporting the {@code org.springframework.orm.jpa} package.
*/
@NonNullApi
package org.springframework.orm.jpa.support;
import org.springframework.lang.NonNullApi;

View File

@@ -19,6 +19,7 @@ package org.springframework.orm.jpa.vendor;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import javax.persistence.EntityManager;
import javax.persistence.spi.PersistenceProvider;
@@ -26,6 +27,8 @@ import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.config.TargetDatabase;
import org.eclipse.persistence.jpa.JpaEntityManager;
import org.springframework.lang.Nullable;
/**
* {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Eclipse
* Persistence Services (EclipseLink). Developed and tested against EclipseLink 2.4.
@@ -88,6 +91,7 @@ public class EclipseLinkJpaVendorAdapter extends AbstractJpaVendorAdapter {
* @param database the specified database
* @return the EclipseLink target database name, or {@code null} if none found
*/
@Nullable
protected String determineTargetDatabaseName(Database database) {
switch (database) {
case DB2: return TargetDatabase.DB2;

View File

@@ -58,6 +58,7 @@ import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.dao.PessimisticLockingFailureException;
import org.springframework.jdbc.datasource.ConnectionHandle;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.lang.Nullable;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.jpa.DefaultJpaDialect;
@@ -177,6 +178,7 @@ public class HibernateJpaDialect extends DefaultJpaDialect {
}
@SuppressWarnings("deprecation")
@Nullable
protected FlushMode prepareFlushMode(Session session, boolean readOnly) throws PersistenceException {
FlushMode flushMode = (FlushMode) ReflectionUtils.invokeMethod(getFlushMode, session);
if (readOnly) {

View File

@@ -18,6 +18,7 @@ package org.springframework.orm.jpa.vendor;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceProvider;
@@ -34,6 +35,8 @@ import org.hibernate.dialect.PostgreSQL95Dialect;
import org.hibernate.dialect.SQLServer2012Dialect;
import org.hibernate.dialect.SybaseDialect;
import org.springframework.lang.Nullable;
/**
* {@link org.springframework.orm.jpa.JpaVendorAdapter} implementation for Hibernate
* EntityManager. Developed and tested against Hibernate 5.0, 5.1 and 5.2;
@@ -155,6 +158,7 @@ public class HibernateJpaVendorAdapter extends AbstractJpaVendorAdapter {
* @param database the target database
* @return the Hibernate database dialect class, or {@code null} if none found
*/
@Nullable
protected Class<?> determineDatabaseDialectClass(Database database) {
switch (database) {
case DB2: return DB2Dialect.class;

View File

@@ -1,4 +1,7 @@
/**
* Support classes for adapting to specific JPA vendors.
*/
@NonNullApi
package org.springframework.orm.jpa.vendor;
import org.springframework.lang.NonNullApi;

View File

@@ -2,4 +2,7 @@
* Root package for Spring's O/R Mapping integration classes.
* Contains generic DataAccessExceptions related to O/R Mapping.
*/
@NonNullApi
package org.springframework.orm;
import org.springframework.lang.NonNullApi;