Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this correct way of using javax.annotation from JSR305?

I've recently added the RI for JSR305 into my project and have been adding annotations to my interfaces like this:

public interface AccountService
{
    @Nullable AccountResult consolidate( @Nonnull Date from, @Nonnull Date to )
}

In the spirit of the JSR (as described here), do you think I'm misusing the annotations by using them in interfaces? I want to indicate that the return value can be null but I think the @Nullable applies more to the method "consolidate". I don't add them to the implementations because when I'm coding, the code for the interface is my guiding light.

like image 827
Jacques René Mesrine Avatar asked May 13 '09 02:05

Jacques René Mesrine


2 Answers

You can see @NonNull String as a strict subclass of String. After all, any non-null String is definitely an 'instanceof' @Nullable String, but any instanceof @Nullable String may not be an instance of @NonNull String (it wouldn't be if it was null, for example).

Looking at it that way, @Nullable and @NonNull are type information, and are therefore perfectly reasonable in interfaces. You are indicating to implementers that they may return null, and that they do not have to worry about input nulls, and you are indicating to callers that they must not pass in null, and that they should expect nulls out.

Of course, while this is all very reasonable, vanilla javac v1.6 certainly doesn't enforce any of these rules the way it enforces type safety for actual types. But one can dream, or one could use something like pmd or findbugs to take the job of verifying these annotations.

The @NonNull and @Nullable annotations aren't enough for a complete nullity typing system, though. I don't really know why JSR305 doesn't address this, but there's a third type: @MaybeNull. It would show up inside of generics parameters; anywhere else it would have the same meaning as @Nullable.

public static <T> void addIfNotNull(List<@MaybeNull T> list, @Nullable T item) {
  if ( item != null ) list.add(item);
}

If the annotation on the first T there is @Nullable, then you could not pass non-null lists in, which would make for a rather useless API. On the other hand, if it was @NonNull, you could not pass a nullable list in. In practice, it doesn't matter what you move in there, it'll

  1. never cause a NullPointerException, and
  2. never violate the annotation.

So, you need a way to express: I don't care if this particular T is Nullable or not; I will null-check when I read from it, and I will never write nulls, so it doesn't matter.

The difference between @MaybeNull and @Nullable is analogous to the difference between ? extends Number and Number in generics. Outside of generics they mean the same thing, but in generics there's a difference.

So, don't keep your hopes up for a rigid typecheck anytime soon.

@Inherited only works for classes, but one would imagine something similar for annotated return types and annotated parameters.

like image 79
2 revs, 2 users 57% Avatar answered Oct 05 '22 05:10

2 revs, 2 users 57%


I think it depends on why you are adding the annotations.

If you're just adding them for reference so that implementers of the interface know your intended design, then that's fine.

I use annotations for transactional processing and security role enforcement, so my annotations are at the implementation level. What's nice about this is that AOP processor in my Spring container can test for the presence of this or that annotation and apply appropriate proxy classes to do things like define a transactional boundary or ensure that the user is authorized for some particular method call.

So, if you're planning to key any processing off of the presence or absence of the annotation, make sure your implementation is annotated. If its just for reference, its OK to annotate just the interface.

like image 35
nont Avatar answered Oct 05 '22 07:10

nont