Did you know? DZone has great portals for Python, Cloud, NoSQL, and HTML5!

Václav is a programming enthusiast who's constantly seeking ways to make development more effective and enjoyable. He's particularly interested in server-side Java technologies, distributed systems, concurrency, agile methodologies, modern programming languages and DSLs.
He works for JetBrains as a senior software developer and a technology evangelist. He is also a board member of the JetBrains Academy. On the side, he's leading the GPars project, an opensource concurrency library, and investigates the domains of neural networks, evolutionary programming and data mining. You can check out his blog or follow him on twitter.
[dzone] Václav is a DZone Zone Leader and has posted 45 posts at DZone. View Full User Profile

Annotate your code to find more bugs

09.30.2009
Email
Views: 4582
  • submit to reddit

We've talked about protecting your reputation with Static Code Analysis recently. In this article we'll build on that technique and show some of the JSR-305 annotations, which can help IntelliJ IDEA spot even trickier issues in your code and so help you save your career of a skilled professional developer.

To briefly recap the story, IntelliJ IDEA comes with a built-in powerful Static Code Analysis engine. This smart engine eagerly scans your code in the background while you think or type, builds an Abstract Syntax Tree (AST) from the code and then searches for known bugs, problems, style rule violations and such in the AST. Found problems get instantly highlighted in the editor for you to fix them. Immediately while you still remember the code and what it does. With static code analysis you typically get rid of many bugs long before you save the file, compile the project and run unit tests.

The JSR-305 proposal suggests several helper annotations, like @Nullable, @NotNull or @Tainted for you to mark certain meta-information in your code. You are able to specify constraints which hold true for a particular method, field, parameter or variable. For example, you can indicate that a particular method may return null and so help the inspection engine to search for potential NullPointerException being raised from your code.

Can you see the warning? Since getName() may return null, the code is incorrectly handling a potentially null value in the name field.

Marking the same method with @NotNull will remove the warning since now your code is free to assume that name doesn't contain a null value and so the NullPointerExceptions cannot happen.

A wise move is to let the @Nullable and @NotNull annotations to influence run-time behavior of the application.



After checking the "Add @NutNull assertions" checkbox in the compiler settings, IntelliJ IDEA will enhance the generated byte-code with checks for null values wherever the @NotNull annotation is used and let the code throw IllegalArgumentException if the @NutNull rule gets violated. You don't get a nasty NullPointerException somewhere far down the road, but instead the application fails with an exception showing the exact spot in your code, where to start searching for the problem - the place, where your expectation expressed via the annotation doesn't match the reality.



Internationalization issues

Let's move on to the next handy fellow - the @NonNls annotation can be used to mark string values as not being locale-sensitive. Since IntelliJ IDEA wants to help you create localized applications, it can complain whenever you try to use a hard-coded String value in an internationalization-sensitive context. By marking a field or parameter as @NonNls you indicate that hard-coded non-localized values can be accepted.

Property files

On a similar note, you can also declare a variable as @PropertyKey and so the engine can check whether the value stored in the variable refers to a valid key in the given property file. And once the meta-information is available, obviously it will be used for your further benefit - to populate a completion dialog for you, if you press Control + Space.



Custom patterns for String values

With the @Pattern annotation you make sure the annotated element always contains a String value matching the supplied regular expressions.

The @Pattern annotation has two helpful children - the @PrintFormat and @Identifier annotations. They are two pre-defined special cases of the @Pattern annotation.
And yes, you are right - defining your own derived annotations is a breeze:

@Pattern("\\d+")
public @interface Number { }

Embeded languages

Last but not the least, we've talked already earlier about language injection with the @Language annotation. Check it out, it is very useful if you combine technologies and languages in your projects.

All combined

So now imagine using these annotations combined in your code. Although you have to add the annotation into your code, in many scenarios they can help you actually reduce the overall amount of code you have. The following method triples a number that comes in a String variable. Notice the amount of code that merely checks whether the value is really a not-null positive integer value.

    public static String triple(final String value) {
try {
if (value != null) {
final int number = Integer.parseInt(value);
if (number<=0)
throw new IllegalArgumentException("The argument must contain a positive integer number");
return "" + number*3;
} else {
throw new IllegalArgumentException("Null values are not allowed");
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("The argument must contain a positive integer number");
}
}

Using the @NotNull and @Pattern annotations we can reduce the above method to this:

    public static String triple(@NotNull @Pattern("[0-9]+") final String value) {
return "" + Integer.parseInt(value) *3;
}

This is a space-saver, isn't it. Also, the method signature now explicitly states, what values are expected, the inspection engine will highlight all attempts to pass invalid values into the method and yet we got code, which is clear at the first glance about what it actually does.

Integration

The annotations.jar file that comes with all IntelliJ IDEA distributions contains the definitions of the annotations we looked at. As long as you keep the file on your project classpath, neither your Continuous Integration server nor the other IDEs will complain about them. However, only IntelliJ IDEA and TeamCity can currently leverage the annotations to your full benefit.

Summary

Now this is it for today. We've looked at a couple of standard JSR-305 annotations, which can help the Static Code Analysis engine find more bugs in our code.

Have fun finding bugs in your code!

 

Published at DZone with permission of its author, Václav Pech.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Balaji N replied on Wed, 2009/09/30 - 3:27pm

Great article! Thanks for taking the time to explain Anotation. I've been thinking about similar topics lately, and it's good to see that I'm not alone. What do you think about writting better CSS?

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.