Last night, just before I passed out into comatose sleep after being up all “Wednursday” (Wednesday + Thursday ;)) again, I wrote code to also export arrays and annotations, i.e. data with structure inside, as XML that reflects the structure. Before, I was just dumping it out as a string. I also tested it, but I really wasn’t sure I could trust my coding OR testing skills after being up that long, so I just revisited it, and the code seems to be good.
You may ask why I’m putting so much importance on correctly exporting these annotations to an XML format. Right now, I don’t have code that imports that XML data back, in fact, I don’t even have the code that inserts the runtime checks. So why bother with exporting?
Looking at the XML is just the easiest way for me to make sure that I am gathering the data correctly and that I’m putting it together the right way. Yeah, writing this code took some time too, but it’s a convenient and reassuring stop on the way to what I need to do, and since importing the XML will be important later, this effort isn’t even wasted.
Here’s an example of XML generated from predicate annotations:
The Java code below contains the methods and some of the annotations and predicates. It demonstrates how different kinds of data are processed:
- The method
void foo()
is annotated with just a marker annotation; the XML for it simply has a<predicate>
tag that specifies the class of the annotation. - The method
void bar()
has an annotation with a string and a boolean, but boolean has a default value, so it’s not specified in the Java code. In the XML, in addition to the<predicate>
tag, there are two nested<arg>
tags that hold name-type-value triples for both the string and the boolean. - The methods
void arr()
andvoid arr2()
both have annotations with an array of strings, butvoid arr2()
uses the default value. For arrays, I’ve decided that there will still be nested<arg>
tags that hold name-type-value triples, but the value is the size of the array, and the actual elements are stored in nested<element>
tags. - The methods
void ann()
void ann2() have an annotation that itself has an annotation as member;void ann2()
again uses the default value. For annotations, the value attribute of the<arg>
tag contains the class name of the annotation, and then the data of the members is placed in<arg>
tags that are themselves nested in the<arg>
tag of the annotation. - The methods
void enu()
void enu2() are pretty simple, but they have an annotation with anenum
as member, andenums
print out a little funny. I guess I could split it up into a class-value pair. - The last two methods,
void arrAnn()
void arrAnn2(), finally have an annotation that contains an array of annotations. The XML they generate is a result of what has been explained above, I just wanted to make sure it works correctly. At this time I also noticed that arrays with more than one dimension (likeString[][]
) aren’t allowed inside annotations; that was another case I was worried about.
// class with predicate methods for structured data
class Checks {
public static boolean checkArray(Object thisObject, String[] value) {
return true;
}
public static boolean checkAnnot(Object thisObject, PredicateLink value /*???*/) {
return true;
}
public static boolean checkEnum(Object thisObject, RetentionPolicy value) {
return true;
}
}
// calls Checks.checkArrayObject thisObject, String[] value)
@PredicateLink(value=Checks.class, method="checkArray")
@interface ArrayTest {
String[] value() default {"foo", "bar"};
}
// calls Checks.checkAnnot(Object thisObject, PredicateLink???)
@PredicateLink(value=Checks.class, method="checkAnnot")
@interface AnnotTest {
PredicateLink value();
}
// calls Checks.checkEnum(Object thisObject, RetentionPolicy)
@PredicateLink(value=Checks.class, method="checkEnum")
@interface EnumTest {
RetentionPolicy value() default RetentionPolicy.RUNTIME;
}
// calls Checks.checkArrayAnnot(Object thisObject, PredicateLink[] value)
@PredicateLink(value=Checks.class, method="checkArrayAnnot")
@interface ArrayAnnotTest {
PredicateLink[] value() default {
@PredicateLink(Object.class),
@PredicateLink(value=String.class, method="foo")};
}
public class TCTest2 {
@OnlyEventThread
public void foo() {
// only allowed to be run by event thread
}
@OnlyThreadWithName("auxThread")
public void bar() {
// only allowed to be run by thread with name "auxThread"
}
@ArrayTest({"abc", "xyz"})
public void arr() {
}
@ArrayTest()
public void arr2() { }
@AnnotTest(@PredicateLink(TCTest2.class))
public void ann() { }
@AnnotTest
public void ann2() { }
@EnumTest(RetentionPolicy.SOURCE)
public void enu() { }
@EnumTest
public void enu2() { }
@ArrayAnnotTest({
@PredicateLink(TCTest2.class),
@PredicateLink(TCTest2.class),
@PredicateLink(TCTest2.class)})
public void arrAnn() { }
@ArrayAnnotTest
public void arrAnn2() { }
}
Of course, the annotations @ArrayTest
, @AnnotTest
, @EnumTest
and @ArrayAnnotTest
don’t have any meaning when it comes to concurrency testing. They’re just there so I can test how arrays, annotations and enums
as member values get dealt with.
There’s still one thing where I don’t quite know if what I did was right: The @AnnotTest
annotation has a member that is an annotation itself, PredicateLink
. According to the conventions for the predicates, the predicate method Checks.checkAnnot
has to accept an Object
for this
and one argument for each value in the annotation. But what is the correct type for this annotation? Is it PredicateLink
? How do I call that method? Checks.checkAnnotation(this, @PredicateLink(Object.class));
doesn’t work, and neither does Checks.checkAnnotation(this, new PredicateLink(Object.class));
, because PredicateLink
is an interface.
This is something that I have to figure out when I write the code that actually calls the predicates. I also think that I may want to change the way default values are exported. After thinking about it a little, I don’t think default values should appear in the XML for members whose values aren’t specified. The XML should correspond exactly to what’s written in the source code. It’s either that, or all default values should appear, and currently they don’t get exported when an annotation is a member value.
I need to get going, COMP 311 and my office hours are ahead of me…. We promised to send out the grades on Wednesday, but not all students have been graded. On Thursday night, I finally decided to send out the grades we have and not wait for consistency as planned. So now the ones that don’t have their grades yet will probably complain to me, and the ones that did get their grades will complain about certain deductions. Yay.