Как связать с пакетом, но только при необходимости выполнить действие, основанное на наличии / доступности пакета во время выполнения? - PullRequest
0 голосов
/ 15 апреля 2009

С точки зрения перекрестной java-службы доступности приложений / апплетов, как бы вы связались с пакетом, но только по желанию могли выполнить действие, основанное на наличии / доступности пакета (уже загруженного) во время выполнения?

Я думаю, что здесь меня интересует способ разрешения кризиса идентичности класса 1004 *, а не проблема, возникающая между двумя приложениями, совместно использующими объекты, - службой, загруженной на более высоком уровне класса. погрузчики. Кажется, что рефлексия - это путь, но я не уверен, как или если я смогу реализовать производный класс таким образом. Мне нужно добавить конкретного слушателя, полученного из определенных необязательных классов, я могу загрузить слушателя, используя загрузчик класса апплета, но внутреннее устройство все равно не работает. Скажем, вы хотели добавить JInternalFrameListener, но Swing не гарантированно был доступен, используя отражение, вы можете найти метод для добавления слушателя, но как вы можете создать и заставить работать слушатель фрейма, если он не может найти какой-либо из связанных классов потому что их нельзя найти в базовом загрузчике классов! Нужно ли создавать поток и использовать setContextClassLoader для загрузчика классов, который знает о Swing, чтобы я мог надежно загрузить класс? просто попытка установить загрузчик классов в моем существующем потоке не сработала.

Ранее описание вопросов Извините, я не совсем уверен, что спросить или как это объяснить, так что это немного гремит.

Скажем, класс использует какую-то особенность другого, но другой класс может быть не всегда доступен - скажем, поиск веб-сайта из JNLP, если это приложение JNLP.

В какой-то момент я подумал, что простая компиляция с использованием JNLP будет означать, что мой класс не загрузится, если JNLP не будет доступен, и поэтому для идентификации этого дополнительного раздела я просто обернул try{} catch( NoClassDefFoundError ) вокруг него.

Позже что-то изменилось (возможно, изменив jdk или ??, я не помню), и мне показалось, что я должен также использовать try{} catch( ClassNotFoundException ).

Теперь я хотел распространить эту идею на другие дополнительные функции, но, похоже, она не работает согласованно.

Скажем, я хотел добавить какую-то функцию, чтобы сделать что-то более продвинутое во время выполнения JRE1.6, используя тот же jar и классы, что и в JRE1.3, или сказать, что я хочу обрабатывать некоторые элементы управления в определенном наборе инструментов GUI не всегда может использоваться как SWT или oracle.forms.

Есть ли способ сделать это более надежно? Просто кажется неправильным вызывать исключение и ловить его, чтобы постоянно игнорировать.

В настоящее время проблема сводится к возможности компилирования с использованием oracle.forms, но тогда компонент специальных возможностей, установленный в ext, не может получить доступ к классам oracle.forms, даже если объекты из пакета oracle.forms уже созданы. Если я брошу файл frmall.jar в каталог ext для проверки, компонент доступности будет работать до такой степени, что весь пакет будет ошибочным из-за разных версий одного и того же пакета.

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

Edit: Пока ответы довольно интересные, но не совсем помогают мне достичь желаемого.

В случае компонентов графического интерфейса, которые я сейчас компилирую в виде фабричного чего-то вроде ...

import oracle.forms.ui.*;
import java.awt.*;
static public IComponentNode newNode( INode parent, Component component ) {
  System.out.println( component.getClass().toString() );
  try{
  if( component instanceof FormDesktopContainer )
     ... does stuff here like return new FormDesktopNode( parent, (FormDesktopContainer) component )
  } catch ( NoClassDefFoundError a ) {
    System.out.println( a.getMessage() ); 
  }

, где он печатает class oracle.forms.ui.FormDesktopContainer, а затем создает исключение при вызове instanceof с NoClassDefFound, таким образом выводя oracle/forms/ui/FormDesktopContainer

Так как же он может иметь экземпляр класса, но не может его найти?

Ответы [ 4 ]

2 голосов
/ 15 апреля 2009

Как насчет этого? грязно, но это должно сработать:

public boolean exists(String className){

  try {
      Class.forName(className);
      return true;
      }
  catch (ClassNotFoundException){
      return false;
  }
}
1 голос
/ 15 апреля 2009

Вы можете проверить наличие класса, позвонив по номеру

ClassLoader.getSystemClassLoader().loadClass("my.package.MyClass")

если выдается исключение ClassNotFoundException, оно недоступно. Если вы получаете объект Class, это так. Затем вы можете выбрать поведение в зависимости от того, доступен класс или нет.

0 голосов
/ 30 сентября 2009

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

Взаимодействие с объектами отражение делает свою работу, хотя и добавляет гораздо больше для поддержки.

// statically linking would be
return component.getText();

// dynamically is
try {
  return (String)component.getClass().getMethod("getText", new Class [] {}).invoke(component, new Object [] {});
} catch (Throwable e) {
  e.printStackTrace();
}

Более сложный момент заключается в написании класса, полученного из интерфейса, который не доступен напрямую, с помощью службы Proxy это достигается, предоставляя прокси-серверу загрузчик классов для конкретного апплета и динамически загружаемый класс для интерфейса.

public void addListener(Container parent) {
  if (parent == null) { return; }
  if ("oracle.forms".equals(parent.getClass().getName())) {
    // Using the class loader of the provided object in the applet
    // get the "class" of the interface you want to implement
    Class desktopListenerClass = Class.forName( "oracle.DesktopListener"
         , true, parent.getClass().getClassLoader());

    // Ask the proxy to create an instance of the class, 
    // providing your implementation through the InvocationHandler::invoke
    Object desktopListener = Proxy.newProxyInstance(
         parent.getClass().getClassLoader()
         , new Class[] { desktopListenerClass }, new InvocationHandler() {

      public Object invoke(Object proxy, Method method, Object[] args) 
        throws Throwable {
        if ("functionName".equals(method.getName())) {
          // do stuff
        }
        return null;
      }
    });

    // do something with your new object
    Method addDesktopListener = parent.getClass().getMethod("");
    addDesktopListener.invoke(parent, desktopListener);
  }
}

примеры сокращены, чтобы показать общий метод

0 голосов
/ 15 апреля 2009

Я предлагаю компилировать большую часть вашего кода относительно вашей минимальной цели. Имейте код, который использует определенные дополнительные библиотеки, четко разделенные, но зависящие от объема вашего кода. Динамически загружайте код, который использует дополнительные библиотеки один раз. Основной класс должен сделать что-то, что проверяет наличие необходимой библиотеки / версии в его статическом инициализаторе.

В случае JNLP ваш основной класс JNLP статически загружает зависимый от JNLP код.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...