2012-05-05 17 views
10

Mam dziwny problem, którego nie mogę zrozumieć, który pojawił się podczas próby wtyczki do mojego programu. Dodatkowym problemem jest to, że nie jestem w stanie stworzyć prostego przypadku testowego, ponieważ za każdym razem, gdy go wypróbuję, działa. Muszę mieć pewne komplikacje, których mi brakuje. Ale postaram się opisać sytuację tak wyraźnie, jak to tylko możliwe, na wypadek gdyby brzmiał znajomo.Nie można uzyskać dostępu do chronionego elementu nadklasy z tego samego pakietu w innym słoju.

Mam klasę podstawową o nazwie Seed, która jest częścią aplikacji głównej i ładowana przez systemowy program ładujący klasy Mam wtyczkę zawierającą klasową Drogę, która jest podklasą Seed. Jest ładowany w środowisku wykonawczym z oddzielnego pliku jar. Droga klasy odwołuje się do pola Seed.garden, które jest zdefiniowane jako:

zabezpieczony końcowy ogród ogrodowy;

Pamiętaj, że nie dostaję błędów kompilacji. Nie otrzymuję również błędów runtime, gdy słoik wtyczki jest uwzględniony w systemowej ścieżce klas. Tylko wtedy, gdy moja główna aplikacja ładuje wtyczkę za pomocą nowego programu ładującego klasy (który ma systemowy program ładujący klasy jako obiekt nadrzędny), pojawia się błąd. Błąd jest:

java.lang.IllegalAccessError: próbował uzyskać dostęp do pola package.Seed.garden z klasy package.Road 4 $

To musi mieć coś wspólnego z faktem, że podklasa został załadowany przez inny program ładujący klasy niż nadklasa, ale nie mogę znaleźć żadnego oficjalnego powodu, dla którego to nie powinno działać. Podobnie jak powiedziałem, kiedy próbuję odtworzyć problem za pomocą prostego przypadku testowego (który obejmuje oddzielne słoiki, ładowanie podklasy innym programem ładującym klasy itp.), Nie otrzymuję błędu.

Nie wydaje się również prawdopodobne, że naruszam zasady dostępu, ponieważ działa, gdy klasy są ładowane przez ten sam program ładujący klasy i nie pojawiają się błędy kompilacji.

Brakuje mi pomysłów! Czy ktokolwiek rozpoznaje ten problem, czy może ma dla mnie wskazówki, na które należy zwrócić uwagę? Wsparcie!

+0

Powinienem dodać, że droga 4 USD to anonimowa wewnętrzna klasa drogi (oczywiście), ale uwzględniłem ten fakt również w moim przypadku testowym i nadal działało. –

+1

Możliwy duplikat opcji [Zastąpienie domyślnej metody dostępu dla różnych modułów ładujących klasy polimorfizm] (http://stackoverflow.com/questions/4060842/overriding-default-accessor-method-across-different-classloaders-breaks-polymorp) – axtavt

+0

@axtavt: możesz mieć rację, chociaż artykuł dotyczy domyślnego dostępu, a nie chronionego dostępu. Myślę, że to samo dotyczy dostępu chronionego. Spojrzałem na specyfikację, ale nie złapałem "pakietu uruchomieniowego". Nie wyjaśnia, dlaczego mój przypadek testowy działa. Zobaczę, czy uda mi się złamać tę wiedzę. Dzięki! –

Odpowiedz

6

OK, więc dzięki pomocy aktavta i innych respondentów zrozumiałem, na czym polega problem. Inne odpowiedzi pomogły, ale nie zrozumiały dokładnie, dlatego odpowiadam na własne pytanie. Problemem okazała się koncepcja „pakietów wykonania”, zdefiniowane w Java Virtual Machine specification następująco:

5.3 Tworzenie i wczytywanie

... w czasie wykonywania, klasa lub interfejs jest nieokreślony tylko przez nazwę, ale przez parę: jego w pełni kwalifikowaną nazwę i definiujący moduł ładujący klasy. Każda taka klasa lub interfejs należy do pojedynczego pakietu środowiska wykonawczego. Pakiet środowiska wykonawczego klasy lub interfejsu jest określony przez nazwę pakietu i definiuje moduł ładujący klasy lub interfejsu. ...

5.4.4 Kontrola dostępu

... Pole R lub metoda jest dostępna dla klasy lub interfejsu D wtedy i tylko wtedy, jeśli którykolwiek z następujących warunków: ..

  • R jest chroniony i jest deklarowany w klasie C, a D jest podklasą samego C lub C.
  • R albo jest chroniony lub zapakować prywatny (czyli ani publicznej, ani chronione ani prywatny), i jest uznana przez klasę w tym samym opakowaniu wykonawczego jako D.

Pierwsza klauzula wyjaśnia dlaczego drogowy jest dozwolony aby uzyskać dostęp do Seed.garden, ponieważ Road jest podklasą Seed, a druga klauzula wyjaśnia, dlaczego Road 4 USD nie ma dostępu do niego, mimo że jest w tym samym pakiecie co Road, ponieważ nie jest w tym samym pakiecie runtime, po załadowaniu przez inny program ładujący klasy. Ograniczenie nie jest w rzeczywistości ograniczeniem języka Java, jest ograniczeniem VM Java.

Wniosek z mojej sytuacji jest taki, że wyjątek pojawia się z powodu uzasadnionego ograniczenia wirtualnej maszyny wirtualnej Java, i będę musiał obejść ten problem, prawdopodobnie poprzez udostępnienie tych pól publicznie, co nie stanowi problemu. ten przypadek, ponieważ są one ostateczne, a nie tajne, lub może eksportując Seed.garden do Road $ 4 przez Road, który ma dostęp.

Dziękuję wszystkim za sugestie i odpowiedzi!

+0

Dziękuję bardzo pomocne. Jedna rzecz do dodania - nie trzeba tworzyć tych publicznych pól chronionych, wystarczy umieścić metodę w podklasie (I może być prywatna), która zwraca te wartości, które są chronione. Tylko klasa anonimowa nie ma dostępu do chronionych pól, a nie do podklasy. –

+0

@MichaelWiles thanks. To właśnie miałem na myśli z moją drugą sugestią. :) –

4

Wygląda na to, że masz kryzys tożsamości klasowej, mając dwie różne ładowarki klas ładujące tę samą klasę w hierarchii klas lub podobne. Przeczytaj trochę na temat ładowarek klas java. Tutaj jest dobry do wprowadzenia, "kryzys tożsamości klasy", patrz rysunek 2: http://www.ibm.com/developerworks/java/library/j-dyn0429/

+0

To nie jest kryzys tożsamości klasy (każda klasa jest ładowana tylko przez jeden program ładujący klasy), ale uważam, że przyczyna jest podobna, jak wskazano w pytaniu axtavt powiązanym z powyższym, a mianowicie fakt, że klasy znajdują się w różnych "pakietach uruchomieniowych" ". –

+0

Nie jestem pewien, na czym polega różnica, czym jest "pakiet uruchomieniowy", do którego się odnosisz, czy odnosisz się do różnych przestrzeni nazw wprowadzonych przez programy ładujące klasy? Następnie mówimy o tej samej rzeczy. –

+0

Tak. "Pakiet uruchomieniowy" jest tym, co Specyfikacja wirtualnej maszyny języka Java nazywa połączeniem pakietu i modułu ładującego klasy. Pomyślałem, że "kryzys tożsamości klasy" oznaczał dwukrotne ładowanie klasy _same_ przy użyciu różnych programów ładujących klasy. –

0

To jest błąd uprawnień, więc zależy to od struktury, której używasz do uruchamiania środowiska wykonawczego. Aby wyjaśnić, że to jest rzeczywiście to, upublicznij członka rodziny, a następnie spróbuj go uruchomić. Jeśli wszystko jest w porządku, przywróć kod, a zgodnie z używanym środowiskiem wykonawczym musimy skonfigurować poprawny dostęp do zabezpieczeń.

+0

To nie jest zwykły błąd uprawnień, w przeciwnym razie nie byłoby nawet kompilacji. Ale myślę, że znaleźliśmy to, zobacz moje komentarze do pierwotnego pytania. –

+0

za pozwoleniem - mam na myśli uprawnienie do wykonywania, nie statyczny/czas kompilacji. W każdym razie wygląda na to, że znalazłeś prawdziwy problem. – miks

1

I should add that Road$4 is an anonymous inner class of Road...

Ktoś inny, że to był błąd, a także w 1998 roku:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4116802

An inner class has no greater access to members of another class than a top-level class, except for those members that are declared within an enclosing, enclosed, or sibling class. It is a common misconception that an inner class has unrestricted access to inherited members of its enclosing classes. This is not true.

Prawdopodobnie badać ten fakt nieco bardziej chociaż ponieważ odnotowano pierwotnie przed Java 1.2 , ale wydaje mi się, że pamiętam z lektury, że jest to również dzisiaj prawdą.

Edycja:

I potwierdziły, że jest to prawdą

http://docs.oracle.com/javase/tutorial/java/javaOO/summarynested.html

Zakres anonimowego klasy wewnętrzna jest tylko w miejscu, gdzie jest to określone. Więc nie będzie miał dostępu do dziedziczonych członków, nawet jeśli zewnętrzna klasa to zrobi.

+0

Interesujące informacje. Myślę, że to jednak nie obowiązuje, ponieważ ochrona oznacza dostęp do pakietu, a klasa wewnętrzna jest w tym samym pakiecie (w moim przypadku) jako nadklasa jego klasy otaczającej, więc powinna mieć dostęp do chronionych członków superklasy. Dobrze? W przeciwnym razie nie powinien nawet kompilować, co robi. –

Powiązane problemy