The Open Road: javax.annotation Blog

Version 2


    Editor's Note: Java SE 5's annotations were one of the most profound additions to the Java language, offering a means of providing metadata about your code to be processed by the compiler or tools, or even at runtime. While many external projects and products have adopted annotations quickly and enthusiastically, the JDK itself continues to make only minimal use of annotations, even in Java SE 6. However, as Elliotte Rusty Harold reports in this latest installment of The Open Road, that's about to change.

    Before we begin, here's a brief update on the status of theOpenJDK 7 project. The most recent JDK 7 drop is Build b34, posted August 28. As with the builds before it since the last Open Road article (b33,b32,b31, and b30), most of the b34 summary of changes items are cleared defects rather than new features. JMX continues to be an area of particular interest in the recent builds, with b34 adding more reliable event handling. Build b33 cleared a number of 2D graphics bugs and added features, including dealing with non-accelerated screenshots generated withjava.awt.Robot, and a number of bugs involving the mishandling of transformed images. Build b32 cleared a rare Priority 1 bug, a failure building rt.jar with pack200. Build b31 cleared a number of significant HotSpot bugs, and b30 has a large number of fixes for the javap disassembler tool.

    In the future, JSRs approved for Java 7 will start making their way into JDK 7. In this article, Elliotte looks at a Java 7 JSR you can actually start using today: JSR 305.

    Java 5 introduced annotationsto the language. Since then, several important third-party libraries and frameworks have taken advantage of them to good effect, including Guice, Hibernate, and JUnit 4. Libraries designed around annotations are often simpler and easier to work with than the equivalent libraries that use reflection or naming conventions to achieve the same result.

    However, the core of Java itself has made relatively little use of annotations. In fact, only three are built into the language as of Java 6: @Override, @Deprecated, and@SuppressWarnings. These are certainly useful, but they hardly exhaust the space of information we may wish to annotate in our Java programs.

    The JSR 305effort being led by Bill Pugh of the University of Maryland plans to change this in Java 7, and dramatically increase the number of annotations used in standard Java code. By adding annotations to classes, methods, fields, and variables, you'll be able to tell static and dynamic analysis tools how you think the code is supposed to behave. Then the tools can warn you when they suspect the code will behave in some other fashion. This improves on the current situation, where static analysis tools need to guess not only what the code does, but what it's supposed to do. Such tools will still generate many false positives; but they'll find many more true positives—that is, genuine errors—in annotated code than in non-annotated code.

    In general, annotations can be targeted at the compiler, the runtime, or both. The JSR 305 annotations are primarily intended for compilers or other tools that read source code. However, they are usually retained in the byte code for the benefit of static analysis tools such as FindBugs that inspect byte code rather than source.

    Annotations can be used by the Java environment itself (compiler and VM) or by third-party tools. The third-party tools of most interest to JSR 305 are static analysis tools such as FindBugs and PMD. However, one of the promises of annotations is that future compilers will be able to check more information about the code they're compiling and issue more accurate warnings. This is unlikely to be the case with the default javac compiler in JDK 7, but could well become a feature of future or third-party compilers.

    This article explores the new annotations being proposed in thejavax.annotations package. Although these annotations are being proposed for inclusion as a standard feature of Java 7, they're all in the javax.annotations package, and there's nothing in them that in any way depends on any new features of Java 7. Provided you add one extra JAR file to your classpath, all of them should work with any codebase compatible with Java 5 or later. In fact, if you like living on the bleeding edge, you can download all of these annotations from the Subversion repository and start using them today. Most compilers won't recognize them yet, but the latest versions of FindBugs will, and other static analysis tools will be adding support soon.

    General Language Annotations

    These annotations in the javax.annotations package give the compiler extra hints about the intended usage of methods, classes, and arguments that it could not determine with certainty on its own. For example, the compiler doesn't really know whether passing null to a method is a mistake, even if it strongly suspects it. However, by adding the @Nonnull annotation to the argument, the programmer tells the compiler that yes, passing null really is a mistake, and if code does that then the build should fail. Conversely, if the programmer adds a@CheckForNull annotation to the argument, then they're saying that nulls may be passed, and the method is expected to handle it.

    For example, the compareTo() method injava.lang.Comparable is a classic example where passing null is a flat-out error:

    public int compareTo(@Nonnull Integer anotherInteger) { int thisVal = this.value; int anotherVal = anotherInteger.value; return (thisVal < anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1)); } 

    Any caller that passes null to compareTo() deserves the NullPointerException they get. WhencompareTo() throws aNullPointerException, the bug is in thecalling method.

    However, the equals() method is expected to handle null without throwing a NullPointerException, and if it does, then the implementer of the equals() method is at fault. When equals() throws aNullPointerException, the bug is in thecalled method.

    public boolean equals(@CheckForNull Object o) { if ( o == null) return false; if (o instanceof Integer) { return value == ((Integer) o).intValue(); } return false; } 

    There's also a third possibility, which is that the method implicitly accepts nulls but doesn't need to check for them. For instance, this would be the case for a setter method that allows a property to be set to null. For these methods, you can annotate the parameter as @Nullable, indicating that null is a perfectly OK value and no special check is required. It's also the case for a slightly shorter version of the equals()method that realizes null is never an instanceof any type.

    public boolean equals(@Nullable Object o) { if (o instanceof Integer) { return value == ((Integer) o).intValue(); } return false; } 

    Now, these are two well-known methods with well-defined contracts. Static analysis tools can implement the correct nullness checks directly for them. But there are thousands more non-standard methods for which the null behavior is not known in advance, unless the code specifies it. When you annotate your methods with@CheckForNull, @Nonnull, and@Nullable, static analysis can be performed on all methods, not just those few of which the tool has advance knowledge.

    I personally don't find it particularly onerous to put simple@CheckForNull and @Nonnull annotations on each parameter. Indeed, the hardest part of this is merely figuring out what the behavior of every method should be when passed a null argument. However, that's work we should be doing anyway, although mostly we haven't been. Once these parameters are in place, your IDE can now warn you of unannotated methods where you may not have properly considered and documented the behavior in face of null parameters.

    Nonetheless, if you do find it onerous to add an extra annotation to each method, you can also declare entire methods, classes, and even packages to be @CheckForNull,@Nonnull, or @Nullable. This annotation is then applied to each method in the class or package, and to all subclasses of those classes. Of course, you can override the default annotation on individual methods within a class or classes within a package simply by applying a different annotation. For example, a new Integer class might be declared like so:

    @Nonnull public class Integer extends Number { //... public boolean equals(@Nullable Object o) { if (o instanceof Integer) { return value == ((Integer) o).intValue(); } return false; } //... } 

    This often catches more than you'd like, though. Instead, you can annotate a package, class, or method withParametersAreNonnullByDefault to indicate that method arguments are not null unless the method overrides a superclass method or another, closer annotation takes precedence.


    In my opinion, the biggest syntactic omissions in Java are not closures or properties or regular expressions or similarly sexy topics. Rather, they are the much more important but less popularpreconditions and class invariants. Far too much Java code blithely assumes that arguments are correct without verifying them. Besides the null annotations already introduced, JSR-305 brings in several other annotations for checking a variety of preconditions and invariants:

    • CheckForSigned
    • Signed
    • Nonnegative
    • MatchesPattern
    • Syntax
    Signedness Annotations

    The CheckForSigned annotation indicates that values passed may be negative and that the method should consider this before executing code. For example,

    public void setSpeed(@CheckForSigned double speed) { if (speed < 0) this.speed = 0; this.speed = speed; } 

    Here, negative speed is a legal input value but requires special handling. However, if the caller is responsible for passing in a non-negative value, then annotate the argument with@Nonnegative instead:

    public void setSpeed(@Nonnegative double speed) { if (speed < 0) throw new IllegalArgumentException("Speed cannot be negative."); this.speed = speed; } 

    Note that non-negative is not the same as positive. Non-negative numbers include zero, but the positive numbers don't. That is, zero is not negative, but is not positive either.

    Finally, the @Signed annotation indicates that the value passed in can be of any sign and no special handling is required:

    public void setBalance(@Signed double value) { this.value = value; } 

    You can apply the @Syntax annotation to string values, arguments, and variables to indicate that the string is expected to contain a fragment of some well-defined language such as XML, regular expressions, or JavaScript. For example, here we require that a local variable/return value contain valid HTML:

    @Syntax("HTML") public String get401Page(String problem) { @Syntax("HTML") String s = "<html><body><h1>" + problem + "</h1></body></html>"); return s; } 

    The exact syntaxes that are recognized will vary from tool to tool. There is no one canonical list, though there are several suggested values:

    • Java
    • RegEx
    • JavaScript
    • Ruby
    • Groovy
    • SQL
    • FormatString

    Furthermore, you can specify subtypes of syntax by adding a colon and a list of key-value pairs, separated by ampersands after the name. For example,HTML?version=3.2&fragment=true could indicate that the syntax is version 3.2 of HTML, but only a document fragment that doesn't necessarily have to begin with<html> and end with </html>. This offers additional hints to tools that recognize them. Tools can ignore hints they don't recognize.

    For custom and unusual syntaxes that your tool doesn't recognize, you can specify a regular expression with@MatchesPattern instead. For example, consider a method that extracts the month from dates in the form "2008-12-15." You could annotate its parameter thusly:

    public int readMonth(@MatchesPattern("\\d\\d\\d\\d-\\d\\d-\\d\\d") String date) { //... } 

    For the truly advanced (or paranoid), you can create custom validators that run code to check constant values. For example, you could write a checksum verifier annotation for credit card numbers, or even one that contacts the credit card company to make sure the card is still active. Here's simpler definition for a class that annotates an int as being between 1 and 12; that is, a month:

    @Documented @TypeQualifier @Retention(RetentionPolicy.RUNTIME) public @interface Month { class Validator implements TypeQualifierValidator<Month> { public boolean forConstantValue(Month annotation, Object v) { if (v instanceof Integer) { Integer i = (Integer) v; if (i.intValue() >= 1 && i.intValue() <= 12) { return true; } } return false; } } } 

    Proper Usage

    Many classes have conditions on how they are used. For instance, Hibernate-generated classes may require that all the setter methods be invoked once each before the business logic methods are called. JUnit 3 test classes assume that a test case's setUp()method will invoke the superclass's setUp() method before running their own code.

    To my way of thinking, these conventions are broken by design. Post-construction, clients should be able to invoke any method on any object at any time in any order. Nonetheless, such usage conventions are common and almost never sufficiently documented. Bugs involving incorrect class usage are legion. Consequently, JSR 305 introduces a couple of methods to both document the correct usage and help tools identify incorrect usage:

    • @OverridingMethodsMustInvokeSuper
    • @CheckReturnValue

    Since these are all conventions established by the class rather than the language, there's no other way a static analysis tool could possibly detect these errors, short of knowing the conventions for usage of every single class.


    The @OverridingMethodsMustInvokeSuper is useful precisely in the JUnit case, when an overriding method must invoke the superclass's variant. This is declared on the superclass, and then the programmer can be warned if they forget to override the method. For example:

    @OverridingMethodsMustInvokeSuper public void setUp() { } 

    Unlike most of the annotations discussed here, which can applied at any level, @OverridingMethodsMustInvokeSuper can only be attached to methods.


    The @CheckReturnValue value annotation is helpful in cases where a programmer might suspect a method to change an object rather than returning a new object. For example, consider the trim() method in java.lang.String. This method creates a new String that is the same as the old String except that white space has been removed from each end. The original String is not changed at all, nor is anything else. Thus if one invokes it like so, absolutely nothing happens:


    You might as well not have bothered. The correct way to invoke it is by assigning the result to a variable, possibly the same one that was used to invoke it:

    s = s.trim();

    Failing to do this is a very common mistake and a frequent source of hard-to-find bugs. By placing the@CheckReturnValue annotation on a method, we clue in the compiler that it should probably issue a warning if the return value isn't used.

    @CheckReturnValue public String trim() { //...


    When passing input and output streams to methods, or retrieving them from methods, it is often hard to tell what the method will do with the stream. In particular, should you close the stream when you're done or not? Since some other class has a reference to the stream, it's hard to tell. The invoking object may or may not use the stream after you're done with it, and it may or may not close it. The next three annotations help both document and verify what happens to input and output streams (or other closeable resources) when a method is done with it.

    • @WillClose
    • @WillNotClose
    • @WillCloseWhenClosed

    If a method will exhaust a stream (or reader or writer) and close it before returning, then annotate the argument with@WillClose like so:

    public String readString(@WillClose Reader in) throws IOException { try { StringBuffer s = new StringBuffer(); for (int i =; i != -1; i = { s.append((char) i); } return s.toString(); } finally { in.close(); } }

    If you don't plan to close the resource, annotate with@WillNotClose instead:

    public String readString(@WillNotClose Reader in) throws IOException { StringBuffer s = new StringBuffer(); for (int i =; i != -1; i = { s.append((char) i); } return s.toString(); }

    Finally, you can use @WillCloseWhenClosed to tie two resources together. This is typically used on a constructor or factory method argument to promise that when the constructed object is closed, the resource will be closed too. For example, this method returns a that uses UTF-8 to translate an underlying input stream. When the reader is closed, the input stream will be too.

    public static Reader getUTF8Reader(@WillCloseWhenClosed InputStream in) throws IOException { return new BufferedReader(new InputStreamReader(in, "UTF-8")); }

    In fact, this is how input stream readers have always worked, but now it's more explicit and obvious.


    Three annotations are used to indicate security properties, and are useful for static analysis tools inspecting web applications for potential vulnerabilities to cross-site scripting, cross-site request forgery, SQL injection, and similar attacks:

    • @Tainted
    • @Untainted
    • @Detainted

    The plan here is to identify which data comes from where. Data from outside the application is marked as @Tainted and not to be trusted. Data from inside the application--for instance, constant strings--is marked as @Untainted and assumed to be trusted. Tainted data that has been sanitized by passing it to some sort of escaping function can be annotated as@Detainted. Security analysis tools can then follow the path of data through a system and make sure that tainted data never reaches a part of the system that trusts its input.

    Concurrency Annotations

    Multithreaded code is some of the hardest to write and debug in any language, and Java is no exception. This is true when you write all the code yourself, and triply so when you have to depend on third-party libraries. Few libraries bother to properly document their thread-safety characteristics. For instance, off the top of your head, can you tell me whether ajava.text.DateFormat is or is not thread-safe? And in more detail, can you tell me under what conditions aDateFormat object can be used in multiple threads? What, if anything, do you need to synchronize to make it thread-safe?

    Four annotations in javax.annotations.concurrentare being proposed to improve this situation:

    • @Immutable
    • @ThreadSafe
    • @NotThreadSafe
    • @GuardedBy

    @Immutable is the simplest concurrency annotation. It merely declares that objects of a class do not change after construction and are thus immutable. For example,

    @Immutable public class String { ...

    Immutable objects are inherently thread-safe. The main benefit of this annotation is simply documentation for client programmers. However, static analysis tools can now complain if they spot, for example, a setter method on a non-final field in a supposedly immutable class.

    @ThreadSafe promises that the class behaves well even when instances are shared between different threads at the same time. It has sufficient internal synchronization to avoid state inconsistency, race conditions, deadlocks, starvation, and similar problems. For example,

    @ThreadSafe public class StringBuffer { ...

    This annotation warns static analysis tools to pay more attention to thread-safety issues they uncover that might not be the result of an error in a class that is specifically marked as@ThreadUnsafe:

    @ThreadUnsafe public class StringBuilder { ...

    A static analysis tool will not flag thread-safety errors in explicitly unsafe classes, but instead will warn@ThreadSafe clients if they fail to use enough external synchronization mechanisms when sharing unsafe objects across threads.

    Finally @GuardedBy warns clients that they can access a class safely in multiple threads if and only if they first obtain a lock on the specified object. For example, here we say you have to have a lock on the object itself:

    @GuardedBy("this") public class Foo { ...

    Some classes require a lock on the class rather than the object:

    @GuardedBy("Foo.class") public class Foo { ...

    Other classes may have a method to return their lock object:

    import java.util.concurrent.locks.*; @GuardedBy("getLock()") public class Foo { private final Lock lock = new ReentrantLock(); public Lock getLock() { return lock; } ...

    Of course, you still have to design the class such that it is thread safe when the correct lock is held. However, now it's simpler to document the proper lock and verify that it's used correctly.

    Summing Up

    Code that uses annotations is clearer, more expressive, and shorter. All of this contributes to more reliable, bug-free code. JSR 305 promises to help us more clearly and easily say what we mean and leave less to be inferred or guessed at. That's a big step forward.

    Remember, although these annotations are being proposed for inclusion as standard in Java 7, they don't depend on any new features of Java 7. With just one extra JAR file, all of this should work with any codebase compatible with Java 5 or later. Why wait for Java 7? Start buttressing your code with JSR 305 annotations today.