Better Control Flow Analysis with Contract Annotations and IntelliJ IDEA 13

As we’re closing in on the release date, we’re going to publish more details on the new features of IntelliJ IDEA 13. Today we’d like to tell you about the new @Contract annotation.

If you are aware of @Nullable/@NotNull annotations, you probably know how helpful they are against NullPointerException. The new @Contract annotation brings one more layer of safety for your code by defining dependencies between method arguments and return values. This information lets IntelliJ IDEA provide smarter control flow analysis for your code and avoid probable errors.

Here’s an example: say we’ve got a method sort() that returns a sorted list or a null value if the argument is null.

Now if we try to to call this method with a null value and check the result against null, IntelliJ IDEA will not complain because it doesn’t know that a null input yields a null output.

How can we help IntelliJ IDEA? That’s right… Decorate the sort() method with a @Contract annotation, specifying that null inputs yield null outputs:

Now IntelliJ IDEA can see that the sort() method always returns null and the if statement is redundant. The corresponding message appears in the editor.

The @Contract annotation value has the following syntax:

  • contract ::= (clause ‘;’)* clause
  • clause ::= args ‘->’ effect
  • args ::= ((arg ‘,’)* arg )?
  • arg ::= value-constraint
  • value-constraint ::= ‘any’ | ‘null’ | ‘!null’ | ‘false’ | ‘true’
  • effect ::= value-constraint | ‘fail’

The constraints denote the following:

  • _ – any value
  • null – null value
  • !null – a value statically proved to be not-null
  • true – true boolean value
  • false – false boolean value
  • fail – the method throws exception, if the arguments satisfy argument constraints

The @Contract annotation is a powerful and flexible tool that helps make your APIs safer. However, you can use it not only for annotating your own code but also for other existing libraries.

Once you’ve configured the annotations for the project libraries, the IDE stores this information in simple XML files so it can be shared with the team via version control.

To enable the annotations in your project, just add <IntelliJ IDEA Home>/lib/annotations.jar to the classpath via Project Structure.

UPDATE: Please find the latest annotations.jar in Maven repository.

Develop with Pleasure!

About Andrey Cheptsov

Andrey Cheptsov is IntelliJ IDEA product marketing manager at JetBrains. He's passionate about productivity, programming languages and tools.
This entry was posted in New Features and tagged , , . Bookmark the permalink.

27 Responses to Better Control Flow Analysis with Contract Annotations and IntelliJ IDEA 13

  1. Vaclav says:

    I really love checking for nullity in IDEA.

    What I miss however is an option to consider everything @NotNull in your project code unless otherwise stated.

    Basically make it behave like types without question mark in Kotlin. And make @Nullable replacement for the Kotlin question mark. So the code is not so polluted by @NotNull.

    • Peter says:

      FindBugs/JSR305 has the ParametersAreNonnullByDefault annotation, and the option to add your own. I would love it if IntelliJ would support this too.

      The contract annotation looks pretty readable, but will IntelliJ mark any spelling or syntax errors?

  2. Josh says:

    “As we’re closing on to the release date” – Is there an expected release date for 13 yet? I’ve held off from using the EAP’s this time so looking forward to the release!

  3. Jacky Chan says:

    Could you upload the annotations jar (13.0) to the central Maven repository to http://central.maven.org/maven2/com/intellij/annotations/ ?

  4. Gerard Krupa says:

    Will this annotations library be available as a Maven dependency in Central?

  5. James says:

    Is the @Contract annotation why http://youtrack.jetbrains.com/issue/IDEA-35808 was removed from 13? I’d love to see a quick blog post explaining how to teach IntelliJ about contracts for third party jars.

  6. Alexander Kosenkov says:

    Andrey, there’s a problem with screen shot on the front page on http://www.jetbrains.com/idea/whatsnew/
    (CONTRACT ANNOTATION http://www.jetbrains.com/idea/whatsnew/img/13/ij13_contract.png)

    List copy = new ArrayList(…)
    copy can never be null, but @Contract annotaion states otherwise (null -> null).

  7. Andrey Haliullin says:

    As far as I can see, 13 version of com.intellij.annotations still not available in maven central repo, while new Idea is already released. I like the feature you described very much, so when you are going to deploy this jar to maven?

    Thank you!

  8. James says:

    Can @Contract be added to an @Override method if the super-type does not have an @Contract annotation? If the super-type does have @Contract, how does this affect the @Override method? Thanks!

    • Peter Gromov says:

      Yes, @Contract can be added to an overriding method. Contract annotation on the super method has no effect currently on the overriding method, we haven’t yet decided what’s the best way to handle this.

      • James says:

        Okay, thank you. Personally, I believe that is adequate if contradicting / missing @Contracts are reported by an inspection similar to “@Nullable Problems.”

  9. Philipp Middendorf says:

    A little correction to your grammar: You wrote:


    value-constraint ::= ‘any’ | ‘null’ | ‘!null’ | ‘false’ | ‘true’

    This should be ‘_’ instead of ‘any’. I stumbled on that. Example:


    @Contract("null,_,_ -> fail")
    public void foo(Object nullable,Object bar,Object baz) {
    if(nullable == null)
    throw new RuntimeException("nullable is null!");
    }

    PS: As of the 17th of December, the IntelliJ contract annotations are finally in Maven Central!

  10. Imran Zahid says:

    Can @Contracts be added to method arguments?
    I am trying to override Google Guavas @Nullable. My annotation.xml file is:

    Now in my code I have done:

    return Maps.uniqueIndex(entities, new Function() {
    @Override @Nonnull
    public Long apply(@Nonnull E input) {
    return input.getId();
    }
    });

    However IDEA is complaining that @Nonnull E input must not override @Nullable parameter

    • Peter Gromov says:

      No, @Contract annotations cannot be added to method parameters yet. Do you have any suggestions what they could do and how they would look?

      Overriding @Nullable parameter with @Nonnull is reported because it may lead to issues when some other passes null to your function because the super signature contains @Nullable.

      • Imran Zahid says:

        Mu annotations.xml (created by IDEA) is:

        This implied that @Contract could be added to method parameters, but if you say no, then I think this is a bug, as IDEA lets me add a method parameter contract (but doesn’t work).

        The reason I wanted a method parameter @Contract is in my Maps.uniqueIndex example where I am sure my application would never pass null values, thus wanted to override the libraries @Nullable method parameters.

        • Peter Gromov says:

          Sorry, I can’t see your annotations.xml. You can email it to me, peter@jetbrains.com.

          You can add an explicit assertion for that parameter or use Preconditions#checkNotNull(T) (externally annotated with a contract). Or suppress the inspection for that particular place. Or just remove @Nullable annotation from Function.apply. It’s too generic a method to proclaim anything about it.

  11. Richard Kent says:

    Please bring back the Configure IsNull/IsNotNull/True/False Check/Assert Methods functionality from Idea 12 (as an aside, a loss of important functionality on upgrade is never acceptable). The Contract annotation is certainly more expressive but simply doesn’t work well in a mixed environment where some devs are using Idea and some are on eclipse. If you are not willing to resurrect the old “methods” functionality then please allow the contract definitions to be stored in the Idea project files, and not in annotations in the source files.

  12. Pat says:

    RE: UPDATE: Please find the latest annotations.jar in Maven repository.

    So, should we be adding the following dependency to our project’s pom.xml?

    org.jetbrains
    annotations
    13.0

    If so, what about Project Structure -> Platform Settings -> SDKs -> Annotations?

    Should we remove the entry /IntelliJ IDEA 13.1/lib/Annotations.jar?

    If not, should we simply overwrite /IntelliJ IDEA 13.1/lib/Annotations.jar with the new JAR file?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>