2013-07-30 17 views
6

Ho riscontrato un problema durante il tentativo di trasferire un'applicazione su JApplet in modo che possa essere eseguito su un browser.Impossibile caricare la definizione di classe dal jar

Contenuto

programma:

  1. file JAR. Contiene la mia implementazione CustomClassLoader. Memorizzato sul sito Web.
  2. Directory dei contenuti. Pieno di lezioni compilate. Memorizzato sul computer degli utenti.

Problema:

sto ottenendo un NoClassDefFoundError quando si tenta di caricare i file nella directory di contenuti .class con la mia CustomClassLoader.

L'errore, sebbene irraggiungibile, si riferisce a una classe all'interno del vaso. La classe è astratta. Tutti i file .class nella directory del contenuto estendono questa classe e riempiono tutti i metodi richiesti. Durante il caricamento di queste classi, viene generato l'errore. Il programma, quando eseguito normalmente java -jar file.jar, funziona perfettamente.

Questo mi fa credere che abbia a che fare con il classpath. Setup

Sicurezza:

Sono in esecuzione l'applet tramite il comando appletviewer in questo modo:

appletviewer -J-Djava.security.policy=policy file.html 

Nella stessa directory è il mio file di policy:

grant { 
    permission java.lang.RuntimePermission "getenv.APPDATA"; 
    permission java.io.FilePermission "<<ALL FILES>>", "read, write, delete, execute"; 
    permission java.lang.RuntimePermission "exitVM"; 
    permission java.util.PropertyPermission "user.name", "read"; 
    permission java.lang.RuntimePermission "createClassLoader"; 
}; 

Per quanto come so, non vengono lanciate altre eccezioni di sicurezza. L'applet è firmata.

file HTML utilizzato per caricare applet:

<!DOCTYPE html> 
<html> 
    <body> 
     <object width="1000" height="600" classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" 
      codebase="http://java.sun.com/products/plugin/autodl/jinstall-1_4-windows-i586.cab#Version=1,4,0,0"> 
      <param name="archive" value="file.jar"/> 
      <param name="code" value="package.to.Boot"/> 
     </object> 
    </body> 
</html> 

Qualsiasi aiuto verso risoluzione di questo problema è molto apprezzato.

CustomClassLoader.java:

package org.obicere.cc.methods; 

import java.io.File; 

public class CustomClassLoader extends ClassLoader { 
    //... 
    private Class<?> loadClass(final File file) { 
     try { 
      final byte[] data = IOUtils.readData(file); 
      return super.defineClass(file.getName().substring(0, file.getName().length() - 6), data, 0, data.length); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 
} 

Esempio Runner: CanReachRunner.java

import java.lang.reflect.Method; 
import java.util.Random; 

import org.obicere.cc.executor.Result; 
import org.obicere.cc.tasks.projects.Runner; 

public class CanReachRunner extends Runner { 

    @Override 
    public Result[] getResults(Class<?> clazz) { 
     try { 
      final Method method = clazz.getMethod("canReach", int.class, int.class, int.class); 
      final Random ran = new Random(); 
      final Result[] results = new Result[10]; 
      for (int i = 0; i < 10; i++) { 
       final int small = ran.nextInt(5) + 5; 
       final int large = ran.nextInt(5); 
       final int goal = (small + large * 5) + 5 + ran.nextInt(6); 
       results[i] = new Result(method.invoke(clazz.newInstance(), small, large, goal), (goal <= small + large * 5) && goal % 5 <= small, small, large, goal); 
      } 
      return results; 
     } catch (Exception e) { 
      return new Result[] {}; 
     } 
    } 
} 
+0

Si potrebbe dare un'occhiata a questo: http://stackoverflow.com/questions/17886565/export-java-applet-to-jar/17887205#17887205 –

+0

Ho 2 classi di avvio. Uno per l'accesso jar, manifest link a questo. L'altro per l'accesso ad applet, collegamenti HTML a questo. –

+0

Qualcuno di voi. I file .java hanno un metodo principale? –

risposta

4

Ci sono diverse cose sbagliate con il caricatore di classe. Il primo è che il metodo loadClass utilizza un argomento di String piuttosto che uno File, la stringa è il nome della classe da caricare. Questo perché la classe da caricare potrebbe non essere in un file, potrebbe essere su una connessione di rete, e comunque la JVM non sa come trovare il file. Il secondo è che è una cattiva pratica ignorare loadClass, perché se lo fai, interferisce con il comportamento predefinito, che prima tenta di caricare le classi nel modo normale, e ricorre solo a chiamare il metodo findClass se questo non funziona. Pertanto, è necessario eseguire l'override di findClass anziché defineClass.Ecco il codice aggiornato:

public class CustomClassLoader extends ClassLoader { 
    private Class<?> findClass(String class) { 
     try { 
      File contentDir = ...; // You have to fill this in with the location of the content dir 
      final byte[] data = IOUtils.readData(new File(contentDir, class + ".class"); 
      return defineClass(class, data, 0, data.length); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      return null; 
     } 
    } 
} 

È necessario trovare la directory contenuti in qualche modo e l'uso che per inizializzare contentDir.

Il motivo per cui funziona quando viene eseguito come jar è perché è quindi in grado di caricare le classi senza la necessità di un caricatore di classe personalizzato.

+0

Funziona perfettamente come un jar eseguibile, ma non quando viene eseguito come un'applet. L'argomento 'file' ha già il' contentDir' aggiunto e il '.class' aggiunto (spiega la sottostringa). Le classi che sto provando a caricare non vengono aggiunte nel classpath, motivo per cui mi limito a definirle, invece di provare a caricarle. Sono quasi sicuro che il problema si trova all'interno del responsabile della sicurezza. –

+0

Se hai letto l'ultimo commento che ho appena cancellato, puoi ignorarlo. In realtà ho trovato un work-around e potrei arrivare presto a una soluzione. Mi hai appena ricordato qualcosa. –

+0

Bene, quindi mostrami il resto del codice per il caricatore di classe – tbodt

Problemi correlati