Merge branch '5.3.x'
This commit is contained in:
commit
170d6dd5f2
|
|
@ -37,7 +37,7 @@ import org.springframework.util.ObjectUtils;
|
|||
|
||||
/**
|
||||
* Contextual descriptor about a type to convert from or to.
|
||||
* Capable of representing arrays and generic collection types.
|
||||
* <p>Capable of representing arrays and generic collection types.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Andy Clement
|
||||
|
|
@ -345,9 +345,9 @@ public class TypeDescriptor implements Serializable {
|
|||
* from the provided collection or array element.
|
||||
* <p>Narrows the {@link #getElementTypeDescriptor() elementType} property to the class
|
||||
* of the provided collection or array element. For example, if this describes a
|
||||
* {@code java.util.List<java.lang.Number<} and the element argument is an
|
||||
* {@code java.util.List<java.lang.Number>} and the element argument is a
|
||||
* {@code java.lang.Integer}, the returned TypeDescriptor will be {@code java.lang.Integer}.
|
||||
* If this describes a {@code java.util.List<?>} and the element argument is an
|
||||
* If this describes a {@code java.util.List<?>} and the element argument is a
|
||||
* {@code java.lang.Integer}, the returned TypeDescriptor will be {@code java.lang.Integer}
|
||||
* as well.
|
||||
* <p>Annotation and nested type context will be preserved in the narrowed
|
||||
|
|
@ -388,9 +388,9 @@ public class TypeDescriptor implements Serializable {
|
|||
* from the provided map key.
|
||||
* <p>Narrows the {@link #getMapKeyTypeDescriptor() mapKeyType} property
|
||||
* to the class of the provided map key. For example, if this describes a
|
||||
* {@code java.util.Map<java.lang.Number, java.lang.String<} and the key
|
||||
* {@code java.util.Map<java.lang.Number, java.lang.String>} and the key
|
||||
* argument is a {@code java.lang.Integer}, the returned TypeDescriptor will be
|
||||
* {@code java.lang.Integer}. If this describes a {@code java.util.Map<?, ?>}
|
||||
* {@code java.lang.Integer}. If this describes a {@code java.util.Map<?, ?>}
|
||||
* and the key argument is a {@code java.lang.Integer}, the returned
|
||||
* TypeDescriptor will be {@code java.lang.Integer} as well.
|
||||
* <p>Annotation and nested type context will be preserved in the narrowed
|
||||
|
|
@ -425,9 +425,9 @@ public class TypeDescriptor implements Serializable {
|
|||
* from the provided map value.
|
||||
* <p>Narrows the {@link #getMapValueTypeDescriptor() mapValueType} property
|
||||
* to the class of the provided map value. For example, if this describes a
|
||||
* {@code java.util.Map<java.lang.String, java.lang.Number<} and the value
|
||||
* {@code java.util.Map<java.lang.String, java.lang.Number>} and the value
|
||||
* argument is a {@code java.lang.Integer}, the returned TypeDescriptor will be
|
||||
* {@code java.lang.Integer}. If this describes a {@code java.util.Map<?, ?>}
|
||||
* {@code java.lang.Integer}. If this describes a {@code java.util.Map<?, ?>}
|
||||
* and the value argument is a {@code java.lang.Integer}, the returned
|
||||
* TypeDescriptor will be {@code java.lang.Integer} as well.
|
||||
* <p>Annotation and nested type context will be preserved in the narrowed
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
|
|
@ -44,7 +44,7 @@ public interface TypeConverter {
|
|||
* Convert (or coerce) a value from one type to another, for example from a
|
||||
* {@code boolean} to a {@code String}.
|
||||
* <p>The {@link TypeDescriptor} parameters enable support for typed collections:
|
||||
* A caller may prefer a {@code List<Integer>}, for example, rather than
|
||||
* A caller may prefer a {@code List<Integer>}, for example, rather than
|
||||
* simply any {@code List}.
|
||||
* @param value the value to be converted
|
||||
* @param sourceType a type descriptor that supplies extra information about the
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
|
|
@ -38,6 +38,7 @@ import org.springframework.util.MethodInvoker;
|
|||
*
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class ReflectionHelper {
|
||||
|
|
@ -281,25 +282,32 @@ public abstract class ReflectionHelper {
|
|||
arguments[i] = converter.convertValue(argument, TypeDescriptor.forObject(argument), targetType);
|
||||
conversionOccurred |= (argument != arguments[i]);
|
||||
}
|
||||
|
||||
MethodParameter methodParam = MethodParameter.forExecutable(executable, varargsPosition);
|
||||
|
||||
// If the target is varargs and there is just one more argument, then convert it here.
|
||||
if (varargsPosition == arguments.length - 1) {
|
||||
// If the target is varargs and there is just one more argument
|
||||
// then convert it here
|
||||
TypeDescriptor targetType = new TypeDescriptor(methodParam);
|
||||
Object argument = arguments[varargsPosition];
|
||||
TypeDescriptor targetType = new TypeDescriptor(methodParam);
|
||||
TypeDescriptor sourceType = TypeDescriptor.forObject(argument);
|
||||
arguments[varargsPosition] = converter.convertValue(argument, sourceType, targetType);
|
||||
// Three outcomes of that previous line:
|
||||
// 1) the input argument was already compatible (ie. array of valid type) and nothing was done
|
||||
// 2) the input argument was correct type but not in an array so it was made into an array
|
||||
// 3) the input argument was the wrong type and got converted and put into an array
|
||||
// If the argument type is equal to the varargs element type, there is no need
|
||||
// to convert it or wrap it in an array. For example, using StringToArrayConverter
|
||||
// to convert a String containing a comma would result in the String being split
|
||||
// and repackaged in an array when it should be used as-is.
|
||||
if (!sourceType.equals(targetType.getElementTypeDescriptor())) {
|
||||
arguments[varargsPosition] = converter.convertValue(argument, sourceType, targetType);
|
||||
}
|
||||
// Three outcomes of the above if-block:
|
||||
// 1) the input argument was correct type but not wrapped in an array, and nothing was done.
|
||||
// 2) the input argument was already compatible (i.e., array of valid type), and nothing was done.
|
||||
// 3) the input argument was the wrong type and got converted and wrapped in an array.
|
||||
if (argument != arguments[varargsPosition] &&
|
||||
!isFirstEntryInArray(argument, arguments[varargsPosition])) {
|
||||
conversionOccurred = true; // case 3
|
||||
}
|
||||
}
|
||||
// Otherwise, convert remaining arguments to the varargs element type.
|
||||
else {
|
||||
// Convert remaining arguments to the varargs element type
|
||||
TypeDescriptor targetType = new TypeDescriptor(methodParam).getElementTypeDescriptor();
|
||||
Assert.state(targetType != null, "No element type");
|
||||
for (int i = varargsPosition; i < arguments.length; i++) {
|
||||
|
|
@ -332,8 +340,8 @@ public abstract class ReflectionHelper {
|
|||
}
|
||||
|
||||
/**
|
||||
* Package up the arguments so that they correctly match what is expected in parameterTypes.
|
||||
* For example, if parameterTypes is {@code (int, String[])} because the second parameter
|
||||
* Package up the arguments so that they correctly match what is expected in requiredParameterTypes.
|
||||
* <p>For example, if requiredParameterTypes is {@code (int, String[])} because the second parameter
|
||||
* was declared {@code String...}, then if arguments is {@code [1,"a","b"]} then it must be
|
||||
* repackaged as {@code [1,new String[]{"a","b"}]} in order to match the expected types.
|
||||
* @param requiredParameterTypes the types of the parameters for the invocation
|
||||
|
|
@ -350,23 +358,24 @@ public abstract class ReflectionHelper {
|
|||
requiredParameterTypes[parameterCount - 1] !=
|
||||
(args[argumentCount - 1] != null ? args[argumentCount - 1].getClass() : null)) {
|
||||
|
||||
int arraySize = 0; // zero size array if nothing to pass as the varargs parameter
|
||||
if (argumentCount >= parameterCount) {
|
||||
arraySize = argumentCount - (parameterCount - 1);
|
||||
}
|
||||
|
||||
// Create an array for the varargs arguments
|
||||
// Create an array for the leading arguments plus the varargs array argument.
|
||||
Object[] newArgs = new Object[parameterCount];
|
||||
// Copy all leading arguments to the new array, omitting the varargs array argument.
|
||||
System.arraycopy(args, 0, newArgs, 0, newArgs.length - 1);
|
||||
|
||||
// Now sort out the final argument, which is the varargs one. Before entering this method,
|
||||
// the arguments should have been converted to the box form of the required type.
|
||||
Class<?> componentType = requiredParameterTypes[parameterCount - 1].getComponentType();
|
||||
Object repackagedArgs = Array.newInstance(componentType, arraySize);
|
||||
for (int i = 0; i < arraySize; i++) {
|
||||
Array.set(repackagedArgs, i, args[parameterCount - 1 + i]);
|
||||
int varargsArraySize = 0; // zero size array if nothing to pass as the varargs parameter
|
||||
if (argumentCount >= parameterCount) {
|
||||
varargsArraySize = argumentCount - (parameterCount - 1);
|
||||
}
|
||||
newArgs[newArgs.length - 1] = repackagedArgs;
|
||||
Class<?> componentType = requiredParameterTypes[parameterCount - 1].getComponentType();
|
||||
Object varargsArray = Array.newInstance(componentType, varargsArraySize);
|
||||
for (int i = 0; i < varargsArraySize; i++) {
|
||||
Array.set(varargsArray, i, args[parameterCount - 1 + i]);
|
||||
}
|
||||
// Finally, add the varargs array to the new arguments array.
|
||||
newArgs[newArgs.length - 1] = varargsArray;
|
||||
return newArgs;
|
||||
}
|
||||
return args;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
|
|
@ -46,6 +46,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
|||
*
|
||||
* @author Andy Clement
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class MethodInvocationTests extends AbstractExpressionTests {
|
||||
|
||||
|
|
@ -233,26 +234,54 @@ public class MethodInvocationTests extends AbstractExpressionTests {
|
|||
|
||||
@Test
|
||||
public void testVarargsInvocation01() {
|
||||
// Calling 'public int aVarargsMethod(String... strings)'
|
||||
//evaluate("aVarargsMethod('a','b','c')", 3, Integer.class);
|
||||
//evaluate("aVarargsMethod('a')", 1, Integer.class);
|
||||
// Calling 'public int aVarargsMethod(String... strings)' - returns number of arguments
|
||||
evaluate("aVarargsMethod('a','b','c')", 3, Integer.class);
|
||||
evaluate("aVarargsMethod('a')", 1, Integer.class);
|
||||
evaluate("aVarargsMethod()", 0, Integer.class);
|
||||
evaluate("aVarargsMethod(1,2,3)", 3, Integer.class); // all need converting to strings
|
||||
evaluate("aVarargsMethod(1)", 1, Integer.class); // needs string conversion
|
||||
evaluate("aVarargsMethod(1,'a',3.0d)", 3, Integer.class); // first and last need conversion
|
||||
// evaluate("aVarargsMethod(new String[]{'a','b','c'})", 3, Integer.class);
|
||||
evaluate("aVarargsMethod(new String[]{'a','b','c'})", 3, Integer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarargsInvocation02() {
|
||||
// Calling 'public int aVarargsMethod2(int i, String... strings)' - returns int+length_of_strings
|
||||
// Calling 'public int aVarargsMethod2(int i, String... strings)' - returns int + length_of_strings
|
||||
evaluate("aVarargsMethod2(5,'a','b','c')", 8, Integer.class);
|
||||
evaluate("aVarargsMethod2(2,'a')", 3, Integer.class);
|
||||
evaluate("aVarargsMethod2(4)", 4, Integer.class);
|
||||
evaluate("aVarargsMethod2(8,2,3)", 10, Integer.class);
|
||||
evaluate("aVarargsMethod2(9)", 9, Integer.class);
|
||||
evaluate("aVarargsMethod2(2,'a',3.0d)", 4, Integer.class);
|
||||
// evaluate("aVarargsMethod2(8,new String[]{'a','b','c'})", 11, Integer.class);
|
||||
evaluate("aVarargsMethod2(8,new String[]{'a','b','c'})", 11, Integer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVarargsInvocation03() {
|
||||
// Calling 'public int aVarargsMethod3(String str1, String... strings)' - returns all strings concatenated with "-"
|
||||
|
||||
// No conversion necessary
|
||||
evaluate("aVarargsMethod3('x')", "x", String.class);
|
||||
evaluate("aVarargsMethod3('x', 'a')", "x-a", String.class);
|
||||
evaluate("aVarargsMethod3('x', 'a', 'b', 'c')", "x-a-b-c", String.class);
|
||||
|
||||
// Conversion necessary
|
||||
evaluate("aVarargsMethod3(9)", "9", String.class);
|
||||
evaluate("aVarargsMethod3(8,2,3)", "8-2-3", String.class);
|
||||
evaluate("aVarargsMethod3('2','a',3.0d)", "2-a-3.0", String.class);
|
||||
evaluate("aVarargsMethod3('8',new String[]{'a','b','c'})", "8-a-b-c", String.class);
|
||||
|
||||
// Individual string contains a comma with multiple varargs arguments
|
||||
evaluate("aVarargsMethod3('foo', ',', 'baz')", "foo-,-baz", String.class);
|
||||
evaluate("aVarargsMethod3('foo', 'bar', ',baz')", "foo-bar-,baz", String.class);
|
||||
evaluate("aVarargsMethod3('foo', 'bar,', 'baz')", "foo-bar,-baz", String.class);
|
||||
|
||||
// Individual string contains a comma with single varargs argument.
|
||||
// Reproduces https://github.com/spring-projects/spring-framework/issues/27582
|
||||
evaluate("aVarargsMethod3('foo', ',')", "foo-,", String.class);
|
||||
evaluate("aVarargsMethod3('foo', ',bar')", "foo-,bar", String.class);
|
||||
evaluate("aVarargsMethod3('foo', 'bar,')", "foo-bar,", String.class);
|
||||
evaluate("aVarargsMethod3('foo', 'bar,baz')", "foo-bar,baz", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2021 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.
|
||||
|
|
@ -28,6 +28,7 @@ import org.springframework.util.ObjectUtils;
|
|||
///CLOVER:OFF
|
||||
@SuppressWarnings("unused")
|
||||
public class Inventor {
|
||||
|
||||
private String name;
|
||||
public String _name;
|
||||
public String _name_;
|
||||
|
|
@ -202,8 +203,14 @@ public class Inventor {
|
|||
return strings.length + i;
|
||||
}
|
||||
|
||||
public Inventor(String... strings) {
|
||||
public String aVarargsMethod3(String str1, String... strings) {
|
||||
if (ObjectUtils.isEmpty(strings)) {
|
||||
return str1;
|
||||
}
|
||||
return str1 + "-" + String.join("-", strings);
|
||||
}
|
||||
|
||||
public Inventor(String... strings) {
|
||||
}
|
||||
|
||||
public boolean getSomeProperty() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue