2013-07-30 6 views
6

Я столкнулся с проблемой при попытке отправить приложение на JApplet, чтобы он мог запускаться в браузере.Не удалось загрузить определение класса из jar

Содержание программы:

  1. Jar файл. Содержит мою реализацию CustomClassLoader. Сохраняется на веб-сайте.
  2. Контент-каталог. Заполняется скомпилированными классами. Сохраняется на компьютере пользователя.

Выпуск:

Я получаю NoClassDefFoundError при попытке загрузить файлы .class в каталог содержимого с моим CustomClassLoader.

Ошибка, хотя и недостижимая, относится к классу внутри банки. Класс абстрактен. Все файлы .class в каталоге содержимого расширяют этот класс и заполняют все необходимые методы. При загрузке этих классов возникает ошибка. Программа, когда работает нормально java -jar file.jar, работает отлично.

Это заставляет меня думать, что это связано с классом. Настройка

Безопасность:

Я бегу апплет с помощью команды appletviewer так:

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

В той же директории, мой файл политики:

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"; 
}; 

Что касается как я знаю, никаких других исключений безопасности не бросают. Апплет подписан.

HTML файла используется для загрузки 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> 

Любая помощь в направлении исправления этой проблемы очень ценится.

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

Пример 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

Вы можете взглянуть на это: http://stackoverflow.com/questions/17886565/export-java-applet-to-jar/17887205#17887205 –

+0

У меня есть 2 класса загрузки. Один для доступа к банкам, явные ссылки на этот. Другой для доступа к апплетам, HTML-ссылки на этот. –

+0

У любого из вас .java-файлов есть основной метод? –

ответ

4

Есть несколько вещей неправильно с загрузчиком класса. Во-первых, метод loadClass использует аргумент String, а не File, причем строка является именем загружаемого класса. Это связано с тем, что класс для загрузки может не быть в файле, он может быть подключен к сети, и в любом случае JVM не знает, как найти файл. Во-вторых, это неправильная практика переопределять loadClass, потому что если вы это сделаете, это мешает поведению по умолчанию, которое сначала пытается нормально загружать классы и только прибегает к вызову метода , если это не работает. Итак, вы должны переопределить findClass вместо defineClass.Вот обновленный код:

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

Вы должны найти каталог контента каким-то образом и использовать его для инициализации contentDir.

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

+0

Он отлично работает как исполняемый банку, но не тогда, когда он запускался как апплет. В аргументе 'file' уже добавлен' contentDir' и добавлен '.class' (объясняет подстроку). Классы, которые я также пытаюсь загрузить, не добавляются в путь к классам, поэтому я просто прибегаю к их определению, вместо того, чтобы загружать их. Я почти уверен, что проблема лежит в менеджере безопасности. –

+0

Если вы прочли этот последний комментарий, который я только что удалил, вы можете его игнорировать. Я на самом деле нашел работу и вскоре придет к решению. Ты только что напомнил мне что-то. –

+0

Ну, тогда покажите мне остальную часть кода для загрузчика классов – tbodt

Смежные вопросы