There are still a few unsolved problems, most of them concerning arrays of annotations, or arrays in general. Some concern arrays that have a different size than the default value, some concern arrays with zero elements, for which it is more difficult to get the element type. Mostly, I have pondered how to deal with arrays of annotations, though, but I haven’t actually implemented anything yet. I have considered passing the members of annotation array elements as individual arrays, but that creates problems too:
@PredicateLink(MyPredicates.class)
@interface MyAnnotation {
String value;
int i;
}
@Combine
@interface MyCombined {
MyAnnotation[] value();
}
// auto-generated predicate for MyCombined:
// boolean check(Object thisO, String[] value, int[] i);
In this example, instead of passing an array of MyAnnotation
, I could pass two arrays, one array of String
and one array of int
. That has the advantage that I don’t have to use RUNTIME
retention or create my own runtime representation for the data in MyAnnotation
. This gets problematic, though, when the array elements contain arrays themselves, i.e. when there’s an array in MyAnnotation
:
@PredicateLink(MyPredicates.class)
@interface MyAnnotation {
String[] value;
int i;
}
@Combine
@interface MyCombined {
MyAnnotation[] value();
}
// auto-generated predicate for MyCombined:
// boolean check(Object thisO, String[][] value$value, int[] value$i);
This isn’t too bad yet, except that such an array of arrays is becoming rather painful to create. The $
is just there to help distinguish members from different fields. It gets worse, though, when the array is an array of annotations:
@PredicateLink(MyPredicates.class)
@interface MyAnnotation {
String[] value;
int i;
}
@Combine
@interface MyCombined {
MyAnnotation[] value();
MyAnnotation other();
}
@Combine
@interface MyCombinedCombined {
MyCombined[] value();
MyAnnotation other();
}
// auto-generated predicate for MyCombined:
// boolean check(Object thisO,
// String[][][] value$value$value, int[][] value$value$i,
// String[][] value$other$value, int[] value$other$i,
// String[] other$value, int other$i);
Do I really want to do this? Here it also becomes more apparent why the $
is needed, but that’s not the problem, I handle that already. I don’t think separating arrays this way is such a good idea. Another thing I could do would be to automatically generate a storage data structure for an annotation used in an array, something like a struct
in C++, i.e. for MyAnnotation
I would generate a MyAnnotationStruct
that just has two public fields, String[] value
and int i
. Then I could more easily pass the data as array, the way it was intended.
At this point, however, I’m starting to wonder if maybe I should just use RUNTIME
retention instead. I should really write a version that uses RUNTIME
retention and reflection to do everything. It may solve some problems more elegantly, like this one, and at least serve as a way to compare performance.
I think my first cut will be the “code bloat” approach, though: I will generate a new predicate for each new array size. To accommodate for multiple arrays in several places, I can simply enumerate the arrays along a preorder walk and include index-size pairs in the predicate method name: check$1-2$2-0$3-0
would be the appropriate predicate for an annotation whose first array has two elements and whose second and third array have zero elements.