Interned type annotation and checker

This document describes the @Interned type annotation, and a checker (a compiler plugin) for it.

If the plugin issues no warnings for a given program, then all reference equality tests (e.g., “==”) in that program operate on interned types. Interning can save memory (and speed up testing for equality by permitting use of ==), but use of == on non-interned values can result in subtle bugs. For example:

  Integer x = new Integer(22);
  Integer y = new Integer(22);
  System.out.println(x == y);  // prints false!

This plugin helps programmers to detect and prevent such bugs.

The Interned checking plugin is distributed as part of the JSR 308 checkers framework.

Contents:

Annotating your code with @Interned

In order to perform checking, you must annotate your code with the @Interned type annotation, which indicates a type for the canonical representation of an object:

  import checkers.quals.*;    // permit use of @Interned
  ...
            String s1 = ...;  // type is (uninterned) "String"
  @Interned String s2 = ...;  // Java type is "String", but plugin treats as "Interned String"

The type system enforced by the compiler plugin ensures that only interned values can be assigned to s2.

To specify that all objects of a given type are interned, annotate the class declaration:

  import checkers.quals.*;    // permit use of "@Interned"
  ...
  public @Interned class MyInternedClass { ... }

This is equivalent to annotating every use of MyInternedClass, in a declaration or elsewhere. For example, enum classes are implicitly so annotated.

What the plugin checks

Objects of an @Interned type may be safely compared using the “==” operator.

The plugin issues a warning in two cases:

  1. When a reference equality (or inequality) operator (“==” or (“!=”) is used to compare objects and the type of at least one operand is not @Interned.
  2. When a non-@Interned type is used where an @Interned type is expected. String literals and the null literal are always considered interned, and object creation expressions (using new) are never considered @Interned unless they are annotated as such.

This example shows both sorts of problems:

            Object  obj; 
  @Interned Object iobj;
  ...
  if (obj == iobj) { ... }  // checker warning: reference equality test is unsafe
  iobj = obj;               // checker warning: iobj's referent may no longer be interned

Example use

Tiny examples

To try the @Interned plugin on a source file that uses the @Interned qualifier, use the following command (where javac is the JSR 308 compiler):

  javac -typeprocessor checkers.interned.InternedChecker examples/InternedExample.java

Compilation will complete without warnings.

To see the checker warn about incorrect usage of annotations, use the following command:

  javac -typeprocessor checkers.interned.InternedChecker examples/InternedExampleWithWarnings.java

The compiler will issue a warning regarding violation of the semantics of @Interned in the InternedExampleWithWarnings.java file.

Credits and related work

If you have any problem with the @Interned checker, please see “How to report bugs” for information on reporting bugs, so that we can improve it in a future release.


Back to the JSR 308 checkers framework.