I\'m trying to write a simple validation lib with annotations that use the new TYPE_USE target from Java 8. The way to access these things is really complex, and left me wit
In your initial call to create
you pass in the field annotations but not the annotations for the AnnotatedType at
. Therefore, the method create
is responsible for calling at.getAnnotations()
. If you look at your implementation you will find out that it will do so only in the array case. In all other cases, your method switches the logic to “the passed in annotation array is the one associated with at
”.
The problem is that your first example seems to work by accident. You didn’t show the declaration of your @First
annotation but I suspect that it is allowed for both @Target
s, ElementType.FIELD
and ElementType.TYPE_USE
. In this case, a declaration of the form
@First("array") List… [] fieldName;
is ambiguous and the annotation will be recorded as both, a field annotation for fieldName
and an annotation for the List…[]
type. So the fact that one annotation array is lost during your recursion is not recognized in the first example because it happens to match the field annotations. But once an annotation is allowed for TYPE_USE
only but not FIELD
targets, your code doesn’t even work with your first example.
So you have to decide whether the passed in annotation array shall be the one associated with the at
parameter or of the surrounding context. It would be easier if both are associated, as in this case you could get rid of that parameter entirely by letting the method retrieve that array rather than the caller.
You should keep in mind:
TYPE_USE
annotation primarily, you don’t need to deal with field annotations at allHere is a simple, straight-forward parsing code finding all annotations:
public static void fullType(Field f) {
AnnotatedType at = f.getAnnotatedType();
fullType("\t", at);
System.out.println(f.getName());
}
public static void fullType(String header, AnnotatedType at) {
final boolean arrayType = at instanceof AnnotatedArrayType;
if(arrayType) {
fullType(header+"\t",
((AnnotatedArrayType)at).getAnnotatedGenericComponentType());
}
for(Annotation a: at.getAnnotations())
System.out.println(header+a);
if(arrayType) {
System.out.println(header+"[]");
}
else if(at instanceof AnnotatedParameterizedType) {
AnnotatedParameterizedType apt = (AnnotatedParameterizedType)at;
System.out.println(header
+((ParameterizedType)apt.getType()).getRawType().getTypeName());
System.out.println(header+'<');
String subHeader=header+"\t";
for(AnnotatedType typeArg:
apt.getAnnotatedActualTypeArguments())
fullType(subHeader, typeArg);
System.out.println(header+'>');
}
else if(at instanceof AnnotatedTypeVariable) {
// when appearing in a Field’s type, it refers to Class’ type variables
System.out.println(header+at.getType().getTypeName());
}
else if(at instanceof AnnotatedWildcardType) {
System.out.println(header+"?");
final AnnotatedWildcardType awt = (AnnotatedWildcardType)at;
AnnotatedType[] bounds=awt.getAnnotatedLowerBounds();
if(bounds==null || bounds.length==0) {
bounds=awt.getAnnotatedUpperBounds();
if(bounds==null || bounds.length==0) return;
System.out.println(header+"extends");
}
else System.out.println(header+"super");
header+="\t";
for(AnnotatedType b: bounds) fullType(header, b);
}
else {
assert at.getType().getClass()==Class.class;
System.out.println(header+at.getType().getTypeName());
}
}
It works flawlessly with your example fields.
You said:
@First("array") List<@First("string") String> @First("list") [] arrayOfListOfString;
Works fine (the annotations are matched with the corresponding types).
This looks wrong to me. A type such as
@English String @NonEmpty []
is read as "non-empty array of English strings".
Now let's consider your example (which I have simplified slightly):
@First("array") List @First("list") [] arrayOfList;
You have a @First("list") array, where each element is a @First("array") List. Is that what you want? It's not what is implied by the names.
I don't know what is wrong with your code in the listOfArrayOfInteger
case, but you might want to revisit your claim "The code seems to work in every other scenario" given that the one example that you gave seems to be incorrect.