怪异的Java反射错误

时间:2014-02-18 15:33:57

标签: java excel reflection

所以,这就是问题所在。我试图在Java中使用反射来定义一种“视图”类型,以便通过有序方法声明输出到Excel工作表。 (以数字方式订购)

理论上,这应该工作得很好,而且确实如此。

问题在于,反射方法似乎随机决定有时工作,而不是其他工作。它不会抛出异常,它会毫无困难地找到方法名称,但只要它检测到方法是否以适当的标记开头,它就会立即停止在j = 5处。这是代码方法澄清:

public boolean objectWriter(List<Object> input, String sheetName, int startingRow, String tag){
    ArrayList<Object> myList = new ArrayList<>();
    jxl.write.Number number;
    Label label;

    //This is just an internal counter since we're using a for-each loop. 
    int j;
    try{
        for (int i = 0; i < input.size(); i++){
            j = 0;
            //we want to iterate over all of the available methods in the given class with reflection
            for (Method m: input.get(i).getClass().getMethods()){
                //Check to see if the method name has our requested tag, plus the appropriate counter
                //tacked on, and ZERO parameters, in our case.
                myLog.debug("this is our boolean check: " + m.getName().startsWith((tag + j)));
                if (m.getName().startsWith((tag + j))){
                    myLog.debug("m.getname inside: " + m.getName());
                    //Invoke the method, give it's return value to r (return)
                    final Object r = m.invoke(input.get(i));
                    //Since we defined in the requirements of this class that it must be a string
                    //those types of methods returned, this works just fine, just case it to
                    //String (Since String extends object) and call it a day. 
                    if (isNumeric((String)r)){
                        //if it's a number, make a number object out of it. 
                        number = new jxl.write.Number(j, startingRow + i
                        , Double.parseDouble((String)r)
                        , buildNumberFormat((String)r));

                        myList.add(number);
                    }else{
                        label = new Label(j,startingRow + i,(String)r);
                        myList.add(label);
                    }
                    j++;
                }
            }
        }
    }catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException ex){
        myLog.error("There was an error working through the point class with reflection.", ex);
        return false;
    }
    boolean successfulWrite = myExcelWriter.writeInformation(myList, sheetName);
    myExcelWriter.resizeColumns(18, sheetName);
    return successfulWrite;

}

因此,正如您在上面所看到的,它反过来在方法名称中查找调用者定义的“标记”以及数字。所以,如果我有一个类似的方法:

public String get0(){}
public String get1(){}
public String get2(){}

等。我给了这个方法标签'get'它会以指定的顺序拉出所有这三个方法。此外,它在使用这个特定方法的要求中定义了所有字符串的返回值,所以这不是我非常肯定的问题。 奇怪的是我无法理解为什么线if (m.getName().startsWith((tag + j)))上的布尔检查会在j = 5时开始失败 某些

无论如何,如果有人有任何想法,我真的很感激。我被困在这里了。

值得注意的是,每次我给出的数据集时,j = 5将成为'else'子句。这对我来说不仅仅是巧合,但我看不出它有什么不妥。

修改

如果我在布尔检查之前在'm'上运行一个操作,那么它完全按预期工作的概率(拉出所有正确枚举的方法等)的增加也是非常值得的(接近99%工作) 。比如如何在实际声明之前打印出那个布尔语句?这使它几乎每次都有效。但这肯定不是解决方案。

编辑#2 根据要求,我继续将println移动到调试日志,这是一个截断版本,但它基本上重复了29次内的模式,也很有趣,似乎如果我将输出发送到我的记录器而不是控制台,前面提到的成功概率可以追溯到没有它的情况......奇怪......

09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,881 DEBUG [root] this is our boolean check: false
09:02:45,882 DEBUG [root] this is our boolean check: false
09:02:45,882 DEBUG [root] this is our boolean check: false
09:02:45,882 DEBUG [root] this is our boolean check: false
09:02:45,882 DEBUG [root] this is our boolean check: false
09:02:45,882 DEBUG [root] this is our boolean check: true
09:02:45,882 DEBUG [root] m.getname inside: xGet0Label
09:02:45,882 DEBUG [root] this is our boolean check: true
09:02:45,882 DEBUG [root] m.getname inside: xGet1MD
09:02:45,882 DEBUG [root] this is our boolean check: true
09:02:45,882 DEBUG [root] m.getname inside: xGet2Easting
09:02:45,882 DEBUG [root] this is our boolean check: true
09:02:45,882 DEBUG [root] m.getname inside: xGet3Northing
09:02:45,882 DEBUG [root] this is our boolean check: true
09:02:45,882 DEBUG [root] m.getname inside: xGet4TVD
09:02:45,882 DEBUG [root] this is our boolean check: true
09:02:45,882 DEBUG [root] m.getname inside: xGet5Date
09:02:45,882 DEBUG [root] this is our boolean check: false
09:02:45,882 DEBUG [root] this is our boolean check: false
09:02:45,882 DEBUG [root] this is our boolean check: false
09:02:45,882 DEBUG [root] this is our boolean check: false
09:02:45,882 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,883 DEBUG [root] this is our boolean check: false
09:02:45,884 DEBUG [root] this is our boolean check: false
09:02:45,884 DEBUG [root] this is our boolean check: false
09:02:45,884 DEBUG [root] this is our boolean check: false
09:02:45,884 DEBUG [root] this is our boolean check: false
09:02:45,884 DEBUG [root] this is our boolean check: true
09:02:45,884 DEBUG [root] m.getname inside: xGet0Label
09:02:45,884 DEBUG [root] this is our boolean check: true
09:02:45,884 DEBUG [root] m.getname inside: xGet1MD
09:02:45,884 DEBUG [root] this is our boolean check: true
09:02:45,884 DEBUG [root] m.getname inside: xGet2Easting
09:02:45,884 DEBUG [root] this is our boolean check: true
09:02:45,884 DEBUG [root] m.getname inside: xGet3Northing
09:02:45,884 DEBUG [root] this is our boolean check: true
09:02:45,884 DEBUG [root] m.getname inside: xGet4TVD
09:02:45,884 DEBUG [root] this is our boolean check: true
09:02:45,884 DEBUG [root] m.getname inside: xGet5Date

1 个答案:

答案 0 :(得分:1)

想出来!因此,我正在接近正在检查的方法的“排序”方式存在固有的错误。虽然我预计'getMethods()'会以一种特定的顺序返回类的方法,但如果其中一种方法以错误的顺序找到我,它永远不会被重新检查!它是简单地说,有时数字排序的第一种方法会在后来的方法之前出现,导致正确的行为。最常见的是,编号方法0-5将在6-14之后出现(这是该数据集中的范围)。

所以,我的解决方案是创建一个被拒绝的方法名称的“池”,然后每次检查失败时,遍历拒绝池,并确保其中一个不符合要求。如果不是那些,那不是我们关心的方法。

这会减慢触摸的速度,但它在毫秒范围内。

解决方案代码:

public boolean objectWriter(List<Object> input, String sheetName, int startingRow, String tag){
    ArrayList<Object> myList = new ArrayList<>();
    ArrayList<Method> methodList = new ArrayList<>();
    jxl.write.Number number;
    Label label;

    //This is just an internal counter since we're using a for-each loop. 
    int j;
    try{
        for (int i = 0; i < input.size(); i++){
            j = 0;
            //we want to iterate over all of the available methods in the given class with reflection
            for (Method m: input.get(i).getClass().getDeclaredMethods()){
                //Check to see if the method name has our requested tag, plus the appropriate counter
                //tacked on, and ZERO parameters, in our case.
                if (m.getName().startsWith((tag + j))){
                    //Invoke the method, give it's return value to r (return)
                    final Object r = m.invoke(input.get(i));
                    //Since we defined in the requirements of this class that it must be a string
                    //those types of methods returned, this works just fine, just case it to
                    //String (Since String extends object) and call it a day. 
                    if (isNumeric((String)r)){
                        //if it's a number, make a number object out of it. 
                        number = new jxl.write.Number(j, startingRow + i
                        , Double.parseDouble((String)r)
                        , buildNumberFormat((String)r));

                        myList.add(number);
                    }else{
                        label = new Label(j,startingRow + i,(String)r);
                        myList.add(label);
                    }
                    j++;
                }else{
                    methodList.add(m);
                    for (int x = 0; x < methodList.size(); x++){
                        if (methodList.get(x).getName().startsWith((tag + j))){
                            //Invoke the method, give it's return value to r (return)
                            final Object r = methodList.get(x).invoke(input.get(i));
                            //Since we defined in the requirements of this class that it must be a string
                            //those types of methods returned, this works just fine, just case it to
                            //String (Since String extends object) and call it a day. 
                            if (isNumeric((String)r)){
                                //if it's a number, make a number object out of it. 
                                number = new jxl.write.Number(j, startingRow + i
                                , Double.parseDouble((String)r)
                                , buildNumberFormat((String)r));

                                myList.add(number);
                            }else{
                                label = new Label(j,startingRow + i,(String)r);
                                myList.add(label);
                            }
                            j++;
                            //methodList.remove(x);
                            break;
                        }
                    }
                }
            }
        }
    }catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException ex){
        myLog.error("There was an error working through the point class with reflection.", ex);
        return false;
    }
    boolean successfulWrite = myExcelWriter.writeInformation(myList, sheetName);
    myExcelWriter.resizeColumns(18, sheetName);
    return successfulWrite;

}

这是一个很好的教训,当你试图在一个固有的无序列表上强加一个订单时,请确保你很小心,因为如果你搞砸了(像我一样!)它会感觉非常不明确的行为。