If you are an unlucky guy like me that believes in durability of Java applications, you may get following fail in your favourite Java / Swing app when driving it with Java 11 (or 9 or 10):
java.lang.ClassCastException: class javax.swing.text.AbstractDocument$DefaultDocumentEventUndoableWrapper cannot be cast to class javax.swing.text.AbstractDocument$DefaultDocumentEvent (javax.swing.text.AbstractDocument$DefaultDocumentEventUndoableWrapper and javax.swing.text.AbstractDocument$DefaultDocumentEvent are in module java.desktop of loader 'bootstrap')
The exception occurs when applying following cast operator (never use casts :-)
UndoableEdit edit = ....;
AbstractDocument.DefaultDocumentEvent documentEvent =
(AbstractDocument.DefaultDocumentEvent) edit;
If you are a lucky guy like me that has access to the source code of your favourite Java application, then here is a fix:
private AbstractDocument.DefaultDocumentEvent toDocumentEvent(UndoableEdit edit) {
if (edit instanceof AbstractDocument.DefaultDocumentEvent) {
return (AbstractDocument.DefaultDocumentEvent) edit;
}
else { // workaround above Java 1.8
try {
Field ddeField = edit.getClass().getDeclaredField("dde");
ddeField.setAccessible(true);
Object dde = ddeField.get(edit);
return (AbstractDocument.DefaultDocumentEvent) dde;
}
catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
This workaround does not depend on Java 11, i.e. it does not import DefaultDocumentEventUndoableWrapper
, thus you can use this for Java 1.8 compilation too. You wouldn't get the dde
from DefaultDocumentEventUndoableWrapper
anyway because it's not exposed.
Reason for DefaultDocumentEventUndoableWrapper
is a rework in Java 9 due to a deadlock situation between UndoManager
and AbstractDocument
.
It was hard to find evidence about this on the web. Swing seems to have been forgotten, although lots of desktop applications use it.
Keep in mind that reflection will be restricted in future Java releases. Frustration is not yet over.
ɔ⃝ Fritz Ritzberger, 2020-02-29