BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Java Nestmates Makes Progress

Java Nestmates Makes Progress

This item in japanese

Lire ce contenu en français

Bookmarks

Oracle has announced JEP 181 - "Nest-based Access Control" - aka "Nestmates". This is a technical enhancement to the platform that pays off a 20 year old architectural debt introduced in Java 1.1

The new feature is connected to the implementation of Java's nested classes (which are often loosely referred to as "inner classes", despite this being only one possible type of nested class).

In general, nested types are used for two separate purposes, both related to encapsulation. First, a type may be only required for a very specific reason, and in a very small section of code. This means that it should be tightly localized, as it is really part of the implementation detail. In older versions of Java, the only way to do this was with a nested type, such as an anonymous implementation of an interface. In practice, with the advent of Java 8, this use case has substantially been taken over by lambda expressions and the use of anonymous types as closely-localized types has dramatically declined, although it still persists for some cases.

Second, a type may be nested because it needs especially intimate access to the internals of another type. By being a nested (i.e. member) type, it has access in the same way that member variables and methods do. This means that nested types have privileged access and can be thought of as "slightly bending the rules of encapsulation".

Another way of thinking about this use case of nested types is that they are types that are somehow tied together with another type. This means that they don’t really have a completely independent existence as an entity, and only live in coexistence with another type.

The purpose of the Nestmates JEP is to generalize and formalize this symbiotic relationship between types, and to clean up the current implementation, which has a certain amount of technical debt and is rather hacky to modern eyes.

As of Java 10, nested classes are compiled into separate top-level classfiles, but with a special naming convention, so that a nested class Nested within a class Outer is compiled into a file named Outer$Nested.class The problem with this implementing strategy is that according to the rules of the Java language, a nested class has access to all the members of the enclosing class, including private members.

To solve this problem, javac adds additional synthetic accessor methods to Outer to allow access. For example, this simple inner class:

public class Outer {
    private int i = 0;
    
    public class Inner {
        public int i() {
            return i;
        }
    }
}

becomes two class files, Outer.class and Outer$Inner.class with bytecode:

public class Outer {
  private int i;

  public Outer();
    Code:
       0: aload_0
       1: invokespecial #2                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_0
       6: putfield      #1                  // Field i:I
       9: return

  static int access$000(Outer);
    Code:
       0: aload_0
       1: getfield      #1                  // Field i:I
       4: ireturn
}

and

public class Outer$Inner {
  final Outer this$0;

  public Outer$Inner(Outer);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #1                  // Field this$0:LOuter;
       5: aload_0
       6: invokespecial #2                  // Method java/lang/Object."<init>":()V
       9: return

  public int i();
    Code:
       0: aload_0
       1: getfield      #1                  // Field this$0:LOuter;
       4: invokestatic  #3                  // Method Outer.access$000:(LOuter;)I
       7: ireturn
}

The private access required by the inner class has been transformed by the compiler into a package-private accessor method access$000() on Outer. The existence of this synthetic accessor means that developers who know about the mechanism can access it, either directly or via reflection - even if they are not a nestmate of the original class.

With the steps being taken to tidy up access control as part of Java's roadmap, this aspect of nested types stands out as being in need of a cleanup, or as the JEP describes the motivation:

A formal notion of a group of class files forming a nest, where nestmates share a common access control mechanism, allows the desired result to be directly achieved in a simpler, more secure, more transparent manner.

The JEP description also notes that future enhancements could include:

  • In generic specialization, each specialized type could be created as a nestmate of the generic type.
  • A safe and supported replacement for the Unsafe.defineAnonymousClass() API could create the new class as a nestmate of an existing class.
  • The concept of "sealed classes" could be effected by only allowing subclasses that are nestmates.
  • Truly private nested types could be effected (presently private nested types are defined with package-access).

Sealed classes and truly private types are likely to be popular with developers working in Scala and other languages where they are supported, as they provide the building blocks necessary for implementing ideas such as algebraic data types that are useful in advanced features such as pattern matching.

Nestmates is being developed as part of Project Valhalla, and the work to produce an initial working prototype is well underway, and is being actively worked on by OpenJDK developers.

As is usual for long-range features, Oracle has not made any commitment as to when (if ever) Nestmates will ship. However, given its usefulness to other landmark features (such as sealed classes and pattern matching) that are currently in development, interested Java programmers should keep an eye out as the project matures.

Rate this Article

Adoption
Style

BT