From 820655a7c434969e776801f1ba048fa0cc1ed88b Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 16 May 2013 13:24:21 +0200 Subject: [PATCH] DATAJPA-345 - Allow @Lock and @QueryHints to be used as meta-annotations. @Lock and @QueryHints can now be used as meta annotations to create custom annotations to e.g. reuse a dedicated set of query hints. --- .../data/jpa/repository/Lock.java | 6 +-- .../data/jpa/repository/QueryHints.java | 6 ++- .../jpa/repository/query/JpaQueryMethod.java | 2 +- .../LockModeRepositoryPostProcessor.java | 4 +- .../query/JpaQueryMethodUnitTests.java | 38 +++++++++++++++++-- 5 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/springframework/data/jpa/repository/Lock.java b/src/main/java/org/springframework/data/jpa/repository/Lock.java index 45f6ea48b..6471a594f 100644 --- a/src/main/java/org/springframework/data/jpa/repository/Lock.java +++ b/src/main/java/org/springframework/data/jpa/repository/Lock.java @@ -1,5 +1,5 @@ /* - * Copyright 2011 the original author or authors. + * 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. @@ -30,7 +30,7 @@ import javax.persistence.LockModeType; * @author Aleksander Blomskøld * @author Oliver Gierke */ -@Target(ElementType.METHOD) +@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Lock { @@ -41,4 +41,4 @@ public @interface Lock { * @return */ LockModeType value(); -} \ No newline at end of file +} diff --git a/src/main/java/org/springframework/data/jpa/repository/QueryHints.java b/src/main/java/org/springframework/data/jpa/repository/QueryHints.java index 750a72aaa..f0c6d1a8a 100644 --- a/src/main/java/org/springframework/data/jpa/repository/QueryHints.java +++ b/src/main/java/org/springframework/data/jpa/repository/QueryHints.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011 the original author or authors. + * Copyright 2008-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. @@ -15,6 +15,7 @@ */ package org.springframework.data.jpa.repository; +import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -30,8 +31,9 @@ import javax.persistence.QueryHint; * * @author Oliver Gierke */ -@Target(ElementType.METHOD) +@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME) +@Documented public @interface QueryHints { /** diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java index 243875b6f..1eaabf9d3 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java @@ -126,7 +126,7 @@ public class JpaQueryMethod extends QueryMethod { */ LockModeType getLockModeType() { - Lock annotation = method.getAnnotation(Lock.class); + Lock annotation = findAnnotation(method, Lock.class); return (LockModeType) AnnotationUtils.getValue(annotation); } 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 index 4ef4420e3..8b2cdff40 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/LockModeRepositoryPostProcessor.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/LockModeRepositoryPostProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2011 the original author or authors. + * 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. @@ -84,7 +84,7 @@ public enum LockModeRepositoryPostProcessor implements RepositoryProxyPostProces return invocation.proceed(); } - Lock annotation = method.getAnnotation(Lock.class); + Lock annotation = AnnotationUtils.findAnnotation(method, Lock.class); LockModeType lockMode = (LockModeType) AnnotationUtils.getValue(annotation); TransactionSynchronizationManager.bindResource(method, lockMode == null ? NULL : lockMode); diff --git a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java index be0e92335..12f61413e 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java @@ -19,6 +19,8 @@ import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; import java.util.List; @@ -37,6 +39,7 @@ import org.springframework.data.jpa.domain.sample.User; import org.springframework.data.jpa.repository.Lock; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.jpa.repository.QueryHints; import org.springframework.data.jpa.repository.sample.UserRepository; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; @@ -60,7 +63,8 @@ public class JpaQueryMethodUnitTests { RepositoryMetadata metadata; Method repositoryMethod, invalidReturnType, pageableAndSort, pageableTwice, sortableTwice, modifyingMethod, - nativeQuery, namedQuery, findWithLockMethod, invalidNamedParameter, findsProjections, findsProjection; + nativeQuery, namedQuery, findWithLockMethod, invalidNamedParameter, findsProjections, findsProjection, + withMetaAnnotation; /** * @throws Exception @@ -85,6 +89,8 @@ public class JpaQueryMethodUnitTests { findsProjections = ValidRepository.class.getMethod("findsProjections"); findsProjection = ValidRepository.class.getMethod("findsProjection"); + + withMetaAnnotation = ValidRepository.class.getMethod("withMetaAnnotation"); } @Test @@ -221,7 +227,7 @@ public class JpaQueryMethodUnitTests { @Test public void considersAnnotatedNamedQueryName() { JpaQueryMethod queryMethod = new JpaQueryMethod(namedQuery, metadata, extractor); - assertThat(queryMethod.getNamedQueryName(), is("Foo.bar")); + assertThat(queryMethod.getNamedQueryName(), is("HateoasAwareSpringDataWebConfiguration.bar")); } /** @@ -256,7 +262,7 @@ public class JpaQueryMethodUnitTests { public void returnsDefaultCountQueryNameBasedOnConfiguredNamedQueryName() { JpaQueryMethod method = new JpaQueryMethod(namedQuery, metadata, extractor); - assertThat(method.getNamedCountQueryName(), is("Foo.bar.count")); + assertThat(method.getNamedCountQueryName(), is("HateoasAwareSpringDataWebConfiguration.bar.count")); } /** @@ -293,6 +299,20 @@ public class JpaQueryMethodUnitTests { assertThat(new JpaQueryMethod(findsProjection, metadata, extractor).isQueryForEntity(), is(false)); } + /** + * @see DATAJPA-345 + */ + @Test + public void detectsLockAndQueryHintsOnIfUsedAsMetaAnnotation() { + + JpaQueryMethod method = new JpaQueryMethod(withMetaAnnotation, metadata, extractor); + + assertThat(method.getLockModeType(), is(LockModeType.OPTIMISTIC_FORCE_INCREMENT)); + assertThat(method.getHints(), hasSize(1)); + assertThat(method.getHints().get(0).name(), is("foo")); + assertThat(method.getHints().get(0).value(), is("bar")); + } + /** * Interface to define invalid repository methods for testing. * @@ -334,7 +354,7 @@ public class JpaQueryMethodUnitTests { @Query(value = "query", nativeQuery = true) List findByLastname(String lastname); - @Query(name = "Foo.bar") + @Query(name = "HateoasAwareSpringDataWebConfiguration.bar") List findByNamedQuery(); @Lock(LockModeType.PESSIMISTIC_WRITE) @@ -344,5 +364,15 @@ public class JpaQueryMethodUnitTests { List findsProjections(); Integer findsProjection(); + + @CustomAnnotation + void withMetaAnnotation(); + } + + @Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT) + @QueryHints(@QueryHint(name = "foo", value = "bar")) + @Retention(RetentionPolicy.RUNTIME) + static @interface CustomAnnotation { + } }