使用空参数调用Class.newInstance导致IllegalArgumentException

时间:2018-07-25 13:12:49

标签: java dynamic reflection constructor null

我在做什么

我在代码中使用了大量反射,其中一部分是反射性地动态创建类实例。我能够从正在解析的数据中得出所需的类型和参数。我将数据放入Object[]中作为参数传递给Class.newinstance。我在做数据交叉引用程序时,某些参数是null。这意味着我要获取两个数据集,并使用一个通用的Object对其进行交叉引用(我现在要专门制作的那个是Salesrep,但是此代码是动态的,因此可以更改)。这意味着在解析一个数据集时,创建该对象的某些参数应为null,因为它们来自另一数据集。

问题和我尝试过的事情

不幸的是,每当我设置null参数时,我都会得到Illegal Argument Exception声明我有错误的参数数量。我检查了文档中的错误,并说只有在包装失败或参数数量错误时才抛出该错误。我尝试在整个Google上搜索,甚至在某些github仓库中都出现堆栈溢出,而我发现的只是有关method.invoke的一些问题,建议做类似的事情:

//add in non null args to objectArray
Object arg = null;
objectArray.add(arg)
//causes the exception here anyways.
Class.newinstance(objectArray)

我尝试过直接添加null而不包装它,但这也不起作用。请注意,这些构造函数不是空的也不是零参数,它们只有一个,并且我可以确认包括空值在内的参数数目等于所需数目。当参数不为null时,我还可以确认是否传递了正确的类型。我99%确信任何类型的参数都可以为空,或者至少我需要的参数类型确实可以为空(主要是基元和数组或其他集合)。我读过一些地方,当传递null时,它需要正确包装,并且它会将null误认为是空的对象数组参数。老实说,我只是想不通。我创建了一个try catch块,该块打印了我传入的参数数量,它们的类型,并且似乎每次都匹配,但是仍然传递给catch块。这是导致错误的我的代码:

代码及其理解方式

请注意以下几点:firstLineArray是我数据中的String[]构造函数自变量名称。并非所有构造函数参数都在数据集中的一个数据集中,因此此代码采用的参数并将可用数据填充其中。其他设置为null。这使用两个映射完成:argsWeHave将参数名称映射到数据,argsWeNeed将参数名称映射到其类型。这两个映射会看到它们共有的参数名称,并将数据与其类型匹配,并按照构造函数需要的顺序将其传递到argArrayOut中。

for (int j = 0; j < numberOfArgsNeeded; j++) {
        //uses parameter name to match the argument string to its type in the constructor
        //if the parameter name in the constructor isn't found among the param names we have data for OR
        //if the parameter name in the header isn't found among the param names of the constructor, it adds a null element
        //basically if there is an argument the constructor needs, and we have that argument by name.
        if (argWeHave.containsKey(ParamNames[j]) && argWeNeed.containsKey(firstLineArray[i])){
            //DONE fix where argWeNeed.get(firstLineArray[i]) returns null. Handle it gracefully rather than having NPE.
            argArrayOut.add(stringToType(argArrayIn[i],argWeNeed.get(firstLineArray[i])));
            i++;
        }
        //if there is no match set this argument to null
        else{
            //TODO wrap the null value or make it properly accept null as an arg to the object[] for newinstance.
            Object arg = null;
            argArrayOut.add(arg);
        }
    }
    try {
        //form the new instance with the properly formed argArrayOut.
        object_to_add = (ObjectImplementation) constructor.newInstance(argArrayOut);
    } 
    //exception is thrown after the try. It always hits this catch block

这是我的堆栈跟踪。首先是我在catch块中打印到系统的内容:

Class type: Sales_Rep_Data.SalesRep
number of parameters in constructor: 5
number of arguments passed to constructor: 5
Types needed in constructor
class java.lang.String , class java.lang.String , class java.lang.String , 
class java.lang.String , class java.util.ArrayList
Types provided to constructor
class java.lang.String , class java.lang.String , class java.lang.String , 
null , null 

然后是实际的堆栈跟踪:

java.lang.IllegalArgumentException: wrong number of arguments
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:488)
at Sales_Rep_Data.ObjectFactory.getObjectImpl(ObjectFactory.java:79)
at Sales_Rep_Data.SalesRepbyId.Parse(SalesRepbyId.java:27)
at Sales_Rep_Data.Data_Parser.main(Data_Parser.java:45)

如您所见,根据打印的内容,我有所需的编号和类型。我只是无法理解为什么会发生此错误。这一定是一些远程包装要求,或者是我很愚蠢的事情。欢迎任何有关代码可读性的建议。该代码无法单独运行,它需要大量其他代码,这只是我的ObjectFactory类的摘录。

1 个答案:

答案 0 :(得分:1)

问题似乎在于您传递的是 $scope.changeDocument = function (applyFilter) { if (applyFilter === true) { //Here is where I cant access $scope } }而不是数组:

List

您需要执行以下操作:

object_to_add = (ObjectImplementation) constructor.newInstance(argArrayOut);
//                                              Passing a List ^^^^^^^^^^^

您没有在帖子中说object_to_add = (ObjectImplementation) constructor.newInstance(argArrayOut.toArray()); argArrayOut,但显然是一个,因为您在其上调用了List方法。