Domanda

Dato questo pezzo di codice:

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();
}

(si prega di nessun consiglio su come chiudere i flussi in modo sicuro, questo è il codice legacy e la nuova versione si avvale di try / finally)

ho un ClassCastException al "ps.println (BUFFER.GET (i))"

Questo metodo viene chiamato più volte (diciamo 5 volte) con un elenco riempito solo con le stringhe quindi, è chiamato con una lista riempito con String e un altro oggetto (dire ErrorObject) Al punto raggiungiamo il primo ErrorObject, otteniamo la ClassCastException.

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

Questo problema si verifica in ambiente di produzione, ma non può essere riprodotto in ambiente dev: Prod: jvm = IBM J9 VM 2.4 J2RE 1.6.0 IBM J9 2.4 AIX ppc-32 jvmap3260-20081105_25433 (JIT abilitato, AOT abilitata) Dev: WinXP, JDK 1.6.0_16

C'è un motivo questo codice potrebbe fallire?

E 'stato patchato da poco, temo che il team di produzione non aggiornare il vaso in modo corretto, ma il mio capo già verificato che la patch è stata applicata correclty ...

Mi chiedevo se il Just in Time compilatore potrebbe "filo" la ps.println al ps.println (String) al posto del ps.println (Object).  Questo potrebbe spiegare un tale problema, ma non ho idea se questo possibile.

Le eventuali consigli benvenuti, vi ringrazio in anticipo

EDIT: mi è stato chiesto piena traccia dello stack così qui è:

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)

EDIT 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
È stato utile?

Soluzione

  

Mi chiedevo se il Just in Time compilatore potrebbe "filo" la ps.println al ps.println (String) al posto del ps.println (Object). Questo potrebbe spiegare un tale problema, ma non ho idea se questo possibile.

Non è possibile. O almeno non meno che ci sia un compilatore bytecode o compilatore JIT bug. E si dovrebbe dare la colpa solo bug del compilatore se avete la prova inconfutabile che sia così.

Tuttavia, la prima cosa che vorrei verificare è che il codice viene eseguito è stato davvero compilato dal codice sorgente che si sta guardando. Un modo per confermare questo sarebbe ricompilare dalla fonte, e quindi confrontare i risultati dell'esecuzione javap sulle rispettive copie della classe. Guardando i bytecode vi dirà anche che il sovraccarico di println compilatore bytecode sta dicendo da usare.

Modifica - l'uscita javap mostra chiaramente che tale versione del bytecode dovrebbe chiamare println(Object), e non c'è nessun codice operativo checkcast in vista. Un bug compilatore JIT che chiama il metodo sbagliato e inserisce spontaneamente codice per fare un classcast suona sempre più plausibile.

Altri suggerimenti

Dichiarare il metodo toString () con la conversione in stringa all'interno della classe ErrorObject e aggiungere + "" per println () chiamata. Come pintln (errorObjList + "");

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top