DATAJPA-173 - Extended support for metadata detection on CRUD methods.

Extended the mechanism previously existing to detect @Lock annotations on redeclared CRUD methods into one being able to transport arbitrary metadata into the execution of CRUD methods.

Renamed LockModeRepositoryPostProcessor to CrudMethodMetadataPostProcessor, refactored the internals and added some metadata caching to avoid repeated reflection lookups to evaluate annotations.
This commit is contained in:
Oliver Gierke
2014-03-12 15:30:46 +01:00
parent 79b5330928
commit 5438c44c8f
10 changed files with 283 additions and 183 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2014 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.
@@ -15,15 +15,17 @@
*/
package org.springframework.data.jpa.repository.support;
import java.util.Map;
import javax.persistence.LockModeType;
/**
* Interface to abstract {@link LockMetadataProvider} that provide the {@link LockModeType} to be used for query
* Interface to abstract {@link CrudMethodMetadata} that provide the {@link LockModeType} to be used for query
* execution.
*
* @author Oliver Gierke
*/
public interface LockMetadataProvider {
public interface CrudMethodMetadata {
/**
* Returns the {@link LockModeType} to be used.
@@ -31,4 +33,11 @@ public interface LockMetadataProvider {
* @return
*/
LockModeType getLockModeType();
}
/**
* Returns all query hints to be applied to queries executed for the CRUD method.
*
* @return
*/
Map<String, Object> getQueryHints();
}

View File

@@ -0,0 +1,200 @@
/*
* Copyright 2011-2014 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.support;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.LockModeType;
import javax.persistence.QueryHint;
import org.aopalliance.intercept.MethodInterceptor;
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.core.annotation.AnnotationUtils;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.QueryHints;
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;
/**
* {@link RepositoryProxyPostProcessor} that sets up interceptors to read metadata information from the invoked method.
* This is necessary to allow redeclaration of CRUD methods in repository interfaces and configure locking information
* or query hints on them.
*
* @author Oliver Gierke
*/
enum CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor {
INSTANCE;
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryProxyPostProcessor#postProcess(org.springframework.aop.framework.ProxyFactory, org.springframework.data.repository.core.RepositoryInformation)
*/
@Override
public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) {
factory.addAdvice(ExposeInvocationInterceptor.INSTANCE);
factory.addAdvice(CrudMethodMetadataPopulatingMethodIntercceptor.INSTANCE);
}
/**
* 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() {
ProxyFactory factory = new ProxyFactory();
factory.addInterface(CrudMethodMetadata.class);
factory.setTargetSource(new ThreadBoundTargetSource());
return (CrudMethodMetadata) factory.getProxy();
}
/**
* {@link MethodInterceptor} to build and cache {@link DefaultCrudMethodMetadata} instances for the invoked
* methods. Will bind the found information to a {@link TransactionSynchronizationManager} for later lookup.
*
* @see DefaultCrudMethodMetadata
* @author Oliver Gierke
*/
static enum CrudMethodMetadataPopulatingMethodIntercceptor implements MethodInterceptor {
INSTANCE;
private final Map<Method, CrudMethodMetadata> metadataCache = new HashMap<Method, CrudMethodMetadata>();
/*
* (non-Javadoc)
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
Object metadata = TransactionSynchronizationManager.getResource(method);
if (metadata != null) {
return invocation.proceed();
}
CrudMethodMetadata methodMetadata = metadataCache.get(method);
if (methodMetadata == null) {
methodMetadata = new DefaultCrudMethodMetadata(method);
metadataCache.put(method, methodMetadata);
}
TransactionSynchronizationManager.bindResource(method, methodMetadata);
try {
return invocation.proceed();
} finally {
TransactionSynchronizationManager.unbindResource(method);
}
}
}
/**
* Default implementation of {@link CrudMethodMetadata} that will inspect the backing method for annotations.
*
* @author Oliver Gierke
*/
private static class DefaultCrudMethodMetadata implements CrudMethodMetadata {
private final LockModeType lockModeType;
private final Map<String, Object> queryHints;
/**
* Creates a new {@link DefaultCrudMethodMetadata} foir the given {@link Method}.
*
* @param method must not be {@literal null}.
*/
public DefaultCrudMethodMetadata(Method method) {
Assert.notNull(method, "Method must not be null!");
this.lockModeType = findLockModeType(method);
this.queryHints = findQueryHints(method);
}
private static final LockModeType findLockModeType(Method method) {
Lock annotation = AnnotationUtils.findAnnotation(method, Lock.class);
return annotation == null ? null : (LockModeType) AnnotationUtils.getValue(annotation);
}
private static final Map<String, Object> findQueryHints(Method method) {
Map<String, Object> queryHints = new HashMap<String, Object>();
QueryHints queryHintsAnnotation = AnnotationUtils.findAnnotation(method, QueryHints.class);
if (queryHintsAnnotation != null) {
for (QueryHint hint : queryHintsAnnotation.value()) {
queryHints.put(hint.name(), hint.value());
}
}
QueryHint queryHintAnnotation = AnnotationUtils.findAnnotation(method, QueryHint.class);
if (queryHintAnnotation != null) {
queryHints.put(queryHintAnnotation.name(), queryHintAnnotation.value());
}
return Collections.unmodifiableMap(queryHints);
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.CrudMethodMetadata#getLockModeType()
*/
@Override
public LockModeType getLockModeType() {
return lockModeType;
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.CrudMethodMetadata#getQueryHints()
*/
@Override
public Map<String, Object> getQueryHints() {
return queryHints;
}
}
private static class ThreadBoundTargetSource extends AbstractLazyCreationTargetSource {
/*
* (non-Javadoc)
* @see org.springframework.aop.target.AbstractLazyCreationTargetSource#createObject()
*/
@Override
protected Object createObject() throws Exception {
MethodInvocation invocation = ExposeInvocationInterceptor.currentInvocation();
return TransactionSynchronizationManager.getResource(invocation.getMethod());
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2012 the original author or authors.
* Copyright 2008-2014 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.
@@ -40,7 +40,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
private final EntityManager entityManager;
private final QueryExtractor extractor;
private final LockModeRepositoryPostProcessor lockModePostProcessor;
private final CrudMethodMetadataPostProcessor lockModePostProcessor;
/**
* Creates a new {@link JpaRepositoryFactory}.
@@ -53,7 +53,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
this.entityManager = entityManager;
this.extractor = PersistenceProvider.fromEntityManager(entityManager);
this.lockModePostProcessor = LockModeRepositoryPostProcessor.INSTANCE;
this.lockModePostProcessor = CrudMethodMetadataPostProcessor.INSTANCE;
addRepositoryProxyPostProcessor(lockModePostProcessor);
}
@@ -64,7 +64,11 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
*/
@Override
protected Object getTargetRepository(RepositoryMetadata metadata) {
return getTargetRepository(metadata, entityManager);
SimpleJpaRepository<?, ?> repository = getTargetRepository(metadata, entityManager);
repository.setRepositoryMethodMetadata(lockModePostProcessor.getLockMetadataProvider());
return repository;
}
/**
@@ -77,7 +81,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected <T, ID extends Serializable> JpaRepository<?, ?> getTargetRepository(RepositoryMetadata metadata,
protected <T, ID extends Serializable> SimpleJpaRepository<?, ?> getTargetRepository(RepositoryMetadata metadata,
EntityManager entityManager) {
Class<?> repositoryInterface = metadata.getRepositoryInterface();
@@ -85,7 +89,6 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
SimpleJpaRepository<?, ?> repo = isQueryDslExecutor(repositoryInterface) ? new QueryDslJpaRepository(
entityInformation, entityManager) : new SimpleJpaRepository(entityInformation, entityManager);
repo.setLockMetadataProvider(lockModePostProcessor.getLockMetadataProvider());
return repo;
}

View File

@@ -1,119 +0,0 @@
/*
* Copyright 2011-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.support;
import java.lang.reflect.Method;
import javax.persistence.LockModeType;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* {@link RepositoryProxyPostProcessor} that sets up interceptors to read {@link LockModeType} information from the
* invoked method. This is necessary to allow redeclaration of CRUD methods in repository interfaces and configure
* locking information on them.
*
* @author Oliver Gierke
*/
public enum LockModeRepositoryPostProcessor implements RepositoryProxyPostProcessor {
INSTANCE;
private static final Object NULL = new Object();
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryProxyPostProcessor#postProcess(org.springframework.aop.framework.ProxyFactory, org.springframework.data.repository.core.RepositoryInformation)
*/
@Override
public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) {
factory.addAdvice(ExposeInvocationInterceptor.INSTANCE);
factory.addAdvice(LockModePopulatingMethodIntercceptor.INSTANCE);
}
/**
* Returns the {@link LockMetadataProvider} to lookup the lock information captured by the interceptors.
*
* @return
*/
public LockMetadataProvider getLockMetadataProvider() {
return ThreadBoundLockMetadata.INSTANCE;
}
/**
* {@link MethodInterceptor} to inspect the currently invoked {@link Method} for a {@link Lock} annotation. Will bind
* the found information to a {@link TransactionSynchronizationManager} for later lookup.
*
* @see ThreadBoundLockMetadata
* @author Oliver Gierke
*/
static enum LockModePopulatingMethodIntercceptor implements MethodInterceptor {
INSTANCE;
/*
* (non-Javadoc)
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
Object lockInfo = TransactionSynchronizationManager.getResource(method);
if (lockInfo != null) {
return invocation.proceed();
}
Lock annotation = AnnotationUtils.findAnnotation(method, Lock.class);
LockModeType lockMode = (LockModeType) AnnotationUtils.getValue(annotation);
TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode);
try {
return invocation.proceed();
} finally {
TransactionSynchronizationManager.unbindResource(method);
}
}
}
/**
* {@link LockMetadataProvider} that looks up locking metadata from the {@link TransactionSynchronizationManager}
* using the current method invocation as key.
*
* @author Oliver Gierke
*/
private static enum ThreadBoundLockMetadata implements LockMetadataProvider {
INSTANCE;
public LockModeType getLockModeType() {
MethodInvocation invocation = ExposeInvocationInterceptor.currentInvocation();
Object lockModeType = TransactionSynchronizationManager.getResource(invocation.getMethod());
return lockModeType == NULL ? null : (LockModeType) lockModeType;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2013 the original author or authors.
* Copyright 2008-2014 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.
@@ -21,6 +21,8 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
@@ -66,7 +68,7 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
private final EntityManager em;
private final PersistenceProvider provider;
private LockMetadataProvider lockMetadataProvider;
private CrudMethodMetadata crudMethodMetadata;
/**
* Creates a new {@link SimpleJpaRepository} to manage objects of the given {@link JpaEntityInformation}.
@@ -95,13 +97,13 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
}
/**
* Configures a custom {@link LockMetadataProvider} to be used to detect {@link LockModeType}s to be applied to
* queries.
* Configures a custom {@link CrudMethodMetadata} to be used to detect {@link LockModeType}s and query hints to be
* applied to queries.
*
* @param lockMetadataProvider
* @param crudMethodMetadata
*/
public void setLockMetadataProvider(LockMetadataProvider lockMetadataProvider) {
this.lockMetadataProvider = lockMetadataProvider;
public void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata) {
this.crudMethodMetadata = crudMethodMetadata;
}
protected Class<T> getDomainClass() {
@@ -208,10 +210,12 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
Assert.notNull(id, "The given id must not be null!");
LockModeType type = lockMetadataProvider == null ? null : lockMetadataProvider.getLockModeType();
LockModeType type = crudMethodMetadata.getLockModeType();
Map<String, Object> hints = crudMethodMetadata.getQueryHints();
Class<T> domainType = getDomainClass();
return type == null ? em.find(domainType, id) : em.find(domainType, id, type);
return type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints);
}
/*
@@ -468,7 +472,7 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
query.orderBy(toOrders(sort, root, builder));
}
return applyLockMode(em.createQuery(query));
return applyRepositoryMethodMetadata(em.createQuery(query));
}
/**
@@ -519,10 +523,16 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
return root;
}
private TypedQuery<T> applyLockMode(TypedQuery<T> query) {
private TypedQuery<T> applyRepositoryMethodMetadata(TypedQuery<T> query) {
LockModeType type = lockMetadataProvider == null ? null : lockMetadataProvider.getLockModeType();
return type == null ? query : query.setLockMode(type);
LockModeType type = crudMethodMetadata.getLockModeType();
TypedQuery<T> toReturn = type == null ? query : query.setLockMode(type);
for (Entry<String, Object> hint : crudMethodMetadata.getQueryHints().entrySet()) {
query.setHint(hint.getKey(), hint.getValue());
}
return toReturn;
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-2014 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.
@@ -19,6 +19,8 @@ import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
@@ -42,7 +44,7 @@ import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class LockIntegrationTests {
public class CrudMethodMetadataIntegrationTests {
@Mock EntityManager em;
@Mock CriteriaBuilder builder;
@@ -69,7 +71,7 @@ public class LockIntegrationTests {
}
/**
* @see DATAJPA-73
* @see DATAJPA-73, DATAJPA-173
*/
@Test
public void usesLockInformationAnnotatedAtRedeclaredMethod() {
@@ -82,16 +84,20 @@ public class LockIntegrationTests {
repository.findAll();
verify(query).setLockMode(LockModeType.READ);
verify(query).setHint("foo", "bar");
}
/**
* @see DATAJPA-359
* @see DATAJPA-359, DATAJPA-173
*/
@Test
public void usesLockInformationAnnotatedAtRedeclaredFindOne() {
public void usesMetadataAnnotatedAtRedeclaredFindOne() {
repository.findOne(1);
verify(em).find(Role.class, 1, LockModeType.READ);
Map<String, Object> expectedLinks = Collections.singletonMap("foo", (Object) "bar");
LockModeType expectedLockModeType = LockModeType.READ;
verify(em).find(Role.class, 1, expectedLockModeType, expectedLinks);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2011 the original author or authors.
* Copyright 2008-2014 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.
@@ -21,9 +21,9 @@ import java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.core.RepositoryMetadata;
/**
@@ -43,14 +43,11 @@ public class CustomGenericJpaRepositoryFactory extends JpaRepositoryFactory {
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.jpa.repository.support.GenericJpaRepositoryFactory
* #getTargetRepository(java.lang.Class, javax.persistence.EntityManager)
* @see org.springframework.data.jpa.repository.support.JpaRepositoryFactory#getTargetRepository(org.springframework.data.repository.core.RepositoryMetadata, javax.persistence.EntityManager)
*/
@Override
@SuppressWarnings("unchecked")
protected JpaRepository<?, ?> getTargetRepository(RepositoryMetadata metadata, EntityManager em) {
protected SimpleJpaRepository<?, ?> getTargetRepository(RepositoryMetadata metadata, EntityManager em) {
JpaEntityInformation<Object, Serializable> entityMetadata = mock(JpaEntityInformation.class);
when(entityMetadata.getJavaType()).thenReturn((Class<Object>) metadata.getDomainType());
@@ -59,14 +56,10 @@ public class CustomGenericJpaRepositoryFactory extends JpaRepositoryFactory {
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.repository.support.RepositoryFactorySupport#
* getRepositoryBaseClass()
* @see org.springframework.data.jpa.repository.support.JpaRepositoryFactory#getRepositoryBaseClass(org.springframework.data.repository.core.RepositoryMetadata)
*/
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return CustomGenericJpaRepository.class;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2011 the original author or authors.
* Copyright 2008-2014 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.
@@ -16,9 +16,11 @@
package org.springframework.data.jpa.repository.sample;
import javax.persistence.LockModeType;
import javax.persistence.QueryHint;
import org.springframework.data.jpa.domain.sample.Role;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.QueryHints;
import org.springframework.data.repository.CrudRepository;
/**
@@ -33,6 +35,7 @@ public interface RoleRepository extends CrudRepository<Role, Integer> {
* @see org.springframework.data.repository.CrudRepository#findAll()
*/
@Lock(LockModeType.READ)
@QueryHints(@QueryHint(name = "foo", value = "bar"))
Iterable<Role> findAll();
/*
@@ -40,5 +43,6 @@ public interface RoleRepository extends CrudRepository<Role, Integer> {
* @see org.springframework.data.repository.CrudRepository#findOne(java.io.Serializable)
*/
@Lock(LockModeType.READ)
@QueryHints(@QueryHint(name = "foo", value = "bar"))
Role findOne(Integer id);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2014 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.
@@ -29,19 +29,18 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor.LockModePopulatingMethodIntercceptor;
import org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor.CrudMethodMetadataPopulatingMethodIntercceptor;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Unit tests for {@link LockModePopulatingMethodIntercceptor}.
* Unit tests for {@link CrudMethodMetadataPopulatingMethodIntercceptor}.
*
* @author Oliver Gierke
*/
@RunWith(MockitoJUnitRunner.class)
public class LockModePopulatingMethodInterceptorUnitTests {
public class CrudMethodMetadataPopulatingMethodInterceptorUnitTests {
@Mock
MethodInvocation invocation;
@Mock MethodInvocation invocation;
/**
* @see DATAJPA-268
@@ -52,7 +51,7 @@ public class LockModePopulatingMethodInterceptorUnitTests {
Method method = Sample.class.getMethod("someMethod");
when(invocation.getMethod()).thenReturn(method);
LockModePopulatingMethodIntercceptor interceptor = LockModePopulatingMethodIntercceptor.INSTANCE;
CrudMethodMetadataPopulatingMethodIntercceptor interceptor = CrudMethodMetadataPopulatingMethodIntercceptor.INSTANCE;
interceptor.invoke(invocation);
assertThat(TransactionSynchronizationManager.getResource(method), is(nullValue()));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2011-2014 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.
@@ -41,20 +41,14 @@ public class SimpleJpaRepositoryUnitTests {
SimpleJpaRepository<User, Long> repo;
@Mock
EntityManager em;
@Mock
CriteriaBuilder builder;
@Mock
CriteriaQuery<User> criteriaQuery;
@Mock
CriteriaQuery<Long> countCriteriaQuery;
@Mock
TypedQuery<User> query;
@Mock
TypedQuery<Long> countQuery;
@Mock
JpaEntityInformation<User, Long> information;
@Mock EntityManager em;
@Mock CriteriaBuilder builder;
@Mock CriteriaQuery<User> criteriaQuery;
@Mock CriteriaQuery<Long> countCriteriaQuery;
@Mock TypedQuery<User> query;
@Mock TypedQuery<Long> countQuery;
@Mock JpaEntityInformation<User, Long> information;
@Mock CrudMethodMetadata metadata;
@Before
public void setUp() {
@@ -69,6 +63,7 @@ public class SimpleJpaRepositoryUnitTests {
when(em.createQuery(countCriteriaQuery)).thenReturn(countQuery);
repo = new SimpleJpaRepository<User, Long>(information, em);
repo.setRepositoryMethodMetadata(metadata);
}
/**