Исключение ClassCastException, вызванное ошибкой в Just In Time?
-
19-09-2019 - |
Вопрос
Учитывая этот фрагмент кода :
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 раз) со списком, заполненным только строками затем он вызывается со списком, заполненным String и другим объектом (скажем, ErrorObject) В тот момент, когда мы достигаем 1-го ErrorObject, мы получаем ClassCastException .
com.mycompany.ErrorObject incompatible with java.lang.String
Эта проблема возникает в рабочей среде, но не может быть воспроизведена в среде разработки :Подталкивать :jvm= IBM J9 VM 2.4 J2RE 1.6.0 IBM J9 2.4 AIX ppc-32 jvmap3260-20081105_25433 (JIT включен, AOT включен) Дев :WinXP, JDK 1.6.0_16
Есть ли какая - либо причина, по которой этот код может выйти из строя?
Он был недавно исправлен, я боюсь, что производственная команда неправильно обновила jar, но мой босс уже проверил, что патч был применен правильно...
Мне было интересно, может ли компилятор 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
Решение
Мне было интересно, может ли компилятор Just in Time "подключить" ps.println к ps.println (String) вместо ps.println (Object).Это могло бы объяснить такую проблему, но я понятия не имею, возможно ли это.
Это невозможно.Или, по крайней мере, нет, если нет ошибки компилятора байт-кода или JIT-компилятора.И вы должны винить ошибки компилятора только в том случае, если у вас есть неопровержимые доказательства того, что это так.
Однако первое, что я бы проверил, это то, что выполняемый код действительно был скомпилирован из исходного кода, который вы просматриваете.Одним из способов подтвердить это было бы перекомпилировать файл из исходного кода, а затем сравнить результаты запуска javap
на соответствующих экземплярах класса.Просмотр байт-кодов также подскажет вам, какая перегрузка println
компилятор байт-кода предлагает использовать.
Редактировать - тот самый javap
выходные данные ясно показывают, что эта версия байт-кода должна вызывать println(Object)
, и нет никакого checkcast
код операции на виду.Ошибка JIT-компилятора, вызывающая неправильный метод и спонтанная вставка кода для создания classcast звучит все более и более неправдоподобно.
Другие советы
Объявите метод toString() с преобразованием в string внутри в классе ErrorObject и добавьте +"" к вызову println().Как pintln(errorObjList+"");