IllegalAccessError при попытке instanceof для AbstractDocument.UndoRedoDocumentEvent из javax.swing.text - PullRequest
5 голосов
/ 09 апреля 2011

В источнике javax.swing.text.DefaultCaret.Handler.insertUpdate(DocumentEvent) я нашел следующие строки (начиная со строки 1685):

if (e instanceof AbstractDocument.UndoRedoDocumentEvent) {
    setDot(offset + length);
    return;
}

Но когда я попробую это:

package javax.swing.text;

public class Foo {
    public static void main(String[] args) {
        Object o = new Object();
        if (o instanceof AbstractDocument.UndoRedoDocumentEvent) {
            System.out.println("yay");
        } else {
            System.out.println("aww");
        }
    }
}

, это даст:

Exception in thread "main" java.lang.IllegalAccessError: tried to access class javax.swing.text.AbstractDocument$UndoRedoDocumentEvent from class javax.swing.text.Foo
    at javax.swing.text.Foo.main(Foo.java:6)

Почему я не могу instanceof против этого класса, но DefaultCaret.Handler может?

Использование java версии 1.6.0_20

$ java -version
java version "1.6.0_20"
OpenJDK Runtime Environment (IcedTea6 1.9.7) (6b20-1.9.7-0ubuntu1~10.04.1)
OpenJDK Client VM (build 19.0-b09, mixed mode, sharing)

ОБНОВЛЕНИЕ:

На основании ответов я попробовал следующее:

файл Foo.java:

package javax.swing.text;

public class Foo {
    public static void main(String[] args) {
        Object o = new Object();
        if (o instanceof Outer.Inner) {
            System.out.println("yay");
        } else {
            System.out.println("aww");
        }
    }
}

файл Outer.java:

package javax.swing.text;

public class Outer {
    class Inner {
    }
}

Это работает нормально и печатает "aww", как и ожидалось.

Обратите внимание, что оба файла находятся в пакете javax.swing.text.Также обратите внимание, что Foo.java уже было в пакете javax.swing.text в моем первоначальном вопросе.

Насколько я могу судить, пакет не "запечатан".Манифест rt.jar (тот, который содержал упаковку javax.swing.text) не содержал «Запечатано».Команда Package.getPackage("javax.swing.text").isSealed() возвращает false.

Так что я могу instance of против своего собственного внутреннего класса, но не против AbstractDocument.UndoRedoDocumentEvent, хотя другие классы из пакета могут.

Любые идеипочему это?

Ответы [ 2 ]

3 голосов
/ 09 апреля 2011

Похоже, UndoRedoDocument защищен пакетами, а DefaultCaret.Handler и UndoRedoDocument находятся в одном пакете (javax.swing.text, если я правильно помню).

1 голос
/ 09 апреля 2011

Первая идея заключается в том, что пакет javax.swing.text запечатан, и вы не можете добавлять в него новые классы. То же самое происходит с вашим собственным пакетом?


Редактировать : Из моего комментария:

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

Вы можете узнать, какой загрузчик классов используется Name.class.getClassLoader() или object.getClass().getClassLoader(). Распечатайте это. (Может случиться так, что ClassLoader класса Swing равен null, который представляет загрузчик класса начальной загрузки (реализованный виртуальной машиной, созданный до загрузки классов Class и ClassLoader). Ваш загрузчик класса приложений весьма вероятен еще один.

Для создания класса с помощью собственного загрузчика классов используйте URLClassLoader. Это должно иметь загрузчик классов вашего приложения в качестве родительского (чтобы позволить классам вообще иметь доступ друг к другу), но использовать другой URL (например, загружать классы, которые не находятся на обычном пути к классам).

Вы могли бы сделать что-то вроде этого:

  • поместите ваш Outer класс в путь к классу приложения.
  • создайте основной класс (в том же пути к классам), как это:

    class Main {
        public static void main(String[] ignored) throws Exception {
            URL url = new URL("file:///path/to/other/dir");
            ClassLoader cl = new URLClassLoader(url, Main.class.getClassLoader());
            Class<?> testClass = cl.loadClass("package.Test");
            testClass.getMethod("test").invoke(null);
        }
    }
    
  • создайте тестовый класс, подобный этому, в том же пакете, что и Outer, но с корнем по URL в основном классе:

    class Test {
       public static void test() {
          Object o = new Object();
          if (o instanceof Outer.Inner) {
              System.out.println("yay");
          } else {
              System.out.println("aww");
         }
       }
    }
    

Если моя теория верна, это должно привести к тому же типу исключения. (Я не пробовал.)

...