210 likes | 237 Views
Java Annotations for Invariant Specification. Mathias Ricken September 22, 2008 COMP 617 Seminar. Comments are dumb. class HashMap { // returns null if no mapping for key Object get(Object key) { … } } HashMap m = new HashMap(); Object o = m.get("foo"); String s = o.toString();.
E N D
Java Annotations for Invariant Specification Mathias Ricken September 22, 2008 COMP 617 Seminar
Comments are dumb class HashMap { // returns null if no mapping for key Object get(Object key) { … } } HashMap m = new HashMap(); Object o = m.get("foo"); String s = o.toString(); NullPointerException at runtime: o is null
Types are smart class HashMap { // returns null if no mapping for key Object|null get(Object key) { … } } HashMap m = new HashMap(); Object o = m.get("foo"); String s = o.toString(); Compiler Error: Return type Object|null incompatible with type Object This is not Java!
Annotations can make Java smarter class HashMap { // returns null if no mapping for key @Nullable Object get(Object key) { … } } HashMap m = new HashMap(); Object o = m.get("foo"); String s = o.toString(); Compiler Warning: Return value may be null, assigned to non-null variable. Pluggable type systems in Java 5 7?
Annotation Targets in Java 5 @A package some.package.name; @B class MyClass { @NonNull Object field; @C MyClass(@NonNull Object param) { field = param; } @NonNull Object method() { @NonNull Object localVar = field; return localVar; } } Note: Local variable annotations are completely ignored.
Concurrency Invariants interface TableModel { // may only be called from event thread void setValueAt(…); } TableModel m; // from outside event thread… m.setValueAt(…); Possible race condition.
Invariant Specification interface TableModel { @OnlyEventThread void setValueAt(…); } TableModel m; // from outside event thread… m.setValueAt(…); Invariant Violation Warning at Runtime (but still possible race condition)
Comparison to assert void setValueAt(…) { assert (EventQueue.isDispatchThread()); … • Similarity • Debug mode – disabled in production code @OnlyEventThread void setValueAt(…) { … }
Annotations are Easier to Find • Javadoc produces invariant index
Inherited Invariants TableModel Object getValueAt(…) @OnlyEventThread void setValueAt(…) Implied @OnlyEventThread AbstractTableModel Object getValueAt(…) void setValueAt(…) DefaultTableModel MySpecialTableModel Object getValueAt(…) void setValueAt(…) Object getValueAt(…) void setValueAt(…) Implied @OnlyEventThread Implied @OnlyEventThread
Inherited Invariants @OnlyEventThread TableModel Object getValueAt(…) void setValueAt(…) Implied @OnlyEventThread AbstractTableModel Object getValueAt(…) void setValueAt(…) Implied @OnlyEventThread DefaultTableModel MySpecialTableModel Object getValueAt(…) void setValueAt(…) Object getValueAt(…) void setValueAt(…) Implied @OnlyEventThread Implied @OnlyEventThread
Limited Universality assert (someComplexPredicate()); • A few supplied invariant annotations @OnlyEventThread @OnlyThreadWithName @OnlySynchronizedThis @NotEventThread @NotThreadWithName @NotSynchronizedThis • assert can test an arbitrary predicate
Predicate Invariant Annotations @PredicateLink(value=Predicates.class, method="eval") public @interface OnlyThreadWithName { String value; } Find predicate method 1. @OnlyThreadWithName("main") void myMethod() { … } 2. • Call predicate method and • pass as arguments: • this (nor null if static) • data in invariant annotation Return true or false to indicate violation 3. public class Predicates { public static boolean eval(Object this0, String name) { return Thread.currentThread().getName(). equals(name); } }
Further Limitation of Annotations • One occurrence of an annotation class per target @OnlyThreadWithName("main") // illegal; and is @OnlyThreadWithName("other") // this "and" or "or"? void myMethod() { … } • Suggestion @Or({ @OnlyThreadWithName("main"), @OnlyThreadWithName("other") }) void myMethod() { … }
Annotation Members extends OtherAnnotation not allowed no subtyping @interface MyAnnotation { int intMember; // primitives String stringMember; // strings Class classMember; // class literals SomeEnum enumMember; // enums // annotions OnlyThreadWithNameannotMember; // arrays of the above OnlyThreadWithName[] arrayMember; }
No Annotation Subtyping in Java @interface Or { OnlyThreadWithName[] value; } @Or({@OnlyThreadWithName("main"), @OnlyThreadWithName("other")}) void myMethod() { … } // legal @Or({@OnlyThreadWithName("main"), @NotThreadWithName("other")}) void otherMethod() { … } // illegal • No common supertype for annotations
xajavac Modified Compiler @interface Base {} @interface OnlyThreadWithName extends Base { String value; } @interface NotThreadWithName extends Base { String value; } @interface Or extends Base { Base[] value; }
Results • Annotations with Subtyping • Minimal changes to the compiler • No changes to class file format • Reduced invariant checker by ~1500 lines • Improved code reuse
Results • Invariant Annotations • Annotated part of Swing and DrJava • Discovered and fixed some bugs in DrJava • Hard to do retroactively and without inside knowledge
Future Work • Reflection library for annotations with subtyping • Annotation getAnnotation(Class c) currently returns the annotation of class c • Annotation[] getAnnotations(Class c) should be added to return all annotations of class c and its subclasses • Modify JSR 308 prototype compiler to support subtyping
More Information and Download • Invariant Specification • http://www.concutest.org/tc/ • Annotations with Subtyping • http://www.cs.rice.edu/~mgricken/research/xajavac/