Is Java annotation order persistent?

2019-04-25 12:05发布

问题:

Is Java annotation order persistent at runtime? I've checked OpenJDK 1.7.0_21 - it preserves annotations order. Can I expect that persistence on all java VMs?

回答1:

Depends on what you mean by "persistent". I think you might have meant something implied in the question, so here's few Q&A:

Is the annotation order persistent?
Yes, it's written in the .class file in an order that doesn't change.

Does the annotations order in the .class file reflect the annotations order in the source code?
Yes. If you compile your code...

@Column(length = 256)
@NotBlankConstraint(message = "The application title must be set.")
@Size(min = 1, max = 256, message = "The application title must be set and not longer than 250 characters.")
private String title;

and check with javap -v:

 #67 = Utf8               Ljavax/validation/constraints/Size;
...
private java.lang.String title;
  descriptor: Ljava/lang/String;
  flags: ACC_PRIVATE
  RuntimeVisibleAnnotations:
    0: #50(#62=I#63)
    1: #64(#65=s#66)
    2: #67(#68=I#69,#70=I#63,#65=s#71

If you change the order of the annotations, the order in the byte code will change as well. Tested with OpenJDK 1.8.0_121, but I think that's the case for earlier JDKs too.

Is the order from the bytecode kept by the getAnnotations() method?
Yes, from what I can see, it is consistently returning the same order as is in the byte code in the .class file.

Is getAnnotations() guaranteed to reflect the bytecode annotations order in the future?
No. As replied by the other answer, this behavior is not documented, so can't be relied on in a publicly available library.
However, there are subtle signs that the order should be kept somehow.

Now to your purpose, If it was guaranteed, should I use the order to have some annotation apply to some previous annotations?
That's a matter of taste, but I would say that most Java programmers wouldn't like that. It wouldn't be much intuitive and readable code. I would suggest to group the annotations such like

@ValidationGroup(
     validators = { @NotNull, @NotEmpty },
     message = "User name must be filled."
)
public String getUsername(); 

The problem with this is that you can't have an array of "any annotation", and since there's no inheritance for annotations, this can't be done (Java 1.8). So various frameworks resort to what Bean Validation uses - see it's concept of groups.

Lastly, I'd second to Eric's comment to check JSR 303, it's quite well done and also integrated into many other libraries like RestEasy.



回答2:

java.lang.reflect.AnnotatedElement.getAnnotations() API says that it returns all annotations present on this element. It says nothing about the order in which these annotations are returned



回答3:

In Java 7 and lower, you cannot have multiple annotations of the same type on an element. You can make them part of the value of another annotation:

// JSR 303
@Pattern.List({
    @Pattern(regexp="\\w{8,14}"),
    @Pattern(regexp=".*Z.*")
})
public String getCode() {
    return code;
}

Java 8 will be relaxing this. See Oracle's bug tracker. This was discussed at Stack Overflow.