Ver Fonte

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

maobaolong há 4 anos atrás
pai
commit
4b1c0e4e5b

+ 22 - 2
hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/ReflectionUtils.java

@@ -122,15 +122,35 @@ public class ReflectionUtils {
    */
   @SuppressWarnings("unchecked")
   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;
+    if (argTypes.length != values.length) {
+      throw new IllegalArgumentException(argTypes.length
+          + " parameters are required but "
+          + values.length
+          + " arguments are provided");
+    }
     try {
       Constructor<T> meth = (Constructor<T>) CONSTRUCTOR_CACHE.get(theClass);
       if (meth == null) {
-        meth = theClass.getDeclaredConstructor(EMPTY_ARRAY);
+        meth = theClass.getDeclaredConstructor(argTypes);
         meth.setAccessible(true);
         CONSTRUCTOR_CACHE.put(theClass, meth);
       }
-      result = meth.newInstance();
+      result = meth.newInstance(values);
     } catch (Exception e) {
       throw new RuntimeException(e);
     }

+ 29 - 0
hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/util/TestReflectionUtils.java

@@ -28,6 +28,7 @@ import java.util.List;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.*;
 
+import org.apache.hadoop.test.GenericTestUtils;
 import org.apache.hadoop.test.GenericTestUtils.LogCapturer;
 import org.junit.Before;
 import org.junit.Test;
@@ -168,6 +169,34 @@ public class TestReflectionUtils {
         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
   private class Parent {
     private int parentField;