Transcript Document

Java Annotations for
Invariant Specification
RICE UNIVERSITY
COMPUTER
SCIENCE
Mathias Ricken
September 22, 2008
COMP 617 Seminar
1
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
2
Types are smart
class HashMap {
// returns null if no mapping for key
Object|null get(Object key) { … }
}
Compiler Error:
Return type Object|null
HashMap m = new HashMap();
incompatible with type
Object
Object o = m.get("foo");
String s = o.toString();
This is not Java!
3
Annotations can make Java smarter
class HashMap {
// returns null if no mapping for key
@Nullable Object get(Object key) { … }
}
HashMap m = new HashMap();
Compiler Warning:
Return value may be null,
assigned to non-null variable.
Object o = m.get("foo");
String s = o.toString();
Pluggable type systems in Java 5 7?
4
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.
5
Concurrency Invariants
interface TableModel {
// may only be called from event thread
void setValueAt(…);
}
TableModel m;
// from outside event thread…
m.setValueAt(…);
Possible race condition.
6
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)
7
Comparison to assert
void setValueAt(…) {
assert (EventQueue.isDispatchThread());
…
Similarity
 Debug mode – disabled in production code
@OnlyEventThread
void setValueAt(…) { … }
8
Annotations are Easier to Find

Javadoc produces invariant index
9
Inherited Invariants
TableModel
Object getValueAt(…)
@OnlyEventThread void setValueAt(…)
Implied
@OnlyEventThread
AbstractTableModel
Object getValueAt(…)
void setValueAt(…)
DefaultTableModel
Object getValueAt(…)
void setValueAt(…)
Implied
@OnlyEventThread
MySpecialTableModel
Object getValueAt(…)
void setValueAt(…)
Implied
@OnlyEventThread
10
Inherited Invariants
@OnlyEventThread TableModel
Object getValueAt(…)
void setValueAt(…)
Implied
@OnlyEventThread
AbstractTableModel
Object getValueAt(…)
void setValueAt(…)
DefaultTableModel
Object getValueAt(…)
void setValueAt(…)
Implied
@OnlyEventThread
Implied
@OnlyEventThread
MySpecialTableModel
Object getValueAt(…)
void setValueAt(…)
Implied
@OnlyEventThread
11
Limited Universality

A few supplied invariant annotations
@OnlyEventThread
@OnlyThreadWithName
@OnlySynchronizedThis

@NotEventThread
@NotThreadWithName
@NotSynchronizedThis
assert can test an arbitrary predicate
assert (someComplexPredicate());
12
Predicate Invariant Annotations
@PredicateLink(value=Predicates.class, method="eval")
public @interface OnlyThreadWithName {
String value;
}
1.
@OnlyThreadWithName("main")
void myMethod() { … }
Return true or false
to indicate violation
3.
2.
Call predicate method and
pass as arguments:
• this (nor null if static)
• data in invariant annotation
public class Predicates {
public static boolean eval(Object this0, String name) {
return Thread.currentThread().getName().
equals(name);
}
}
13
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() { … }
14
Annotation Members
extends OtherAnnotation
not allowed  no subtyping
@interface MyAnnotation {
int
String
Class
SomeEnum
intMember;
stringMember;
classMember;
enumMember;
//
//
//
//
primitives
strings
class literals
enums
// annotions
OnlyThreadWithName annotMember;
// arrays of the above
OnlyThreadWithName[] arrayMember;
}
15
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
16
xajavac Modified Compiler
@interface Base {}
@interface OnlyThreadWithName extends Base {
String value;
}
@interface NotThreadWithName extends Base {
String value;
}
@interface Or extends Base {
Base[] value;
}
17
Results

Annotations with Subtyping
 Minimal
changes to the compiler
 No changes to class file format
 Reduced invariant checker by ~1500 lines
 Improved code reuse
18
Results

Invariant Annotations
 Annotated
part of Swing and DrJava
 Discovered and fixed some bugs in DrJava
 Hard to do retroactively and without inside
knowledge
19
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
20
More Information and Download

Invariant Specification
 http://www.concutest.org/tc/

Annotations with Subtyping
 http://www.cs.rice.edu/~mgricken/research/xajavac/