diff --git a/src/main/java/org/springframework/data/jpa/repository/support/LockMetadataProvider.java b/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadata.java similarity index 68% rename from src/main/java/org/springframework/data/jpa/repository/support/LockMetadataProvider.java rename to src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadata.java index 4de971291..f735e19b7 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/LockMetadataProvider.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadata.java @@ -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(); -} \ No newline at end of file + + /** + * Returns all query hints to be applied to queries executed for the CRUD method. + * + * @return + */ + Map getQueryHints(); +} diff --git a/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java b/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java new file mode 100644 index 000000000..93d98ace5 --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java @@ -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 metadataCache = new HashMap(); + + /* + * (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 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 findQueryHints(Method method) { + + Map queryHints = new HashMap(); + 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 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()); + } + } +} diff --git a/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java b/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java index c60efef7c..eb417336a 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java @@ -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 JpaRepository getTargetRepository(RepositoryMetadata metadata, + protected 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; } diff --git a/src/main/java/org/springframework/data/jpa/repository/support/LockModeRepositoryPostProcessor.java b/src/main/java/org/springframework/data/jpa/repository/support/LockModeRepositoryPostProcessor.java deleted file mode 100644 index ec7b2d820..000000000 --- a/src/main/java/org/springframework/data/jpa/repository/support/LockModeRepositoryPostProcessor.java +++ /dev/null @@ -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; - } - } -} diff --git a/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java b/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java index 62bf23371..3726fbf57 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java @@ -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 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 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 getDomainClass() { @@ -208,10 +210,12 @@ public class SimpleJpaRepository implements JpaRepos Assert.notNull(id, "The given id must not be null!"); - LockModeType type = lockMetadataProvider == null ? null : lockMetadataProvider.getLockModeType(); + LockModeType type = crudMethodMetadata.getLockModeType(); + Map hints = crudMethodMetadata.getQueryHints(); + Class 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 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 implements JpaRepos return root; } - private TypedQuery applyLockMode(TypedQuery query) { + private TypedQuery applyRepositoryMethodMetadata(TypedQuery query) { - LockModeType type = lockMetadataProvider == null ? null : lockMetadataProvider.getLockModeType(); - return type == null ? query : query.setLockMode(type); + LockModeType type = crudMethodMetadata.getLockModeType(); + TypedQuery toReturn = type == null ? query : query.setLockMode(type); + + for (Entry hint : crudMethodMetadata.getQueryHints().entrySet()) { + query.setHint(hint.getKey(), hint.getValue()); + } + + return toReturn; } /** diff --git a/src/test/java/org/springframework/data/jpa/repository/LockIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/CrudMethodMetadataIntegrationTests.java similarity index 82% rename from src/test/java/org/springframework/data/jpa/repository/LockIntegrationTests.java rename to src/test/java/org/springframework/data/jpa/repository/CrudMethodMetadataIntegrationTests.java index 47e094c71..de7835478 100644 --- a/src/test/java/org/springframework/data/jpa/repository/LockIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/CrudMethodMetadataIntegrationTests.java @@ -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 expectedLinks = Collections.singletonMap("foo", (Object) "bar"); + LockModeType expectedLockModeType = LockModeType.READ; + + verify(em).find(Role.class, 1, expectedLockModeType, expectedLinks); } } diff --git a/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactory.java b/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactory.java index 2155d27a4..4cec44383 100644 --- a/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactory.java +++ b/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactory.java @@ -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 entityMetadata = mock(JpaEntityInformation.class); when(entityMetadata.getJavaType()).thenReturn((Class) 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; } } diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepository.java b/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepository.java index 81cfa1337..bb14f0af6 100644 --- a/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepository.java +++ b/src/test/java/org/springframework/data/jpa/repository/sample/RoleRepository.java @@ -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 { * @see org.springframework.data.repository.CrudRepository#findAll() */ @Lock(LockModeType.READ) + @QueryHints(@QueryHint(name = "foo", value = "bar")) Iterable findAll(); /* @@ -40,5 +43,6 @@ public interface RoleRepository extends CrudRepository { * @see org.springframework.data.repository.CrudRepository#findOne(java.io.Serializable) */ @Lock(LockModeType.READ) + @QueryHints(@QueryHint(name = "foo", value = "bar")) Role findOne(Integer id); } diff --git a/src/test/java/org/springframework/data/jpa/repository/support/LockModePopulatingMethodInterceptorUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPopulatingMethodInterceptorUnitTests.java similarity index 76% rename from src/test/java/org/springframework/data/jpa/repository/support/LockModePopulatingMethodInterceptorUnitTests.java rename to src/test/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPopulatingMethodInterceptorUnitTests.java index e2f90e088..452b6a2c3 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/LockModePopulatingMethodInterceptorUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPopulatingMethodInterceptorUnitTests.java @@ -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())); diff --git a/src/test/java/org/springframework/data/jpa/repository/support/SimpleJpaRepositoryUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/support/SimpleJpaRepositoryUnitTests.java index d4318a198..2e6e505d7 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/SimpleJpaRepositoryUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/SimpleJpaRepositoryUnitTests.java @@ -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 repo; - @Mock - EntityManager em; - @Mock - CriteriaBuilder builder; - @Mock - CriteriaQuery criteriaQuery; - @Mock - CriteriaQuery countCriteriaQuery; - @Mock - TypedQuery query; - @Mock - TypedQuery countQuery; - @Mock - JpaEntityInformation information; + @Mock EntityManager em; + @Mock CriteriaBuilder builder; + @Mock CriteriaQuery criteriaQuery; + @Mock CriteriaQuery countCriteriaQuery; + @Mock TypedQuery query; + @Mock TypedQuery countQuery; + @Mock JpaEntityInformation information; + @Mock CrudMethodMetadata metadata; @Before public void setUp() { @@ -69,6 +63,7 @@ public class SimpleJpaRepositoryUnitTests { when(em.createQuery(countCriteriaQuery)).thenReturn(countQuery); repo = new SimpleJpaRepository(information, em); + repo.setRepositoryMethodMetadata(metadata); } /**