2014-02-18 61 views
0

所以,這是問題所在。我試圖在Java中使用反射來定義一種類型的'視圖',通過有序的方法聲明輸出到Excel表格。 (以數字順序)幽靈般的Java反射錯誤

從理論上講,這應該工作得很好,而且確實如此。

問題是,反射方法似乎隨機決定有時工作,而不是其他人。它不會引發異常,它會毫無問題地找到方法名稱,但只要它檢測到方法是否以適當的標記開始,就會在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(){} 

等等,等等,我給了這種方法的標籤「得到」會退出所有三個指定順序的方法。此外,它的使用這個特定的方法的要求定義爲返回值都是字符串,所以這不是我很確定的問題。 奇怪的是我不明白爲什麼上線if (m.getName().startsWith((tag + j)))布爾檢查將開始與j =失敗5 SOMETIMES

無論如何,如果任何人有任何想法,我會很感激。我很困難。

同樣值得注意的是,對於我給它的數據集,j = 5將成爲每次「else」子句。這對我來說不僅僅是巧合,而且我也看不出有什麼問題。

編輯

這也是一文不值,如果我運行一個操作它究竟是按預期工作(拉出所有正確的枚舉法等)的概率顯著上升(接近99%的工作)在布爾檢查之前'm'。比如我如何在實際陳述之前打印出布爾語句?這使得它幾乎每一次都能正常工作。但這當然不能解決問題。

編輯#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 
+2

我們很難只用部分代碼來幫助你,但是包含我們真正不需要的東西的那部分代碼。如果你能夠提供一個簡短而完整的程序來展示問題,那麼將會更容易幫助你。此外,鑑於你有日誌記錄,這將有助於如果你顯示日誌... –

+2

偶爾工作會讓我懷疑線程問題。這種方法你沒有同步。 myExcelWriter看起來像一個共享的可變數據成員。如果是的話,看看這是否是根本原因。 – duffymo

+0

@duffymo我同意,它感覺像一個線程的問題,但這是所有主要(javafx應用程序)線程運行。除非Java引發一個我不知道的反射調用的新線程,否則我看不出這是問題所在。 喬恩斯威特 - 不幸的是,提出一個具有相同特徵的支持示例是一項相對不重要的任務。這種方法可能有大約2000行支持代碼。我可能在一段時間後嘗試一起破解一些東西來重現小規模的行爲。 – WillBD

回答

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; 

} 

這是一個很好的教訓,當你嘗試一種固有的非有序列表上強加一個秩序,確保你小心,因爲如果你搞砸了(如我!)它會覺得非常不確定的行爲。