Adopt MongoParameters and MongoParameter to reflect the actual parameter type when using generics.
Closes #4579
This commit is contained in:
@@ -30,6 +30,7 @@ import org.springframework.data.mongodb.repository.Near;
|
||||
import org.springframework.data.mongodb.repository.query.MongoParameters.MongoParameter;
|
||||
import org.springframework.data.repository.query.Parameter;
|
||||
import org.springframework.data.repository.query.Parameters;
|
||||
import org.springframework.data.repository.query.ParametersSource;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -49,38 +50,48 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
private final @Nullable Integer nearIndex;
|
||||
private final @Nullable Integer collationIndex;
|
||||
private final int updateIndex;
|
||||
private final TypeInformation<?> domainType;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MongoParameters} instance from the given {@link Method} and {@link MongoQueryMethod}.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @param parametersSource must not be {@literal null}.
|
||||
* @param isGeoNearMethod indicate if this is a geo spatial query method
|
||||
*/
|
||||
public MongoParameters(Method method, boolean isGeoNearMethod) {
|
||||
public MongoParameters(ParametersSource parametersSource, boolean isGeoNearMethod) {
|
||||
this(parametersSource, new NearIndex(parametersSource, isGeoNearMethod));
|
||||
}
|
||||
|
||||
super(method);
|
||||
/**
|
||||
* Creates a new {@link MongoParameters} instance from the given {@link Method} and {@link MongoQueryMethod}.
|
||||
*
|
||||
* @param parametersSource must not be {@literal null}.
|
||||
* @param nearIndex the near parameter index.
|
||||
*/
|
||||
private MongoParameters(ParametersSource parametersSource, NearIndex nearIndex) {
|
||||
|
||||
super(parametersSource, methodParameter -> new MongoParameter(methodParameter,
|
||||
parametersSource.getDomainTypeInformation(), nearIndex.nearIndex));
|
||||
|
||||
Method method = parametersSource.getMethod();
|
||||
List<Class<?>> parameterTypes = Arrays.asList(method.getParameterTypes());
|
||||
|
||||
this.domainType = parametersSource.getDomainTypeInformation();
|
||||
this.fullTextIndex = parameterTypes.indexOf(TextCriteria.class);
|
||||
|
||||
TypeInformation<?> declaringClassInfo = TypeInformation.of(method.getDeclaringClass());
|
||||
TypeInformation<?> declaringClassInfo = TypeInformation.of(parametersSource.getContainingClass());
|
||||
List<TypeInformation<?>> parameterTypeInfo = declaringClassInfo.getParameterTypes(method);
|
||||
|
||||
this.rangeIndex = getTypeIndex(parameterTypeInfo, Range.class, Distance.class);
|
||||
this.maxDistanceIndex = this.rangeIndex == -1 ? getTypeIndex(parameterTypeInfo, Distance.class, null) : -1;
|
||||
this.collationIndex = getTypeIndex(parameterTypeInfo, Collation.class, null);
|
||||
this.updateIndex = QueryUtils.indexOfAssignableParameter(UpdateDefinition.class, parameterTypes);
|
||||
|
||||
int index = findNearIndexInParameters(method);
|
||||
if (index == -1 && isGeoNearMethod) {
|
||||
index = getNearIndex(parameterTypes);
|
||||
}
|
||||
|
||||
this.nearIndex = index;
|
||||
this.nearIndex = nearIndex.nearIndex;
|
||||
}
|
||||
|
||||
private MongoParameters(List<MongoParameter> parameters, int maxDistanceIndex, @Nullable Integer nearIndex,
|
||||
@Nullable Integer fullTextIndex, int rangeIndex, @Nullable Integer collationIndex, int updateIndex) {
|
||||
@Nullable Integer fullTextIndex, int rangeIndex, @Nullable Integer collationIndex, int updateIndex,
|
||||
TypeInformation<?> domainType) {
|
||||
|
||||
super(parameters);
|
||||
|
||||
@@ -90,9 +101,25 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
this.rangeIndex = rangeIndex;
|
||||
this.collationIndex = collationIndex;
|
||||
this.updateIndex = updateIndex;
|
||||
this.domainType = domainType;
|
||||
}
|
||||
|
||||
private int getNearIndex(List<Class<?>> parameterTypes) {
|
||||
static class NearIndex {
|
||||
|
||||
private final @Nullable Integer nearIndex;
|
||||
|
||||
public NearIndex(ParametersSource parametersSource, boolean isGeoNearMethod) {
|
||||
|
||||
int index = findNearIndexInParameters(parametersSource.getMethod());
|
||||
if (index == -1 && isGeoNearMethod) {
|
||||
index = getNearIndex(Arrays.asList(parametersSource.getMethod().getParameterTypes()));
|
||||
}
|
||||
|
||||
this.nearIndex = index;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getNearIndex(List<Class<?>> parameterTypes) {
|
||||
|
||||
for (Class<?> reference : Arrays.asList(Point.class, double[].class)) {
|
||||
|
||||
@@ -112,15 +139,18 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int findNearIndexInParameters(Method method) {
|
||||
static int findNearIndexInParameters(Method method) {
|
||||
|
||||
int index = -1;
|
||||
for (java.lang.reflect.Parameter p : method.getParameters()) {
|
||||
|
||||
MongoParameter param = createParameter(MethodParameter.forParameter(p));
|
||||
if (param.isManuallyAnnotatedNearParameter()) {
|
||||
MethodParameter methodParameter = MethodParameter.forParameter(p);
|
||||
|
||||
if ((Point.class.isAssignableFrom(methodParameter.getParameterType())
|
||||
|| methodParameter.getParameterType().equals(double[].class))
|
||||
&& methodParameter.hasParameterAnnotation(Near.class)) {
|
||||
if (index == -1) {
|
||||
index = param.getIndex();
|
||||
index = methodParameter.getParameterIndex();
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
String.format("Found multiple @Near annotations ond method %s; Only one allowed", method));
|
||||
@@ -131,11 +161,6 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MongoParameter createParameter(MethodParameter parameter) {
|
||||
return new MongoParameter(parameter);
|
||||
}
|
||||
|
||||
public int getDistanceRangeIndex() {
|
||||
return -1;
|
||||
}
|
||||
@@ -197,6 +222,7 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
|
||||
/**
|
||||
* Returns the index of the {@link UpdateDefinition} parameter or -1 if not present.
|
||||
*
|
||||
* @return -1 if not present.
|
||||
* @since 3.4
|
||||
*/
|
||||
@@ -207,7 +233,7 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
@Override
|
||||
protected MongoParameters createFrom(List<MongoParameter> parameters) {
|
||||
return new MongoParameters(parameters, this.maxDistanceIndex, this.nearIndex, this.fullTextIndex, this.rangeIndex,
|
||||
this.collationIndex, this.updateIndex);
|
||||
this.collationIndex, this.updateIndex, this.domainType);
|
||||
}
|
||||
|
||||
private int getTypeIndex(List<TypeInformation<?>> parameterTypes, Class<?> type, @Nullable Class<?> componentType) {
|
||||
@@ -234,18 +260,21 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class MongoParameter extends Parameter {
|
||||
static class MongoParameter extends Parameter {
|
||||
|
||||
private final MethodParameter parameter;
|
||||
private final @Nullable Integer nearIndex;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MongoParameter}.
|
||||
*
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @param domainType must not be {@literal null}.
|
||||
*/
|
||||
MongoParameter(MethodParameter parameter) {
|
||||
super(parameter);
|
||||
MongoParameter(MethodParameter parameter, TypeInformation<?> domainType, @Nullable Integer nearIndex) {
|
||||
super(parameter, domainType);
|
||||
this.parameter = parameter;
|
||||
this.nearIndex = nearIndex;
|
||||
|
||||
if (!isPoint() && hasNearAnnotation()) {
|
||||
throw new IllegalArgumentException("Near annotation is only allowed at Point parameter");
|
||||
@@ -259,7 +288,6 @@ public class MongoParameters extends Parameters<MongoParameters, MongoParameter>
|
||||
}
|
||||
|
||||
private boolean isNearParameter() {
|
||||
Integer nearIndex = MongoParameters.this.nearIndex;
|
||||
return nearIndex != null && nearIndex.equals(getIndex());
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.springframework.data.mongodb.repository.Update;
|
||||
import org.springframework.data.mongodb.util.BsonUtils;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.ParametersSource;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.ReactiveWrappers;
|
||||
@@ -94,8 +95,8 @@ public class MongoQueryMethod extends QueryMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MongoParameters createParameters(Method method) {
|
||||
return new MongoParameters(method, isGeoNearQuery(method));
|
||||
protected MongoParameters createParameters(ParametersSource parametersSource) {
|
||||
return new MongoParameters(parametersSource, isGeoNearQuery(parametersSource.getMethod()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.data.mongodb.repository.query.MongoParameters.MongoParameter;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.ParametersSource;
|
||||
import org.springframework.data.repository.util.ReactiveWrapperConverters;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.ReactiveWrappers;
|
||||
@@ -71,8 +72,8 @@ public class ReactiveMongoQueryMethod extends MongoQueryMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MongoParameters createParameters(Method method) {
|
||||
return new MongoParameters(method, isGeoNearQuery(method));
|
||||
protected MongoParameters createParameters(ParametersSource parametersSource) {
|
||||
return new MongoParameters(parametersSource, isGeoNearQuery(parametersSource.getMethod()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.springframework.data.mongodb.core.query.UpdateDefinition;
|
||||
import org.springframework.data.mongodb.repository.Near;
|
||||
import org.springframework.data.mongodb.repository.Person;
|
||||
import org.springframework.data.repository.query.Parameter;
|
||||
import org.springframework.data.repository.query.ParametersSource;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link MongoParameters}.
|
||||
@@ -52,7 +53,7 @@ class MongoParametersUnitTests {
|
||||
void discoversDistanceParameter() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByLocationNear", Point.class, Distance.class);
|
||||
MongoParameters parameters = new MongoParameters(method, false);
|
||||
MongoParameters parameters = new MongoParameters(ParametersSource.of(method), false);
|
||||
|
||||
assertThat(parameters.getNumberOfParameters()).isEqualTo(2);
|
||||
assertThat(parameters.getMaxDistanceIndex()).isEqualTo(1);
|
||||
@@ -67,7 +68,7 @@ class MongoParametersUnitTests {
|
||||
@Test
|
||||
void doesNotConsiderPointAsNearForSimpleQuery() throws Exception {
|
||||
Method method = PersonRepository.class.getMethod("findByLocationNear", Point.class, Distance.class);
|
||||
MongoParameters parameters = new MongoParameters(method, false);
|
||||
MongoParameters parameters = new MongoParameters(ParametersSource.of(method), false);
|
||||
|
||||
assertThat(parameters.getNearIndex()).isEqualTo(-1);
|
||||
}
|
||||
@@ -77,7 +78,7 @@ class MongoParametersUnitTests {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByLocationNearAndOtherLocation", Point.class, Point.class);
|
||||
|
||||
assertThatIllegalStateException().isThrownBy(() -> new MongoParameters(method, true));
|
||||
assertThatIllegalStateException().isThrownBy(() -> new MongoParameters(ParametersSource.of(method), true));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -85,21 +86,21 @@ class MongoParametersUnitTests {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("invalidDoubleArrays", double[].class, double[].class);
|
||||
|
||||
assertThatIllegalStateException().isThrownBy(() -> new MongoParameters(method, true));
|
||||
assertThatIllegalStateException().isThrownBy(() -> new MongoParameters(ParametersSource.of(method), true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotRejectMultiplePointsForSimpleQueryMethod() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("someOtherMethod", Point.class, Point.class);
|
||||
new MongoParameters(method, false);
|
||||
new MongoParameters(ParametersSource.of(method), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void findsAnnotatedPointForGeoNearQuery() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByOtherLocationAndLocationNear", Point.class, Point.class);
|
||||
MongoParameters parameters = new MongoParameters(method, true);
|
||||
MongoParameters parameters = new MongoParameters(ParametersSource.of(method), true);
|
||||
assertThat(parameters.getNearIndex()).isOne();
|
||||
}
|
||||
|
||||
@@ -107,7 +108,7 @@ class MongoParametersUnitTests {
|
||||
void findsAnnotatedDoubleArrayForGeoNearQuery() throws Exception {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("validDoubleArrays", double[].class, double[].class);
|
||||
MongoParameters parameters = new MongoParameters(method, true);
|
||||
MongoParameters parameters = new MongoParameters(ParametersSource.of(method), true);
|
||||
assertThat(parameters.getNearIndex()).isOne();
|
||||
}
|
||||
|
||||
@@ -115,7 +116,7 @@ class MongoParametersUnitTests {
|
||||
void shouldFindTextCriteriaAtItsIndex() throws SecurityException, NoSuchMethodException {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByNameAndText", String.class, TextCriteria.class);
|
||||
MongoParameters parameters = new MongoParameters(method, false);
|
||||
MongoParameters parameters = new MongoParameters(ParametersSource.of(method), false);
|
||||
assertThat(parameters.getFullTextParameterIndex()).isOne();
|
||||
}
|
||||
|
||||
@@ -123,7 +124,7 @@ class MongoParametersUnitTests {
|
||||
void shouldTreatTextCriteriaParameterAsSpecialParameter() throws SecurityException, NoSuchMethodException {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByNameAndText", String.class, TextCriteria.class);
|
||||
MongoParameters parameters = new MongoParameters(method, false);
|
||||
MongoParameters parameters = new MongoParameters(ParametersSource.of(method), false);
|
||||
assertThat(parameters.getParameter(parameters.getFullTextParameterIndex()).isSpecialParameter()).isTrue();
|
||||
}
|
||||
|
||||
@@ -131,7 +132,7 @@ class MongoParametersUnitTests {
|
||||
void shouldFindMinAndMaxDistanceParameters() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByLocationNear", Point.class, Range.class);
|
||||
MongoParameters parameters = new MongoParameters(method, false);
|
||||
MongoParameters parameters = new MongoParameters(ParametersSource.of(method), false);
|
||||
|
||||
assertThat(parameters.getRangeIndex()).isOne();
|
||||
assertThat(parameters.getMaxDistanceIndex()).isEqualTo(-1);
|
||||
@@ -141,7 +142,7 @@ class MongoParametersUnitTests {
|
||||
void shouldNotHaveMinDistanceIfOnlyOneDistanceParameterPresent() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByLocationNear", Point.class, Distance.class);
|
||||
MongoParameters parameters = new MongoParameters(method, false);
|
||||
MongoParameters parameters = new MongoParameters(ParametersSource.of(method), false);
|
||||
|
||||
assertThat(parameters.getRangeIndex()).isEqualTo(-1);
|
||||
assertThat(parameters.getMaxDistanceIndex()).isOne();
|
||||
@@ -151,7 +152,7 @@ class MongoParametersUnitTests {
|
||||
void shouldReturnMinusOneIfCollationParameterDoesNotExist() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByLocationNear", Point.class, Distance.class);
|
||||
MongoParameters parameters = new MongoParameters(method, false);
|
||||
MongoParameters parameters = new MongoParameters(ParametersSource.of(method), false);
|
||||
|
||||
assertThat(parameters.getCollationParameterIndex()).isEqualTo(-1);
|
||||
}
|
||||
@@ -160,7 +161,7 @@ class MongoParametersUnitTests {
|
||||
void shouldReturnIndexOfCollationParameterIfExists() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findByText", String.class, Collation.class);
|
||||
MongoParameters parameters = new MongoParameters(method, false);
|
||||
MongoParameters parameters = new MongoParameters(ParametersSource.of(method), false);
|
||||
|
||||
assertThat(parameters.getCollationParameterIndex()).isOne();
|
||||
}
|
||||
@@ -169,7 +170,7 @@ class MongoParametersUnitTests {
|
||||
void shouldReturnIndexUpdateIfExists() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("findAndModifyByFirstname", String.class, UpdateDefinition.class, Pageable.class);
|
||||
MongoParameters parameters = new MongoParameters(method, false);
|
||||
MongoParameters parameters = new MongoParameters(ParametersSource.of(method), false);
|
||||
|
||||
assertThat(parameters.getUpdateIndex()).isOne();
|
||||
}
|
||||
@@ -178,7 +179,7 @@ class MongoParametersUnitTests {
|
||||
void shouldReturnInvalidIndexIfUpdateDoesNotExist() throws NoSuchMethodException, SecurityException {
|
||||
|
||||
Method method = PersonRepository.class.getMethod("someOtherMethod", Point.class, Point.class);
|
||||
MongoParameters parameters = new MongoParameters(method, false);
|
||||
MongoParameters parameters = new MongoParameters(ParametersSource.of(method), false);
|
||||
|
||||
assertThat(parameters.getUpdateIndex()).isEqualTo(-1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user