From 5438c44c8f922cfb07f30ff7f5902631e1266224 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 12 Mar 2014 15:30:46 +0100 Subject: [PATCH] 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. --- ...aProvider.java => CrudMethodMetadata.java} | 17 +- .../CrudMethodMetadataPostProcessor.java | 200 ++++++++++++++++++ .../support/JpaRepositoryFactory.java | 15 +- .../LockModeRepositoryPostProcessor.java | 119 ----------- .../support/SimpleJpaRepository.java | 36 ++-- ...> CrudMethodMetadataIntegrationTests.java} | 18 +- .../CustomGenericJpaRepositoryFactory.java | 17 +- .../jpa/repository/sample/RoleRepository.java | 6 +- ...PopulatingMethodInterceptorUnitTests.java} | 13 +- .../support/SimpleJpaRepositoryUnitTests.java | 25 +-- 10 files changed, 283 insertions(+), 183 deletions(-) rename src/main/java/org/springframework/data/jpa/repository/support/{LockMetadataProvider.java => CrudMethodMetadata.java} (68%) create mode 100644 src/main/java/org/springframework/data/jpa/repository/support/CrudMethodMetadataPostProcessor.java delete mode 100644 src/main/java/org/springframework/data/jpa/repository/support/LockModeRepositoryPostProcessor.java rename src/test/java/org/springframework/data/jpa/repository/{LockIntegrationTests.java => CrudMethodMetadataIntegrationTests.java} (82%) rename src/test/java/org/springframework/data/jpa/repository/support/{LockModePopulatingMethodInterceptorUnitTests.java => CrudMethodMetadataPopulatingMethodInterceptorUnitTests.java} (76%) 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); } /**