ClassCastException вызвано ошибкой в ​​Just In Time? - PullRequest
2 голосов
/ 11 марта 2010

Учитывая этот кусок кода:

public static void writeFile(File file,List buffer)throws IOException{
    File fic = new File(file.getCanonicalPath());
    cat.debug("writing file : "+fic.getAbsolutePath());
    FileOutputStream out = new FileOutputStream(fic);
    PrintStream ps = new PrintStream(out);
    for(int i=0;i<buffer.size();i++){
        ps.println(buffer.get(i));
    }
    ps.flush();
    ps.close();
    out.close();
}

(пожалуйста, не советуйте, как безопасно закрыть потоки, это устаревший код, а в новой версии используется try / finally)

Я получаю ClassCastException в "ps.println (buffer.get (i))"

этот метод вызывается несколько раз (скажем, 5 раз) со списком, заполненным только строками затем он вызывается со списком, заполненным строкой и другим объектом (скажем, ErrorObject) В тот момент, когда мы достигаем 1-го объекта ErrorObject, мы получаем ClassCastException.

com.mycompany.ErrorObject incompatible with java.lang.String

Эта проблема возникает в производственной среде, но не может быть воспроизведена в среде Dev: Продукт: jvm = IBM J9 VM 2.4 J2RE 1.6.0 IBM J9 2.4 AIX ppc-32 jvmap3260-20081105_25433 (JIT включен, AOT включен) Dev: WinXP, JDK 1.6.0_16

Есть ли какая-то причина, по которой этот код может не работать?

Это было исправлено недавно, я боюсь, что производственная команда не обновила банку правильно, но мой босс уже проверил, что исправление было применено правильно ...

Мне было интересно, может ли компилятор Just in Time «связать» ps.println с ps.println (String) вместо ps.println (Object). Это могло бы объяснить такую ​​проблему, но я понятия не имею, если это возможно.

Любые советы приветствуются, заранее спасибо

РЕДАКТИРОВАТЬ: меня просили полный след стека, вот оно:

java.lang.ClassCastException: com.mycompany.util.ErrorObject incompatible with java.lang.String
    at com.mycompany.util.FileUtils.writeFile(FileUtils.java:91)
    at com.mycompany.util.FileUtils.writeFile(FileUtils.java:50)
    at com.mycompany.itools.task.DBCompareInits.doDBTask(DBCompareInits.java:959)
    at com.mycompany.itools.task.DBTask.doTask(DBTask.java:115)
    at com.mycompany.itools.task.TaskGroup.startGroup(TaskGroup.java:115)
    at com.mycompany.runner.Runner.main(Runner.java:209)

РЕДАКТИРОВАТЬ 2: javap -c

   65:  invokeinterface #20,  1; //InterfaceMethod java/util/List.size:()I
   70:  if_icmpge   92
   73:  aload   4
   75:  aload_1
   76:  iload   5
   78:  invokeinterface #21,  2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
   83:  invokevirtual   #31; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   86:  iinc    5, 1
   89:  goto    62
   92:  aload   4
   94:  invokevirtual   #32; //Method java/io/PrintStream.flush:()V
   97:  aload   4
   99:  invokevirtual   #33; //Method java/io/PrintStream.close:()V
   102: aload_3
   103: invokevirtual   #28; //Method java/io/FileOutputStream.close:()V

Ответы [ 2 ]

4 голосов
/ 11 марта 2010

Мне было интересно, может ли компилятор Just in Time «связать» ps.println с ps.println (String) вместо ps.println (Object). Это могло бы объяснить такую ​​проблему, но я понятия не имею, если это возможно.

Это невозможно. Или, по крайней мере, нет, если нет ошибки компилятора байт-кода или JIT-компилятора. И вы должны винить только ошибки компилятора, если у вас есть неопровержимые доказательства того, что это так.

Однако первое, что я хотел бы проверить, это то, что исполняемый код действительно был скомпилирован из исходного кода, который вы просматриваете. Один из способов подтвердить это - перекомпилировать из исходного кода, а затем сравнить результаты выполнения javap на соответствующих копиях класса. Просмотр байт-кодов также скажет вам, какую перегрузку println говорит использовать компилятор байт-кода.

EDIT - вывод javap ясно показывает, что эта версия байт-кода должна вызывать println(Object), и в поле зрения нет опкода checkcast. Ошибка компилятора JIT, вызывающая неправильный метод и , который самопроизвольно вставляет код для проведения классной трансляции, звучит все более и более неправдоподобно.

0 голосов
/ 11 марта 2010

Объявите метод toString () с преобразованием в строку внутри класса ErrorObject и добавьте + "" к вызову println (). Например, pintln (errorObjList + "");

...