2014-02-18 5 views
0

Итак, вот в чем проблема. Я пытаюсь использовать отражение в Java, чтобы определить тип «представления» для вывода на лист Excel через объявления упорядоченного метода. (упорядоченно численно)Ошибка Spooky Java Reflection

, и теоретически это должно работать нормально, и это точно.

Проблема в том, что отражающий метод, по-видимому, случайно решает работать иногда, а не другие. Он не бросает исключение, он находит имена методов без каких-либо проблем, но как только он попадает в логическую проверку для того, запускается метод с соответствующим тегом, он иногда останавливается при 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))) бы начать неудачу при у = 5 ИНОГДА

Во всяком случае, если у кого есть какие-либо идеи, я действительно ценю это. Я довольно застрял здесь.

Следует также отметить, что j = 5 каждый раз будет использоваться для предложения данных, которое я дал ему. Что выделяется для меня как нечто большее, чем совпадение, но я не вижу в этом ничего плохого.

EDIT

Стоит также ничего такого, что вероятность этого работает точно так, как ожидалось (вытаскивая все правильно перечисленных методов, и т.д.) значительно увеличивает (близко к 99% рабочий), если я запустить операцию на 'm' перед булевой проверкой. Например, как я распечатываю это логическое выражение непосредственно перед фактическим утверждением? что заставило его работать почти каждый раз. Но это, безусловно, не может быть решением.

EDIT # 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 application). Если java не искроет новый поток для рефлексивного вызова, о котором я не знал, я не вижу, что это проблема. Jon skeet - к сожалению, это относительно нетривиальная задача придумать пример поддержки, который имеет те же характеристики. Вероятно, этот метод содержит около 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; 

} 

Это хороший урок, когда вы пытаетесь навязать заказ на неотъемлемо маркированный список, убедитесь, что вы будете осторожны, потому что если вы запутались его (например, меня!) будет чувствовать себя ОЧЕНЬ неопределенное поведение.