DATACMNS-364 - Infrastructure to allow redeclaring CRUD methods with queries.
Introduced new meta-annotation QueryAnnotation to mark and identify store specific Query annotations. This enables us to handle finder methods annotated with such store specific annotations in a generic way. Adjusted DefaultRepositoryInformation.getQueryMethods(…) to consider custom store specific query annotations. Original pull request: #43.
This commit is contained in:
committed by
Oliver Gierke
parent
4849f32447
commit
e7475e5e0f
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.data.repository.Repository;
|
||||
|
||||
/**
|
||||
* Meta-Annotation to mark a store specific annotation as a query annotation. This allows generic special handing of
|
||||
* finder methods on {@link Repository} interfaces.
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
public @interface QueryAnnotation {
|
||||
}
|
||||
@@ -29,6 +29,8 @@ import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.annotation.QueryAnnotation;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.CrudMethods;
|
||||
import org.springframework.data.repository.core.RepositoryInformation;
|
||||
@@ -167,7 +169,7 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
|
||||
for (Method method : getRepositoryInterface().getMethods()) {
|
||||
method = ClassUtils.getMostSpecificMethod(method, getRepositoryInterface());
|
||||
if (!isCustomMethod(method) && !isBaseClassMethod(method)) {
|
||||
if (isQueryMethodCandidate(method)) {
|
||||
result.add(method);
|
||||
}
|
||||
}
|
||||
@@ -175,6 +177,28 @@ class DefaultRepositoryInformation extends AbstractRepositoryMetadata implements
|
||||
return Collections.unmodifiableSet(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given method is a query method candidate.
|
||||
*
|
||||
* @param method
|
||||
* @return
|
||||
*/
|
||||
private boolean isQueryMethodCandidate(Method method) {
|
||||
return isQueryAnnotationPresentOn(method) || (!isCustomMethod(method) && !isBaseClassMethod(method));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given method contains a custom store specific query annotation annotated with
|
||||
* {@link QueryAnnotation}. The method-hierarchy is also considered in the search for the annotation.
|
||||
*
|
||||
* @param method
|
||||
* @return
|
||||
*/
|
||||
private boolean isQueryAnnotationPresentOn(Method method) {
|
||||
|
||||
return AnnotationUtils.findAnnotation(method, QueryAnnotation.class) != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.support.RepositoryInformation#isCustomMethod(java.lang.reflect.Method)
|
||||
|
||||
@@ -4,6 +4,10 @@ import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
@@ -13,6 +17,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.QueryAnnotation;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@@ -29,11 +34,9 @@ import org.springframework.data.repository.core.support.DefaultRepositoryMetadat
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DefaultRepositoryInformationUnitTests {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
static final Class<DummyGenericRepositorySupport> REPOSITORY = DummyGenericRepositorySupport.class;
|
||||
@SuppressWarnings("rawtypes") static final Class<DummyGenericRepositorySupport> REPOSITORY = DummyGenericRepositorySupport.class;
|
||||
|
||||
@Mock
|
||||
FooRepositoryCustom customImplementation;
|
||||
@Mock FooRepositoryCustom customImplementation;
|
||||
|
||||
@Test
|
||||
public void discoversRepositoryBaseClassMethod() throws Exception {
|
||||
@@ -157,6 +160,20 @@ public class DefaultRepositoryInformationUnitTests {
|
||||
assertThat(information.isQueryMethod(queryMethod), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATACMNS-364
|
||||
*/
|
||||
@Test
|
||||
public void ignoresCrudMethodsAnnotatedWithQuery() throws Exception {
|
||||
|
||||
RepositoryMetadata metadata = new DefaultRepositoryMetadata(ConcreteRepository.class);
|
||||
RepositoryInformation information = new DefaultRepositoryInformation(metadata, CrudRepository.class, null);
|
||||
|
||||
Method method = BaseRepository.class.getMethod("findOne", Serializable.class);
|
||||
|
||||
assertThat(information.getQueryMethods(), hasItem(method));
|
||||
}
|
||||
|
||||
private Method getMethodFrom(Class<?> type, String name) {
|
||||
for (Method method : type.getMethods()) {
|
||||
if (method.getName().equals(name)) {
|
||||
@@ -166,6 +183,13 @@ public class DefaultRepositoryInformationUnitTests {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@QueryAnnotation
|
||||
@interface MyQuery {
|
||||
|
||||
}
|
||||
|
||||
interface FooRepository extends CrudRepository<User, Integer>, FooRepositoryCustom {
|
||||
|
||||
// Redeclared method
|
||||
@@ -200,6 +224,9 @@ public class DefaultRepositoryInformationUnitTests {
|
||||
<K extends S> K save(K entity);
|
||||
|
||||
void delete(S entity);
|
||||
|
||||
@MyQuery
|
||||
S findOne(ID id);
|
||||
}
|
||||
|
||||
interface ConcreteRepository extends BaseRepository<User, Integer> {
|
||||
|
||||
Reference in New Issue
Block a user