Zielony Smok - logo witryny

Nest-Based Access Control

Nest-Based Access Control – dosł. Kontrola dostępu bazująca na gniazdach.

Zagnieżdżanie typów

W języku Java zagnieżdżone mogą być:

  • członkowie statyczni: klasy statyczne, wyliczenia i interfejsy
  • klasy (nie statyczne)
  • klasy lokalne
  • klasy anonimowe (wewnętrzne)

Pokazana niżej klasa pokazuje niektóre z możliwości zagnieżdżenia:

1    package java11zmiany;
public class Klasa {//klasa główna (najwyższego poziomu)
    static class StaticClass {
    } //klasa statyczna
    interface Interf {
    } // iterfejs (statyczny)
    enum ENUM {} // wyliczenie (statyczne)
    class NonStaticClass {
    }// klasa wewnętrzna
    void metoda1() {
    }
    {
        class LocalClass {
        }// klasa lokalna (wewnętrzna)
    }
    static void metoda2() {
        class StaticLocalClass {
        }// klasa lokalna (wewnętrzna) w kontekście statycznym
    }
    StaticClass sc = new StaticClass() {
    }; // Klasa anonimowa (wewnętrzna)
    static Interf inf = new Interf() {
    }; // Klasa anonimowa (wewnętrzna) w kontekście statycznym
}

Postawienie problemu

Zapoznajmy się z klasą:

package java11zmiany;
import java.lang.reflect.Field;
public class NestedMembers {
    public static class Nest1 {
        private int nest1;
        public void foo() throws IllegalAccessException {
            final Nest2 nest2a = new Nest2();
            nest2a.nest2 = 2;
            try {
                final Field f2 = Nest2.class.getDeclaredField("nest2");
                f2.setInt(nest2a, 2);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();//
            }
        }
    }
    public static class Nest2 {
        private int nest2;
    }
    public static void main(String[] args) throws Exception {
        new Nest1().foo();
    }
}

Klasa Nest1 uzyskuje dostęp do zmiennych w klasie Nest2. Jednak, gdy w Java 10 i wcześniejszych spróbowalibyśmy
uzyskać informację o polu, jego zawartości i zmienić tę zawartość przy użyciu refleksji otrzymamy błąd:

Exception in thread "main" java.lang.IllegalAccessException: class java11zmiany.NestedMembers$Nest1 (in module java11zmiany) cannot access a member of class java11zmiany.NestedMembers$Nest2 (in module java11zmiany) with modifiers "private"
	at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:360)
	at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:589)
	at java.base/java.lang.reflect.Field.checkAccess(Field.java:1075)
	at java.base/java.lang.reflect.Field.setInt(Field.java:958)
	at java11zmiany/java11zmiany.NestedMembers$Nest1.foo(NestedMembers.java:18)
	at java11zmiany/java11zmiany.NestedMembers.main(NestedMembers.java:30)

Rozwiązanie problemu

Java 11 rozwiązuje powyższy problem. Klasa uruchomiona w Java 11 nie wyrzuca wyjątków.

Stworzono gniazda (nest) – kontekst kontroli dostępu umożliwiający mechanizmom refleksji dostęp do wszystkich, w tym prywatnych członków klas.

Szczegóły problemu i jego rozwiązanie opisane jest w https://openjdk.java.net/jeps/181

JEP – JDK Enhancement Proposals – dosł. Propozycje rozszerzenia JDK.

Przyjęte rozwiązania są wewnętrzne. Nie zmieniają one w żaden sposób dotychczasowych poziomów dostępu ani nie powodują zmian w organizacji modułów. Nie powodują też konieczności jakichkolwiek zmian w sposobie pisania kodu.