From 50ed8632795a1e0c5b3fe3b0247258d0253c20f8 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 22 Jan 2013 20:39:23 +0100 Subject: [PATCH] EntityManagerFactoryUtils finds default EntityManagerFactory in parent contexts as well Also introduces consistent use of getBean(Class) for similar use cases across the framework, accepting a locally unique target bean even if further matching beans would be available in parent contexts (in contrast to BeanFactoryUtils.beanOfType's behavior). Issue: SPR-10160 --- .../config/ServiceLocatorFactoryBean.java | 35 ++++++++------- .../orm/jpa/EntityManagerFactoryUtils.java | 41 ++++++++++-------- .../interceptor/TransactionAspectSupport.java | 43 ++++++++----------- .../TransactionProxyFactoryBean.java | 7 ++- 4 files changed, 61 insertions(+), 65 deletions(-) diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.java b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.java index 192f6b7e66..1ded4154aa 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,6 @@ import org.springframework.beans.BeansException; import org.springframework.beans.FatalBeanException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ListableBeanFactory; @@ -36,8 +35,8 @@ import org.springframework.util.StringUtils; /** * A {@link FactoryBean} implementation that takes an interface which must have one or more - * methods with the signatures MyType xxx() or MyType xxx(MyIdType id) - * (typically, MyService getService() or MyService getService(String id)) + * methods with the signatures {@code MyType xxx()} or {@code MyType xxx(MyIdType id)} + * (typically, {@code MyService getService()} or {@code MyService getService(String id)}) * and creates a dynamic proxy which implements that interface, delegating to an * underlying {@link org.springframework.beans.factory.BeanFactory}. * @@ -51,7 +50,7 @@ import org.springframework.util.StringUtils; * setter or constructor injection of the target bean is preferable. * *

On invocation of the no-arg factory method, or the single-arg factory - * method with a String id of null or empty String, if exactly + * method with a String id of {@code null} or empty String, if exactly * one bean in the factory matches the return type of the factory * method, that bean is returned, otherwise a * {@link org.springframework.beans.factory.NoSuchBeanDefinitionException} @@ -64,7 +63,7 @@ import org.springframework.util.StringUtils; * *

A factory method argument will usually be a String, but can also be an * int or a custom enumeration type, for example, stringified via - * toString. The resulting String can be used as bean name as-is, + * {@code toString}. The resulting String can be used as bean name as-is, * provided that corresponding beans are defined in the bean factory. * Alternatively, {@link #setServiceMappings(java.util.Properties) a custom mapping} * between service ids and bean names can be defined. @@ -99,7 +98,7 @@ import org.springframework.util.StringUtils; * *</beans> * - *

The attendant MyClientBean class implementation might then + *

The attendant {@code MyClientBean} class implementation might then * look something like this: * *

package a.b.c;
@@ -151,7 +150,7 @@ import org.springframework.util.StringUtils;
  *
  *</beans>
* - *

The attendant MyClientBean class implementation might then + *

The attendant {@code MyClientBean} class implementation might then * look something like this: * *

package a.b.c;
@@ -202,8 +201,8 @@ public class ServiceLocatorFactoryBean implements FactoryBean, BeanFacto
 
 	/**
 	 * Set the service locator interface to use, which must have one or more methods with
-	 * the signatures MyType xxx() or MyType xxx(MyIdType id)
-	 * (typically, MyService getService() or MyService getService(String id)).
+	 * the signatures {@code MyType xxx()} or {@code MyType xxx(MyIdType id)}
+	 * (typically, {@code MyService getService()} or {@code MyService getService(String id)}).
 	 * See the {@link ServiceLocatorFactoryBean class-level Javadoc} for
 	 * information on the semantics of such methods.
 	 */
@@ -214,8 +213,8 @@ public class ServiceLocatorFactoryBean implements FactoryBean, BeanFacto
 	/**
 	 * Set the exception class that the service locator should throw if service
 	 * lookup failed. The specified exception class must have a constructor
-	 * with one of the following parameter types: (String, Throwable)
-	 * or (Throwable) or (String).
+	 * with one of the following parameter types: {@code (String, Throwable)}
+	 * or {@code (Throwable)} or {@code (String)}.
 	 * 

If not specified, subclasses of Spring's BeansException will be thrown, * for example NoSuchBeanDefinitionException. As those are unchecked, the * caller does not need to handle them, so it might be acceptable that @@ -236,7 +235,7 @@ public class ServiceLocatorFactoryBean implements FactoryBean, BeanFacto * Set mappings between service ids (passed into the service locator) * and bean names (in the bean factory). Service ids that are not defined * here will be treated as bean names as-is. - *

The empty string as service id key defines the mapping for null and + *

The empty string as service id key defines the mapping for {@code null} and * empty string, and for factory methods without parameter. If not defined, * a single matching bean will be retrieved from the bean factory. * @param serviceMappings mappings between service ids and bean names, @@ -271,8 +270,8 @@ public class ServiceLocatorFactoryBean implements FactoryBean, BeanFacto * Determine the constructor to use for the given service locator exception * class. Only called in case of a custom service locator exception. *

The default implementation looks for a constructor with one of the - * following parameter types: (String, Throwable) - * or (Throwable) or (String). + * following parameter types: {@code (String, Throwable)} + * or {@code (Throwable)} or {@code (String)}. * @param exceptionClass the exception class * @return the constructor to use * @see #setServiceLocatorExceptionClass @@ -364,12 +363,12 @@ public class ServiceLocatorFactoryBean implements FactoryBean, BeanFacto try { String beanName = tryGetBeanName(args); if (StringUtils.hasLength(beanName)) { - // Service locator for a specific bean name. + // Service locator for a specific bean name return beanFactory.getBean(beanName, serviceLocatorMethodReturnType); } else { - // Service locator for a bean type. - return BeanFactoryUtils.beanOfTypeIncludingAncestors(beanFactory, serviceLocatorMethodReturnType); + // Service locator for a bean type + return beanFactory.getBean(serviceLocatorMethodReturnType); } } catch (BeansException ex) { diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java index 8ed9ed0718..044cb72be3 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/jpa/EntityManagerFactoryUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -76,12 +76,14 @@ public abstract class EntityManagerFactoryUtils { * Find an EntityManagerFactory with the given name in the given * Spring application context (represented as ListableBeanFactory). *

The specified unit name will be matched against the configured - * peristence unit, provided that a discovered EntityManagerFactory + * persistence unit, provided that a discovered EntityManagerFactory * implements the {@link EntityManagerFactoryInfo} interface. If not, * the persistence unit name will be matched against the Spring bean name, * assuming that the EntityManagerFactory bean names follow that convention. + *

If no unit name has been given, this method will search for a default + * EntityManagerFactory through {@link ListableBeanFactory#getBean(Class)}. * @param beanFactory the ListableBeanFactory to search - * @param unitName the name of the persistence unit (may be null or empty, + * @param unitName the name of the persistence unit (may be {@code null} or empty, * in which case a single bean of type EntityManagerFactory will be searched for) * @return the EntityManagerFactory * @throws NoSuchBeanDefinitionException if there is no such EntityManagerFactory in the context @@ -108,7 +110,8 @@ public abstract class EntityManagerFactoryUtils { return beanFactory.getBean(unitName, EntityManagerFactory.class); } else { - return BeanFactoryUtils.beanOfType(beanFactory, EntityManagerFactory.class); + // Find unique EntityManagerFactory bean in the context, falling back to parent contexts. + return beanFactory.getBean(EntityManagerFactory.class); } } @@ -116,9 +119,9 @@ public abstract class EntityManagerFactoryUtils { * Obtain a JPA EntityManager from the given factory. Is aware of a * corresponding EntityManager bound to the current thread, * for example when using JpaTransactionManager. - *

Note: Will return null if no thread-bound EntityManager found! + *

Note: Will return {@code null} if no thread-bound EntityManager found! * @param emf EntityManagerFactory to create the EntityManager with - * @return the EntityManager, or null if none found + * @return the EntityManager, or {@code null} if none found * @throws DataAccessResourceFailureException if the EntityManager couldn't be obtained * @see JpaTransactionManager */ @@ -132,11 +135,11 @@ public abstract class EntityManagerFactoryUtils { * Obtain a JPA EntityManager from the given factory. Is aware of a * corresponding EntityManager bound to the current thread, * for example when using JpaTransactionManager. - *

Note: Will return null if no thread-bound EntityManager found! + *

Note: Will return {@code null} if no thread-bound EntityManager found! * @param emf EntityManagerFactory to create the EntityManager with - * @param properties the properties to be passed into the createEntityManager - * call (may be null) - * @return the EntityManager, or null if none found + * @param properties the properties to be passed into the {@code createEntityManager} + * call (may be {@code null}) + * @return the EntityManager, or {@code null} if none found * @throws DataAccessResourceFailureException if the EntityManager couldn't be obtained * @see JpaTransactionManager */ @@ -154,11 +157,11 @@ public abstract class EntityManagerFactoryUtils { * Obtain a JPA EntityManager from the given factory. Is aware of a * corresponding EntityManager bound to the current thread, * for example when using JpaTransactionManager. - *

Same as getEntityManager, but throwing the original PersistenceException. + *

Same as {@code getEntityManager}, but throwing the original PersistenceException. * @param emf EntityManagerFactory to create the EntityManager with - * @param properties the properties to be passed into the createEntityManager - * call (may be null) - * @return the EntityManager, or null if none found + * @param properties the properties to be passed into the {@code createEntityManager} + * call (may be {@code null}) + * @return the EntityManager, or {@code null} if none found * @throws javax.persistence.PersistenceException if the EntityManager couldn't be created * @see #getTransactionalEntityManager(javax.persistence.EntityManagerFactory) * @see JpaTransactionManager @@ -273,7 +276,7 @@ public abstract class EntityManagerFactoryUtils { /** * Convert the given runtime exception to an appropriate exception from the - * org.springframework.dao hierarchy. + * {@code org.springframework.dao} hierarchy. * Return null if no translation is appropriate: any other exception may * have resulted from user code, and should not be translated. *

The most important cases like object not found or optimistic locking failure @@ -281,7 +284,7 @@ public abstract class EntityManagerFactoryUtils { * support sophisticated translation of exceptions via a JpaDialect. * @param ex runtime exception that occurred * @return the corresponding DataAccessException instance, - * or null if the exception should not be translated + * or {@code null} if the exception should not be translated */ public static DataAccessException convertJpaAccessExceptionIfPossible(RuntimeException ex) { // Following the JPA specification, a persistence provider can also @@ -317,17 +320,17 @@ public abstract class EntityManagerFactoryUtils { if (ex instanceof PersistenceException) { return new JpaSystemException((PersistenceException) ex); } - + // If we get here, we have an exception that resulted from user code, // rather than the persistence provider, so we return null to indicate // that translation should not occur. - return null; + return null; } /** * Close the given JPA EntityManager, * catching and logging any cleanup exceptions thrown. - * @param em the JPA EntityManager to close (may be null) + * @param em the JPA EntityManager to close (may be {@code null}) * @see javax.persistence.EntityManager#close() */ public static void closeEntityManager(EntityManager em) { diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java index 995c4bcbd5..9f9b9503dd 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionAspectSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,9 +24,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils; import org.springframework.core.NamedThreadLocal; import org.springframework.transaction.NoTransactionException; @@ -44,16 +42,16 @@ import org.springframework.util.StringUtils; * *

Subclasses are responsible for calling methods in this class in the correct order. * - *

If no transaction name has been specified in the TransactionAttribute, - * the exposed name will be the fully-qualified class name + "." + method name + *

If no transaction name has been specified in the {@code TransactionAttribute}, + * the exposed name will be the {@code fully-qualified class name + "." + method name} * (by default). * - *

Uses the Strategy design pattern. A PlatformTransactionManager + *

Uses the Strategy design pattern. A {@code PlatformTransactionManager} * implementation will perform the actual transaction management, and a - * TransactionAttributeSource is used for determining transaction definitions. + * {@code TransactionAttributeSource} is used for determining transaction definitions. * - *

A transaction aspect is serializable if its PlatformTransactionManager - * and TransactionAttributeSource are serializable. + *

A transaction aspect is serializable if its {@code PlatformTransactionManager} + * and {@code TransactionAttributeSource} are serializable. * * @author Rod Johnson * @author Juergen Hoeller @@ -68,7 +66,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init // class for AspectJ aspects (which are not allowed to implement Serializable)! /** - * Holder to support the currentTransactionStatus() method, + * Holder to support the {@code currentTransactionStatus()} method, * and to support communication between different cooperating advices * (e.g. before and after advice) if the aspect involves more than a * single method (as will be the case for around advice). @@ -85,11 +83,11 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init * An around advice such as an AOP Alliance MethodInterceptor can hold a * reference to the TransactionInfo throughout the aspect method. *

A TransactionInfo will be returned even if no transaction was created. - * The TransactionInfo.hasTransaction() method can be used to query this. + * The {@code TransactionInfo.hasTransaction()} method can be used to query this. *

To find out about specific transaction characteristics, consider using - * TransactionSynchronizationManager's isSynchronizationActive() - * and/or isActualTransactionActive() methods. - * @return TransactionInfo bound to this thread, or null if none + * TransactionSynchronizationManager's {@code isSynchronizationActive()} + * and/or {@code isActualTransactionActive()} methods. + * @return TransactionInfo bound to this thread, or {@code null} if none * @see TransactionInfo#hasTransaction() * @see org.springframework.transaction.support.TransactionSynchronizationManager#isSynchronizationActive() * @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive() @@ -247,12 +245,8 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init else if (this.transactionManagerBeanName != null) { return this.beanFactory.getBean(this.transactionManagerBeanName, PlatformTransactionManager.class); } - else if (this.beanFactory instanceof ListableBeanFactory) { - return BeanFactoryUtils.beanOfTypeIncludingAncestors(((ListableBeanFactory) this.beanFactory), PlatformTransactionManager.class); - } else { - throw new IllegalStateException( - "Cannot retrieve PlatformTransactionManager beans from non-listable BeanFactory: " + this.beanFactory); + return this.beanFactory.getBean(PlatformTransactionManager.class); } } @@ -262,7 +256,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init * @param method the method about to execute * @param targetClass the class that the method is being invoked on * @return a TransactionInfo object, whether or not a transaction was created. - * The hasTransaction() method on TransactionInfo can be used to + * The {@code hasTransaction()} method on TransactionInfo can be used to * tell if there was a transaction created. * @see #getTransactionAttributeSource() */ @@ -307,14 +301,15 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init * Create a transaction if necessary based on the given TransactionAttribute. *

Allows callers to perform custom TransactionAttribute lookups through * the TransactionAttributeSource. - * @param txAttr the TransactionAttribute (may be null) + * @param txAttr the TransactionAttribute (may be {@code null}) * @param joinpointIdentification the fully qualified method name * (used for monitoring and logging purposes) * @return a TransactionInfo object, whether or not a transaction was created. - * The hasTransaction() method on TransactionInfo can be used to + * The {@code hasTransaction()} method on TransactionInfo can be used to * tell if there was a transaction created. * @see #getTransactionAttributeSource() */ + @SuppressWarnings("serial") protected TransactionInfo createTransactionIfNecessary( PlatformTransactionManager tm, TransactionAttribute txAttr, final String joinpointIdentification) { @@ -345,7 +340,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init /** * Prepare a TransactionInfo for the given attribute and status object. - * @param txAttr the TransactionAttribute (may be null) + * @param txAttr the TransactionAttribute (may be {@code null}) * @param joinpointIdentification the fully qualified method name * (used for monitoring and logging purposes) * @param status the TransactionStatus for the current transaction @@ -449,7 +444,7 @@ public abstract class TransactionAspectSupport implements BeanFactoryAware, Init /** * Reset the TransactionInfo ThreadLocal. *

Call this in all cases: exception or normal return! - * @param txInfo information about the current transaction (may be null) + * @param txInfo information about the current transaction (may be {@code null}) */ protected void cleanupTransactionInfo(TransactionInfo txInfo) { if (txInfo != null) { diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionProxyFactoryBean.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionProxyFactoryBean.java index fe7ab37bbe..62b408e155 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionProxyFactoryBean.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/interceptor/TransactionProxyFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -156,7 +156,6 @@ public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBe * @see TransactionAttributeSourceEditor * @see MethodMapTransactionAttributeSource * @see NameMatchTransactionAttributeSource - * @see AttributesTransactionAttributeSource * @see org.springframework.transaction.annotation.AnnotationTransactionAttributeSource */ public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) { @@ -177,8 +176,8 @@ public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBe /** * This callback is optional: If running in a BeanFactory and no transaction * manager has been set explicitly, a single matching bean of type - * PlatformTransactionManager will be fetched from the BeanFactory. - * @see org.springframework.beans.factory.BeanFactoryUtils#beanOfTypeIncludingAncestors + * {@link PlatformTransactionManager} will be fetched from the BeanFactory. + * @see org.springframework.beans.factory.BeanFactory#getBean(Class) * @see org.springframework.transaction.PlatformTransactionManager */ public void setBeanFactory(BeanFactory beanFactory) {