Summary
For many years common runtime exceptions like NullPointerException or ClassCastException are haunting poor Java programmers. This often leads to repetitions in the source code for checking method arguments for nullness. This is violating the DRY(Don’t repeat yourself) principle. The Java Community Process created JSR-305 to address this issue. Unfortunately this JSR didn’t become part of the official Java languages, but tools like FindBugs or IDEs like IntelliJ are offering static code analysis to find such NullPointerExceptions at compile time.
Here is an example of a very leaky code:
public void doSomethingTheOldWay(String aParam) {
if (aParam == null) {
throw new IllegalArgumentException();
}
int length = aParam.length();
}
This method will definitely throw a IllegalArgumentException if null is passed as an argument. Ok, now lets take a look at the following code:
public String returnSomething() {
return null;
}
public void compute() {
int theLength = returnSomething().length();
}
This will for sure generate a NullPointerException. Those errors are hard to track. Even with static code analysis FindBugs or IntelliJ do not recognize the problem.
JSR-305
JSR-305 was designed to help with automatic detect detection. This JSR provides a set of common annotations to easy code analysis. Here is an example:
public void doSomethingWithParam(@Nonnull String aParam) {
if (aParam == null) {
throw new IllegalArgumentException();
}
}
@Nonnull public String compute(@Nonnull String aParam) {
return null;
}
The doSomethingWithParam() Method is annotated so it cannot accept a null as a parameter. The compute() Method is annotated that is does not accept a null parameter and even does not return a null value. Let''s see what IntellJ inspections are doing with the following example:
doSomethingWithParam(null);
compute("Mirko");
This will give you the following bug report:
JSR-308
JSR-308 Annotations on Java Types is another approach to the problem mentioned above. It defines a language extension that will probably be added in Java 8. It includes a set of annotations like @NonNull, @Nullable and so on, and a checker framework as well. Unfortunately it provides some redundant annotations to JSR-303, hopefully this will be fixed.
JSR-303
JSR-303 Bean Validation API gives us the same set of annotations as JSR-305, Nullable, NotNull and so on. It also provides more like validations rules with patterns. JSR-305 was probably retired as JSR-303 or JSR-308 can do the same thing.
Very interesting is JSR-303 Version 1.1. It provides a new Method Level Validation. Details can be found here. The official release is planned for Q3/Q4 2012. IntelliJ does recognize Nullable or NotNull annotations, but not the NotNull annotations for method return value. Here is a bug report generated by IntelliJ for the above example with JSR-303 annotations:
AOP
Checking method parameters for nullness and manual throwing of IllegalArgumentException is bloating the source code and also violating the DRY principle. We can use an around advice together with an AOP framework like AspectJ to weave every JSR-303 annotated method and decorate it with JSR-303 method level validation. By this way we can check pre- and post conditions of method invocation.
The following code will remain:
public void doSomethingWithParam(@NotNull String aParam) {
int length = aParam.length();
}
In this case, the IllegalArgumentException is thrown by the AOP advice. Nice, isn’t it?
Summary
Together with AOP and JSR-303, defect detection automation can be very powerful. It cleans up the sources and also helps not to violate the DRY principle. Feel free to consult the AspectJ documentation or the JSR-303 reference implementation Hibernate Validator for more information.
Git revision: 2e692ad