I had to make a few changes, but at least for subclasses of java.lang.Component
, there’s now an option to allow any thread before it has been realized, but only the event thread after that.
I replaced the eventThread
member of the @ThreadDesc
and @OnlyRunBy
annotations to an enumeration OnlyRunBy.EVENT\_THREAD
with the possible values NO
, ONLY_AFTER\_REALIZED
and ONLY
, in increasingly strict order. If two of them are merged together, the strictest one will be picked, and it is a subtyping error to go from weaker to stronger, e.g. from ONLY\_AFTER\_REALIZED
to ONLY
, which corresponds exactly to a previous change from false
to true
.
Lets look at an example program:
public class ThreadCheckSample2 {
public void run() {
JFrame frame = new JFrame("ThreadCheckSample2") {
@OnlyRunBy(@ThreadDesc(eventThread=
OnlyRunBy.EVENT\_THREAD.ONLY\_AFTER\_REALIZED))
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (WindowEvent.WINDOW_CLOSING == e.getID()) {
System.exit(0);
}
}
};
JPanel panel = new JPanel();
JButton button = new JButton("Button") {
@OnlyRunBy(@ThreadDesc(eventThread=
OnlyRunBy.EVENT\_THREAD.ONLY\_AFTER\_REALIZED))
public void addActionListener(ActionListener l) {
super.addActionListener(l);
}
};
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleButton();
}
});
panel.add(button);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
handleButton();
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("2nd handler");
}
});
}
@OnlyRunBy(@ThreadDesc(eventThread=OnlyRunBy.EVENT\_THREAD.ONLY))
private void handleButton() {
System.out.println("Button was pushed");
}
public static void main(String[] args) {
(new ThreadCheckSample2()).run();
}
}
This generates the thread checker log:
---------------------------------------- Log opened 2006-08-10, 15:09:23 CST (GMT-5) Thread Violation: OnlyRunBy Current thread 'main', id 1, group 'main' did not match the event thread at sample.threadCheck.ThreadCheckSample2.handleButton (ThreadCheckSample2.java:40) at sample.threadCheck.ThreadCheckSample2.run (ThreadCheckSample2.java:30) at sample.threadCheck.ThreadCheckSample2.main (ThreadCheckSample2.java:44) Thread Violation: OnlyRunBy Current thread 'main', id 1, group 'main' did not match the event thread at sample.threadCheck.ThreadCheckSample2$2.addActionListener (ThreadCheckSample2.java:18) at sample.threadCheck.ThreadCheckSample2.run (ThreadCheckSample2.java:31) at sample.threadCheck.ThreadCheckSample2.main (ThreadCheckSample2.java:44)
The really interesting thing here is that I have annotated the addActionListener
method of the button to allow only the event thread after the button has been realized. The first call to addActionListener
in line 21 does not generate a violation, but the second call in line 31 does, because the call to JFrame.pack
has realized the button.
This is pretty sweet already.
Update
Because determining if a component has been realized requires… a component, I have restricted the ONLY\_AFTER\_REALIZED
to non-static methods in subclasses of java.awt.Component
. But what should I do with static methods if the ONLY\_AFTER\_REALIZED
annotation is on class-level? Right now I throw an exception, but I don’t think that’s right. But do I want to tighten the rules (ONLY
) or relax them (NO
)? Right now, I’m thinking I’ll print out a warning but then relax the annotation to NO
.
I ran the DrJava unit tests again, and because I fixed a bug, this time I got a lot of reports of the same problem. I may want to think about removing duplicates and the ability to suppress certain reports.