DATAJPA-871 - CrudMethodMetadataPostProcessor now uses the bean ClassLoader.

The thread-local proxy for the CrudMethodMetadata is now created using the bean ClassLoader, which the repository factory gets set from the container.

Renamed the property for the post processor and its lookup method.
This commit is contained in:
Oliver Gierke
2015-11-05 18:53:32 +01:00
parent d26833b7ad
commit b3324a0e7d
3 changed files with 47 additions and 8 deletions

View File

@@ -30,6 +30,7 @@ import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.aop.target.AbstractLazyCreationTargetSource;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.Lock;
@@ -38,6 +39,7 @@ import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* {@link RepositoryProxyPostProcessor} that sets up interceptors to read metadata information from the invoked method.
@@ -47,9 +49,19 @@ import org.springframework.util.Assert;
* @author Oliver Gierke
* @author Thomas Darimont
*/
enum CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor {
class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, BeanClassLoaderAware {
INSTANCE;
private ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java.lang.ClassLoader)
*/
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader == null ? ClassUtils.getDefaultClassLoader() : classLoader;
}
/*
* (non-Javadoc)
@@ -64,14 +76,14 @@ enum CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor {
* Returns a {@link CrudMethodMetadata} proxy that will lookup the actual target object by obtaining a thread bound
* instance from the {@link TransactionSynchronizationManager} later.
*/
public CrudMethodMetadata getLockMetadataProvider() {
public CrudMethodMetadata getCrudMethodMetadata() {
ProxyFactory factory = new ProxyFactory();
factory.addInterface(CrudMethodMetadata.class);
factory.setTargetSource(new ThreadBoundTargetSource());
return (CrudMethodMetadata) factory.getProxy();
return (CrudMethodMetadata) factory.getProxy(this.classLoader);
}
/**

View File

@@ -43,7 +43,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
private final EntityManager entityManager;
private final QueryExtractor extractor;
private final CrudMethodMetadataPostProcessor lockModePostProcessor;
private final CrudMethodMetadataPostProcessor crudMethodMetadataPostProcessor;
/**
* Creates a new {@link JpaRepositoryFactory}.
@@ -56,9 +56,19 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
this.entityManager = entityManager;
this.extractor = PersistenceProvider.fromEntityManager(entityManager);
this.lockModePostProcessor = CrudMethodMetadataPostProcessor.INSTANCE;
this.crudMethodMetadataPostProcessor = new CrudMethodMetadataPostProcessor();
addRepositoryProxyPostProcessor(lockModePostProcessor);
addRepositoryProxyPostProcessor(crudMethodMetadataPostProcessor);
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#setBeanClassLoader(java.lang.ClassLoader)
*/
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
super.setBeanClassLoader(classLoader);
this.crudMethodMetadataPostProcessor.setBeanClassLoader(classLoader);
}
/*
@@ -69,7 +79,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
protected Object getTargetRepository(RepositoryInformation information) {
SimpleJpaRepository<?, ?> repository = getTargetRepository(information, entityManager);
repository.setRepositoryMethodMetadata(lockModePostProcessor.getLockMetadataProvider());
repository.setRepositoryMethodMetadata(crudMethodMetadataPostProcessor.getCrudMethodMetadata());
return repository;
}

View File

@@ -31,6 +31,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.aop.framework.Advised;
import org.springframework.core.OverridingClassLoader;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.custom.CustomGenericJpaRepositoryFactory;
@@ -38,7 +39,9 @@ import org.springframework.data.jpa.repository.custom.UserCustomExtendedReposito
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ClassUtils;
/**
* Unit test for {@code JpaRepositoryFactory}.
@@ -164,6 +167,20 @@ public class JpaRepositoryFactoryUnitTests {
assertEquals(CustomJpaRepository.class, ((Advised) repository).getTargetClass());
}
/**
* @see DATAJPA-819
*/
@Test
public void crudMethodMetadataPostProcessorUsesBeanClassLoader() {
ClassLoader classLoader = new OverridingClassLoader(ClassUtils.getDefaultClassLoader());
factory.setBeanClassLoader(classLoader);
Object processor = ReflectionTestUtils.getField(factory, "crudMethodMetadataPostProcessor");
assertThat(ReflectionTestUtils.getField(processor, "classLoader"), is((Object) classLoader));
}
private interface SimpleSampleRepository extends JpaRepository<User, Integer> {
@Transactional