HADOOP-17287. Support new Instance by non default constructor by ReflectionUtils (#2341)

This commit is contained in:
maobaolong 2020-10-01 05:22:55 +08:00 committed by Chao Sun
parent 578370d6c8
commit 4b1c0e4e5b
2 changed files with 51 additions and 2 deletions

View File

@ -122,15 +122,35 @@ public class ReflectionUtils {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T newInstance(Class<T> theClass, Configuration conf) { public static <T> T newInstance(Class<T> theClass, Configuration conf) {
return newInstance(theClass, conf, EMPTY_ARRAY);
}
/** Create an object for the given class and initialize it from conf
*
* @param theClass class of which an object is created
* @param conf Configuration
* @param argTypes the types of the arguments
* @param values the values of the arguments
* @return a new object
*/
@SuppressWarnings("unchecked")
public static <T> T newInstance(Class<T> theClass, Configuration conf,
Class<?>[] argTypes, Object ... values) {
T result; T result;
if (argTypes.length != values.length) {
throw new IllegalArgumentException(argTypes.length
+ " parameters are required but "
+ values.length
+ " arguments are provided");
}
try { try {
Constructor<T> meth = (Constructor<T>) CONSTRUCTOR_CACHE.get(theClass); Constructor<T> meth = (Constructor<T>) CONSTRUCTOR_CACHE.get(theClass);
if (meth == null) { if (meth == null) {
meth = theClass.getDeclaredConstructor(EMPTY_ARRAY); meth = theClass.getDeclaredConstructor(argTypes);
meth.setAccessible(true); meth.setAccessible(true);
CONSTRUCTOR_CACHE.put(theClass, meth); CONSTRUCTOR_CACHE.put(theClass, meth);
} }
result = meth.newInstance(); result = meth.newInstance(values);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@ -28,6 +28,7 @@ import java.util.List;
import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import org.apache.hadoop.test.GenericTestUtils;
import org.apache.hadoop.test.GenericTestUtils.LogCapturer; import org.apache.hadoop.test.GenericTestUtils.LogCapturer;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -168,6 +169,34 @@ public class TestReflectionUtils {
containsString("Process Thread Dump: " + title)); containsString("Process Thread Dump: " + title));
} }
@Test
public void testNewInstanceForNonDefaultConstructor() {
Object x = ReflectionUtils.newInstance(
NoDefaultCtor.class, null, new Class[] {int.class}, 1);
assertTrue(x instanceof NoDefaultCtor);
}
@Test
public void testNewInstanceForNonDefaultConstructorWithException() {
try {
ReflectionUtils.newInstance(
NoDefaultCtor.class, null, new Class[]{int.class}, 1, 2);
fail("Should have failed before this point");
} catch (IllegalArgumentException e) {
GenericTestUtils.assertExceptionContains(
"1 parameters are required but 2 arguments are provided", e);
}
try {
ReflectionUtils.newInstance(
NoDefaultCtor.class, null, new Class[]{int.class});
fail("Should have failed before this point");
} catch (IllegalArgumentException e) {
GenericTestUtils.assertExceptionContains(
"1 parameters are required but 0 arguments are provided", e);
}
}
// Used for testGetDeclaredFieldsIncludingInherited // Used for testGetDeclaredFieldsIncludingInherited
private class Parent { private class Parent {
private int parentField; private int parentField;