2014-10-16 5 views
0

Для моего апплета нужны классы, которые являются частью внешних банок (подписанных банок) и родных библиотек. Я развертываю эти банки в своем апплете apple.jar. Чтобы загрузить классы из этих банок, я нашел com.jdotsoft.jarloader.JarClassLoader класс, который будет полезен. Сначала я создаю консольное приложение для проверки функциональности своего апплета, и JarClassLoader отлично работает для меня. Далее я написал класс MyApplet с двумя дополнительными общедоступными методами, скажем action1() и action2(). И, как описано JarClassLoader, я написал класс MyAppletLauncher. (см. код ниже). Чтобы получить ссылку на объект MyApplet, созданный JarClassLoader, я добавил метод getApplet() в класс JarClassLoader.Как использовать объект, созданный другим ClassLoader

MyApplet.java:

public class MyApplet extends Applet { 
    public void init() { ... } 
    public void start() { ... } 
    public void stop() { ... } 
    public void destroy() { ... } 

    public String action1() { 
     ... 
    } 
    public int action2() { 
     ... 
    } 
} 

MyAppletLauncher.java:

public class MyAppletLauncher extends Applet { 
    private JarClassLoader jcl; 
    public void init() { 
     jcl = new JarClassLoader(); 
     jcl.initApple("MyApplet", this); 
    } 
    public void start() { 
     jcl.startApplet(); 
    } 
    public void stop() { 
     jcl.stopApplet(); 
    } 
    public void destroy() { 
     jcl.destroyApplet(); 
    } 
    public String action1() { 
     return ((MyApplet) jcl.getApplet()).action1(); // <-- ClassCastException 
    } 
    public int action2() { 
     return ((MyApplet) jcl.getApplet()).action2(); // <-- ClassCastException 
    } 
} 

Мои изменения в JarClassLoader.java:

public class JarClassLoader extends ClassLoader { 

    private Applet applet; // was JApplet 

    public JarClassLoader() { 
     this(ClassLoader.getSystemClassLoader()); 
    } 

    public JarClassLoader(ClassLoader parent) { 
     super(parent); 

     ... 
    } 

    public void initApplet(String sClass, final Applet appletParent) { // 2nd arg was JApplet 
     Class<?> clazz = loadClass(sClass); 
     applet = (Applet) clazz.newInstance(); 
     ... 
    } 

    public Applet getApplet() { 
     return applet; 
    } 
    ... 

На мой взгляд, очевидно, что экземпляр MyAppletLauncher не может сбрасывать предоставленный экземпляр Applet в MyApplet, потому что экземпляр MyApplet был создан в другое пространство имен (= не тот же загрузчик классов). Но моя проблема здесь в том, как получить вызовы action1() и action2() к объекту MyApplet? Или чаще, можно ли вызвать публичный интерфейс MyApplet из объекта MyAppletLauncher?

Я уже попробовал несколько вещей, как

  • MyApplet реализует MyInterface, а затем бросили в MyInterface
  • Изменить тип члена JarClassLoader.applet к MyApplet

Но результат в ClassCastException в какой-то момент.

Любое предложение приветствуется. Спасибо.

ответ

1

Я думаю, что вам не хватает точки запуска аплета. Он служит в качестве прокладки между контейнером апплета и его системой ClassLoader, с одной стороны, и реальным апплетом JCL и JCL с другой. В аплетах запуска не должно быть ничего, кроме методов жизненного цикла апплета.

Я не уверен, что любые методы, кроме методов жизненного цикла, вызывают в вашем аплетах запуска. Это не может быть случайным, поэтому просто прекратите пытаться это сделать. Внедрите все функциональные возможности вашего апплета в настоящий класс апплета и любые вспомогательные классы, которые вам нужны, как если бы апплет запуска не существовал.

Если у вас должны быть внешние компоненты, которые ищут ваш апплет и вызывают методы на нем, то измените или подклассу JCL, чтобы предоставить дополнительные методы прокладки, используя ту же модель, что она уже использует для методов жизненного цикла приложения.

+0

Возможно, аплету необходимо принимать вызовы с Javascript? – biziclop

+0

Это правильно biziclop, я вызываю action1() и action2() непосредственно из Javascript. –

+0

Javascript, вызывающий методы апплета, обычно оказывается довольно беспорядочным, но да, я полагаю, это может быть то, что происходит. Я предполагаю, что другие апплеты могут делать то же самое (также беспорядок). –

0

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

Что вам нужно сделать, это что-то вроде этого:

public void init() { 
    jcl = new JarClassLoader(this.getClass().getClassLoader()); 
    jcl.initApplet("MyApplet", this); 
} 

И JarClassLoader должен вызвать the appropriate super constructor of ClassLoader. Таким образом, все классы, которые могут загружаться загрузчиком класса «main», будут загружаться только один раз, поэтому приведение в интерфейс должно работать.

Обновление: Если нет никакого способа передвижения JarClassLoader, то ваш следующий лучший вариант - отражение. Это не приятно, но, по крайней мере, это работает.

public void action1() { 
    Applet applet = jcl.getApplet(); 
    Method action = applet.getClass().getDeclaredMethod("action1"); 
    action.invoke(applet); 
} 
+0

К сожалению, похоже, что 'JarClassLoader' * не * правильно делегирует его родительскому классу ClassLoader (который по умолчанию является' ClassLoader.getSystemClassLoader() '), поскольку в документах ограничения включают в себя то, что он может загружать системные классы из других мест, кроме встроенная библиотека системы. Насти. –

+0

Можно предположить, что решение интерфейса все равно будет работать. –

+0

В этом случае, отражение. – biziclop

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