这是使用JSR305中的javax.annotation的正确方法吗?

时间:2022-09-25 10:37:01

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

我最近将JSR305的RI添加到我的项目中,并且一直在为我的接口添加注释,如下所示:

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.

根据JSR的精神(如此处所述),您认为我在界面中使用它们会误用注释吗?我想指出返回值可以为null但我认为@Nullable更多地应用于方法“合并”。我没有将它们添加到实现中,因为当我编码时,接口的代码是我的指路明灯。

2 个解决方案

#1


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).

您可以将'@NonNull String'视为String的严格子类。毕竟,任何非null的String绝对是'instanceof''@ Nullable String',但是'@Nullable String'的任何实例都可能不是'@NonNull String'的实例(如果它是null,则不会是例如)。

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.

以这种方式看,@ Nullable和@NonNull是类型信息,因此在接口中非常合理。您向实现者指示他们可能返回null,并且他们不必担心输入空值,并且您向调用者指示他们不能传入null,并且他们应该期望null。

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.

当然,虽然这一切都非常合理,但vanilla javac v1.6肯定不会强制实施任何这些规则,因为它强制实际类型的类型安全。但是人们可以梦想,或者可以使用像pmd或findbugs这样的东西来完成验证这些注释的工作。

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.

但是,对于完整的无效类型系统,@ NonNull和@Nullable注释是不够的。我真的不知道为什么JSR305没有解决这个问题,但还有第三种类型:“@ MaybeNull”。它会显示在泛型参数内部;在任何其他地方,它与@Nullable具有相同的含义。

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

public static 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 (A) never cause a NullPointerException, and (B) 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.

如果第一个'T'上的注释有“@Nullable”,那么你就无法传递非空列表,这会产生一个相当无用的API。另一方面,如果它是@NonNull,你就无法传递一个可空的列表。在实践中,你在那里移动并不重要,它将(A)永远不会导致NullPointerException,并且(B)从不违反了注释。所以,你需要一种表达方式:我不在乎这个特定的'T'是否可以为空;当我从中读取时,我将进行空值检查,并且我永远不会写空值,所以无关紧要。

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.

@ MaybeNull和@Nullable之间的区别类似于'?在泛型中扩展Number'和'Number'。除了泛型之外,它们的含义相同,但在泛型中则存在差异。

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.

@Inherited仅适用于类,但可以想象类似于带注释的返回类型和带注释的参数。

#2


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.

我使用注释进行事务处理和安全角色实施,因此我的注释处于实现级别。有趣的是,我的Spring容器中的AOP处理器可以测试这个或那个注释的存在,并应用适当的代理类来执行诸如定义事务边界或确保用户被授权进行某些特定方法调用的操作。

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.

因此,如果您计划关闭是否存在注释的任何处理,请确保您的实现已注释。如果仅供参考,可以只注释界面。

#1


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).

您可以将'@NonNull String'视为String的严格子类。毕竟,任何非null的String绝对是'instanceof''@ Nullable String',但是'@Nullable String'的任何实例都可能不是'@NonNull String'的实例(如果它是null,则不会是例如)。

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.

以这种方式看,@ Nullable和@NonNull是类型信息,因此在接口中非常合理。您向实现者指示他们可能返回null,并且他们不必担心输入空值,并且您向调用者指示他们不能传入null,并且他们应该期望null。

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.

当然,虽然这一切都非常合理,但vanilla javac v1.6肯定不会强制实施任何这些规则,因为它强制实际类型的类型安全。但是人们可以梦想,或者可以使用像pmd或findbugs这样的东西来完成验证这些注释的工作。

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.

但是,对于完整的无效类型系统,@ NonNull和@Nullable注释是不够的。我真的不知道为什么JSR305没有解决这个问题,但还有第三种类型:“@ MaybeNull”。它会显示在泛型参数内部;在任何其他地方,它与@Nullable具有相同的含义。

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

public static 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 (A) never cause a NullPointerException, and (B) 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.

如果第一个'T'上的注释有“@Nullable”,那么你就无法传递非空列表,这会产生一个相当无用的API。另一方面,如果它是@NonNull,你就无法传递一个可空的列表。在实践中,你在那里移动并不重要,它将(A)永远不会导致NullPointerException,并且(B)从不违反了注释。所以,你需要一种表达方式:我不在乎这个特定的'T'是否可以为空;当我从中读取时,我将进行空值检查,并且我永远不会写空值,所以无关紧要。

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.

@ MaybeNull和@Nullable之间的区别类似于'?在泛型中扩展Number'和'Number'。除了泛型之外,它们的含义相同,但在泛型中则存在差异。

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.

@Inherited仅适用于类,但可以想象类似于带注释的返回类型和带注释的参数。

#2


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.

我使用注释进行事务处理和安全角色实施,因此我的注释处于实现级别。有趣的是,我的Spring容器中的AOP处理器可以测试这个或那个注释的存在,并应用适当的代理类来执行诸如定义事务边界或确保用户被授权进行某些特定方法调用的操作。

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.

因此,如果您计划关闭是否存在注释的任何处理,请确保您的实现已注释。如果仅供参考,可以只注释界面。