/** * Create a new MethodParameter for the given method or constructor. * <p>This is a convenience factory method for scenarios where a * Method or Constructor reference is treated in a generic fashion. * @param methodOrConstructor the Method or Constructor to specify a parameter for * @param parameterIndex the index of the parameter * @return the corresponding MethodParameter instance * @deprecated as of 5.0, in favor of {@link #forExecutable} */ @Deprecated public static MethodParameter forMethodOrConstructor(Object methodOrConstructor, int parameterIndex) { if (!(methodOrConstructor instanceof Executable)) { throw new IllegalArgumentException( "Given object [" + methodOrConstructor + "] is neither a Method nor a Constructor"); } return forExecutable((Executable) methodOrConstructor, parameterIndex); }
/** * Create a new MethodParameter for the given parameter descriptor. * <p>This is a convenience factory method for scenarios where a * Java 8 {@link Parameter} descriptor is already available. * @param parameter the parameter descriptor * @return the corresponding MethodParameter instance * @since 5.0 */ public static MethodParameter forParameter(Parameter parameter) { return forExecutable(parameter.getDeclaringExecutable(), findParameterIndex(parameter)); }
/** * Create a new MethodParameter for the given parameter descriptor. * <p>This is a convenience factory method for scenarios where a * Java 8 {@link Parameter} descriptor is already available. * @param parameter the parameter descriptor * @return the corresponding MethodParameter instance * @since 5.0 */ public static MethodParameter forParameter(Parameter parameter) { return forExecutable(parameter.getDeclaringExecutable(), findParameterIndex(parameter)); }
@Test // SPR-11044 public void getGenericsOnArrayFromParamCannotBeResolved() throws Exception { MethodParameter methodParameter = MethodParameter.forExecutable( WithArrayBase.class.getDeclaredMethod("array", Object[].class), 0); Class<?> resolved = GenericTypeResolver.resolveParameterType(methodParameter, WithArray.class); assertThat(resolved, equalTo((Class<?>) Object[].class)); }
private Object getErrors(MethodParameter parameter, BindingContext context) { Assert.isTrue(parameter.getParameterIndex() > 0, "Errors argument must be declared immediately after a model attribute argument"); int index = parameter.getParameterIndex() - 1; MethodParameter attributeParam = MethodParameter.forExecutable(parameter.getExecutable(), index); ReactiveAdapter adapter = getAdapterRegistry().getAdapter(attributeParam.getParameterType()); Assert.state(adapter == null, "An @ModelAttribute and an Errors/BindingResult argument " + "cannot both be declared with an async type wrapper. " + "Either declare the @ModelAttribute without an async wrapper type or " + "handle a WebExchangeBindException error signal through the async type."); ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class); String name = (ann != null && StringUtils.hasText(ann.value()) ? ann.value() : Conventions.getVariableNameForParameter(attributeParam)); Object errors = context.getModel().asMap().get(BindingResult.MODEL_KEY_PREFIX + name); Assert.state(errors != null, () -> "An Errors/BindingResult argument is expected " + "immediately after the @ModelAttribute argument to which it applies. " + "For @RequestBody and @RequestPart arguments, please declare them with a reactive " + "type wrapper and use its onError operators to handle WebExchangeBindException: " + parameter.getMethod()); return errors; }
@Test public void forMethodParameter() throws Exception { Method method = Methods.class.getDeclaredMethod("method", Class.class, Object.class); Type type = SerializableTypeWrapper.forMethodParameter(MethodParameter.forExecutable(method, 0)); assertThat(type.toString(), equalTo("java.lang.Class<T>")); assertSerializable(type); }
@Test public void forConstructor() throws Exception { Constructor<?> constructor = Constructors.class.getDeclaredConstructor(List.class); Type type = SerializableTypeWrapper.forMethodParameter(MethodParameter.forExecutable(constructor, 0)); assertThat(type.toString(), equalTo("java.util.List<java.lang.String>")); assertSerializable(type); }
@Test public void forMethodParameter() throws Exception { Method method = Methods.class.getMethod("charSequenceParameter", List.class); MethodParameter methodParameter = MethodParameter.forExecutable(method, 0); ResolvableType type = ResolvableType.forMethodParameter(methodParameter); assertThat(type.getType(), equalTo(method.getGenericParameterTypes()[0])); }
@Test // SPR-16652 public void annotatedConstructorParameterInInnerClass() throws Exception { Constructor<?> constructor = InnerClass.class.getConstructor(getClass(), String.class, Callable.class); MethodParameter methodParameter = MethodParameter.forExecutable(constructor, 0); assertEquals(getClass(), methodParameter.getParameterType()); assertNull(methodParameter.getParameterAnnotation(Param.class)); methodParameter = MethodParameter.forExecutable(constructor, 1); assertEquals(String.class, methodParameter.getParameterType()); assertNotNull("Failed to find @Param annotation", methodParameter.getParameterAnnotation(Param.class)); methodParameter = MethodParameter.forExecutable(constructor, 2); assertEquals(Callable.class, methodParameter.getParameterType()); assertNull(methodParameter.getParameterAnnotation(Param.class)); }
@Test // SPR-16734 public void genericConstructorParameterInInnerClass() throws Exception { Constructor<?> constructor = InnerClass.class.getConstructor(getClass(), String.class, Callable.class); MethodParameter methodParameter = MethodParameter.forExecutable(constructor, 0); assertEquals(getClass(), methodParameter.getParameterType()); assertEquals(getClass(), methodParameter.getGenericParameterType()); methodParameter = MethodParameter.forExecutable(constructor, 1); assertEquals(String.class, methodParameter.getParameterType()); assertEquals(String.class, methodParameter.getGenericParameterType()); methodParameter = MethodParameter.forExecutable(constructor, 2); assertEquals(Callable.class, methodParameter.getParameterType()); assertEquals(ResolvableType.forClassWithGenerics(Callable.class, Integer.class).getType(), methodParameter.getGenericParameterType()); }
@Test public void annotatedConstructorParameterInStaticNestedClass() throws Exception { Constructor<?> constructor = NestedClass.class.getDeclaredConstructor(String.class); MethodParameter methodParameter = MethodParameter.forExecutable(constructor, 0); assertEquals(String.class, methodParameter.getParameterType()); assertNotNull("Failed to find @Param annotation", methodParameter.getParameterAnnotation(Param.class)); }
@Test public void resolveTypeVariableFromMethodParameterType() throws Exception { Method method = Methods.class.getMethod("typedParameter", Object.class); MethodParameter methodParameter = MethodParameter.forExecutable(method, 0); ResolvableType type = ResolvableType.forMethodParameter(methodParameter); assertThat(type.resolve(), nullValue()); assertThat(type.getType().toString(), equalTo("T")); }
@Test // SPR-16210 public void forMethodParameterWithSameSignatureAndGenerics() throws Exception { Method method = Methods.class.getMethod("list1"); MethodParameter methodParameter = MethodParameter.forExecutable(method, -1); ResolvableType type = ResolvableType.forMethodParameter(methodParameter); assertThat(((MethodParameter)type.getSource()).getMethod(), equalTo(method)); method = Methods.class.getMethod("list2"); methodParameter = MethodParameter.forExecutable(method, -1); type = ResolvableType.forMethodParameter(methodParameter); assertThat(((MethodParameter)type.getSource()).getMethod(), equalTo(method)); }
@Test public void resolveTypeVariableFromMethodParameterTypeWithImplementsClass() throws Exception { Method method = Methods.class.getMethod("typedParameter", Object.class); MethodParameter methodParameter = MethodParameter.forExecutable(method, 0); methodParameter.setContainingClass(TypedMethods.class); ResolvableType type = ResolvableType.forMethodParameter(methodParameter); assertThat(type.resolve(), equalTo((Class) String.class)); assertThat(type.getType().toString(), equalTo("T")); }
@Test public void resolveTypeVariableFromMethodParameterTypeWithImplementsType() throws Exception { Method method = Methods.class.getMethod("typedParameter", Object.class); MethodParameter methodParameter = MethodParameter.forExecutable(method, 0); ResolvableType implementationType = ResolvableType.forClassWithGenerics(Methods.class, Integer.class); ResolvableType type = ResolvableType.forMethodParameter(methodParameter, implementationType); assertThat(type.resolve(), equalTo((Class) Integer.class)); assertThat(type.getType().toString(), equalTo("T")); }
@Test @SuppressWarnings("deprecation") public void testFactoryMethods() { assertEquals(stringParameter, MethodParameter.forMethodOrConstructor(method, 0)); assertEquals(longParameter, MethodParameter.forMethodOrConstructor(method, 1)); assertEquals(stringParameter, MethodParameter.forExecutable(method, 0)); assertEquals(longParameter, MethodParameter.forExecutable(method, 1)); assertEquals(stringParameter, MethodParameter.forParameter(method.getParameters()[0])); assertEquals(longParameter, MethodParameter.forParameter(method.getParameters()[1])); }
@Test public void forMethodParameterWithNesting() throws Exception { Method method = Methods.class.getMethod("nested", Map.class); MethodParameter methodParameter = MethodParameter.forExecutable(method, 0); methodParameter.increaseNestingLevel(); ResolvableType type = ResolvableType.forMethodParameter(methodParameter); assertThat(type.resolve(), equalTo((Class) Map.class)); assertThat(type.getGeneric(0).resolve(), equalTo((Class) Byte.class)); assertThat(type.getGeneric(1).resolve(), equalTo((Class) Long.class)); }
@Test public void getSource() throws Exception { Class<?> classType = MySimpleInterfaceType.class; Field basicField = Fields.class.getField("classType"); Field field = Fields.class.getField("charSequenceList"); Method method = Methods.class.getMethod("charSequenceParameter", List.class); MethodParameter methodParameter = MethodParameter.forExecutable(method, 0); assertThat(ResolvableType.forField(basicField).getSource(), equalTo((Object) basicField)); assertThat(ResolvableType.forField(field).getSource(), equalTo((Object) field)); assertThat(ResolvableType.forMethodParameter(methodParameter).getSource(), equalTo((Object) methodParameter)); assertThat(ResolvableType.forMethodParameter(method, 0).getSource(), equalTo((Object) methodParameter)); assertThat(ResolvableType.forClass(classType).getSource(), equalTo((Object) classType)); assertThat(ResolvableType.forClass(classType).getSuperType().getSource(), equalTo((Object) classType.getGenericSuperclass())); }
@Test public void forMethodParameterWithNestingAndLevels() throws Exception { Method method = Methods.class.getMethod("nested", Map.class); MethodParameter methodParameter = MethodParameter.forExecutable(method, 0); methodParameter.increaseNestingLevel(); methodParameter.setTypeIndexForCurrentLevel(0); ResolvableType type = ResolvableType.forMethodParameter(methodParameter); assertThat(type.resolve(), equalTo((Class) Map.class)); assertThat(type.getGeneric(0).resolve(), equalTo((Class) String.class)); assertThat(type.getGeneric(1).resolve(), equalTo((Class) Integer.class)); }
for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) { Object argValue = argsToResolve[argIndex]; MethodParameter methodParam = MethodParameter.forExecutable(executable, argIndex); GenericTypeResolver.resolveParameterType(methodParam, executable.getDeclaringClass()); if (argValue instanceof AutowiredArgumentMarker) {