Hello,
Please review the changes to address:
JDK-8058202 : AnnotatedType implementations don't override
toString(), equals(), hashCode()
http://cr.openjdk.java.net/~darcy/8058202.2/
Some discussion and explanation of the changes:
The java.lang.reflect.AnnotatedType interface hierarchy was added in JDK
8 to support type annotations
(http://openjdk.java.net/projects/type-annotations/) in core reflection.
It offers a parallel set of interfaces to the java.lang.reflect.Type
family of interfaces added in JDK 5. The separate AnnotatedType
interfaces are needed since type annotations are used on type *uses* and
not type declarations. For example, it is necessary to be able to model
both of the types of the fields foo and bar in a case like:
@Nonnull String foo;
@Nullable String bar;
so clearly the same object cannot be used for both as the annotated type
of the fields since the type annotations differ.
The implementation classes for the AnnotatedType family used in core
reflection are in a single file AnnotatedTypeFactory.java. There are
instantiated instances both of the base class AnnotatedTypeBaseImpl and
its subclasses which implement the specialized subinterfaces of
AnnotatedType for arrays, type variables, etc.
The implementation classes do *not* declare equals, hashCode, or
toString methods, which the proposed change rectifies.
For equals and hashCode, the interfaces do *not* define how the equals
relation should be calculated, an omission shared by the Type
interfaces. While the default identity-is-equality is correct in some
sense, it is not very useful as the objects returned by successive "get
annotated return type" calls on the same method object will not be equal.
The proposed equals implementations check if the argument object
implements the same AnnotatedType subinterface (and makes sure one of
the subinterfaces is *not* implemented when determining equality for
AnnotatedType implementation objects) and compares the results of
corresponding methods. This is analogous to the equals implementations
of the Type implementation classes found in the impl classes in the
sun.reflect.generics.reflectiveObjects package.
The order of annotations is considered significant for equality; this is
arguably overly strict, but I didn't think it was worthwhile to form
sets of annotations for the purposes of equality comparison in this case.
For toString to replicate the source ordering for most kinds of types,
the type annotations, if any, occur textually to the left of the text
representing the type as in
@Nonnull String
or more interestingly
@Nonnull List<String>
the latter meaning "a nonnull list where the list contains strings."
However, this pattern is not followed for arrays. The annotated type
@Nonnull String[]
means "an array of strings where the strings are nonnull" rather than
"an array that is nonnull where the array contains strings." The
rationale for this is explained in JSR 308 related documents such as:
https://checkerframework.org/jsr308/jsr308-faq.html#syntax
https://checkerframework.org/jsr308/specification/java-annotation-design.html
A multi-dimensional array is represented as an AnnotatedArrayType whose
component type is an array type of lower dimension, and so on, bottoming
out with a non-array component type. The existing toString output for
the Type objects of an array uses VM style notation like
"[[Ljava.lang.String" for a 2D string array. This is even less helpful
for annotated type objects and therefore toString output in the style
usable in source code ("String [] []") will be used instead. Starting
from an AnnotatedArrayType object for a 2D array of strings, using the
integer value of type annotations the encounter order for the
annotations and types is:
@TypeAnno(2) String @TypeAnno(0) [] @TypeAnno(1) []
Therefore, for multi-dimensional arrays, the results for the nested
dimensions are appended to the in-progress string builder while the
results for the non-array component are pre-pended.
Thanks,
-Joe