Introduce ParametersSource to Parameters.
We now provide a ParametersSource object to create MethodParameter objects associated with the enclosing class so parameters can resolve generics properly. Closes #2996
This commit is contained in:
@@ -18,8 +18,6 @@ package org.springframework.data.repository.query;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link Parameters}.
|
||||
*
|
||||
@@ -31,7 +29,7 @@ public final class DefaultParameters extends Parameters<DefaultParameters, Param
|
||||
* Creates a new {@link DefaultParameters} instance from the given {@link Method}.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @deprecated since 3.1, use {@link #DefaultParameters(Method, TypeInformation)} instead.
|
||||
* @deprecated since 3.1, use {@link #DefaultParameters(ParametersSource)} instead.
|
||||
*/
|
||||
@Deprecated(since = "3.1", forRemoval = true)
|
||||
public DefaultParameters(Method method) {
|
||||
@@ -39,14 +37,13 @@ public final class DefaultParameters extends Parameters<DefaultParameters, Param
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultParameters} instance from the given {@link Method} and aggregate
|
||||
* {@link TypeInformation}.
|
||||
* Creates a new {@link DefaultParameters} instance from the given {@link ParametersSource}.
|
||||
*
|
||||
* @param method must not be {@literal null}.
|
||||
* @param aggregateType must not be {@literal null}.
|
||||
* @param parametersSource must not be {@literal null}.
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public DefaultParameters(Method method, TypeInformation<?> aggregateType) {
|
||||
super(method, param -> new Parameter(param, aggregateType));
|
||||
public DefaultParameters(ParametersSource parametersSource) {
|
||||
super(parametersSource, param -> new Parameter(param, parametersSource.getDomainTypeInformation()));
|
||||
}
|
||||
|
||||
private DefaultParameters(List<Parameter> parameters) {
|
||||
|
||||
@@ -44,7 +44,8 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public abstract class Parameters<S extends Parameters<S, T>, T extends Parameter> implements Streamable<T> {
|
||||
|
||||
public static final List<Class<?>> TYPES = Arrays.asList(ScrollPosition.class, Pageable.class, Sort.class, Limit.class);
|
||||
public static final List<Class<?>> TYPES = Arrays.asList(ScrollPosition.class, Pageable.class, Sort.class,
|
||||
Limit.class);
|
||||
|
||||
private static final String PARAM_ON_SPECIAL = format("You must not use @%s on a parameter typed %s or %s",
|
||||
Param.class.getSimpleName(), Pageable.class.getSimpleName(), Sort.class.getSimpleName());
|
||||
@@ -82,14 +83,30 @@ public abstract class Parameters<S extends Parameters<S, T>, T extends Parameter
|
||||
* @param method must not be {@literal null}.
|
||||
* @param parameterFactory must not be {@literal null}.
|
||||
* @since 3.0.2
|
||||
* @deprecated since 3.2.1, use {@link Parameters(ParametersSource, Function)} instead.
|
||||
*/
|
||||
@Deprecated(since = "3.2.1", forRemoval = true)
|
||||
protected Parameters(Method method, Function<MethodParameter, T> parameterFactory) {
|
||||
this(ParametersSource.of(method), parameterFactory);
|
||||
}
|
||||
|
||||
Assert.notNull(method, "Method must not be null");
|
||||
/**
|
||||
* Creates a new {@link Parameters} instance for the given {@link Method} and {@link Function} to create a
|
||||
* {@link Parameter} instance from a {@link MethodParameter}.
|
||||
*
|
||||
* @param parametersSource must not be {@literal null}.
|
||||
* @param parameterFactory must not be {@literal null}.
|
||||
* @since 3.2.1
|
||||
*/
|
||||
protected Parameters(ParametersSource parametersSource,
|
||||
Function<MethodParameter, T> parameterFactory) {
|
||||
|
||||
Assert.notNull(parametersSource, "ParametersSource must not be null");
|
||||
|
||||
// Factory nullability not enforced yet to support falling back to the deprecated
|
||||
// createParameter(MethodParameter). Add assertion when the deprecation is removed.
|
||||
|
||||
Method method = parametersSource.getMethod();
|
||||
int parameterCount = method.getParameterCount();
|
||||
|
||||
this.parameters = new ArrayList<>(parameterCount);
|
||||
@@ -102,7 +119,9 @@ public abstract class Parameters<S extends Parameters<S, T>, T extends Parameter
|
||||
|
||||
for (int i = 0; i < parameterCount; i++) {
|
||||
|
||||
MethodParameter methodParameter = new MethodParameter(method, i);
|
||||
MethodParameter methodParameter = new MethodParameter(method, i)
|
||||
.withContainingClass(parametersSource.getContainingClass());
|
||||
|
||||
methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
|
||||
|
||||
T parameter = parameterFactory == null //
|
||||
@@ -421,7 +440,9 @@ public abstract class Parameters<S extends Parameters<S, T>, T extends Parameter
|
||||
return !TYPES.contains(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return parameters.iterator();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2023 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
|
||||
*
|
||||
* https://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.repository.query;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Interface providing access to the method, containing class and domain type as source object for parameter
|
||||
* descriptors.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public interface ParametersSource {
|
||||
|
||||
/**
|
||||
* Create a new parameter source for the given {@link Method}.
|
||||
*
|
||||
* @param method the method to use.
|
||||
* @return a new parameter source for the given {@link Method}.
|
||||
*/
|
||||
static ParametersSource of(Method method) {
|
||||
|
||||
Assert.notNull(method, "Method must not be null");
|
||||
|
||||
return new ParametersSource() {
|
||||
|
||||
@Override
|
||||
public Class<?> getContainingClass() {
|
||||
return method.getDeclaringClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeInformation<?> getDomainTypeInformation() {
|
||||
return TypeInformation.OBJECT;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new parameter source for the given {@link Method} in the context of {@link RepositoryMetadata}.
|
||||
*
|
||||
* @param method the method to use.
|
||||
* @return a new parameter source for the given {@link Method}.
|
||||
*/
|
||||
static ParametersSource of(RepositoryMetadata metadata, Method method) {
|
||||
|
||||
Assert.notNull(metadata, "RepositoryMetadata must not be null");
|
||||
Assert.notNull(method, "Method must not be null");
|
||||
|
||||
return new ParametersSource() {
|
||||
|
||||
@Override
|
||||
public Class<?> getContainingClass() {
|
||||
return metadata.getRepositoryInterface();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeInformation<?> getDomainTypeInformation() {
|
||||
return metadata.getDomainTypeInformation();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the class that contains the {@link #getMethod()}.
|
||||
*/
|
||||
Class<?> getContainingClass();
|
||||
|
||||
/**
|
||||
* @return the method for which the parameter source is defined.
|
||||
*/
|
||||
Method getMethod();
|
||||
|
||||
/**
|
||||
* @return the domain type associated with the parameter source.
|
||||
*/
|
||||
TypeInformation<?> getDomainTypeInformation();
|
||||
|
||||
}
|
||||
@@ -183,16 +183,29 @@ public class QueryMethod {
|
||||
* @param method must not be {@literal null}.
|
||||
* @param domainType must not be {@literal null}.
|
||||
* @return must not return {@literal null}.
|
||||
* @deprecated since 3.2.1, use {@link #createParameters(ParametersSource)} instead.
|
||||
* @since 3.0.2
|
||||
*/
|
||||
@Deprecated(since = "3.2.1", forRemoval = true)
|
||||
protected Parameters<?, ?> createParameters(Method method, TypeInformation<?> domainType) {
|
||||
return new DefaultParameters(method, domainType);
|
||||
return createParameters(ParametersSource.of(getMetadata(), method));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Parameters} instance.
|
||||
*
|
||||
* @param parametersSource must not be {@literal null}.
|
||||
* @return must not return {@literal null}.
|
||||
* @since 3.2.1
|
||||
*/
|
||||
protected Parameters<?, ?> createParameters(ParametersSource parametersSource) {
|
||||
return new DefaultParameters(parametersSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method's name.
|
||||
*
|
||||
* @return
|
||||
* @return the method's name.
|
||||
*/
|
||||
public String getName() {
|
||||
return method.getName();
|
||||
|
||||
Reference in New Issue
Block a user