[BLUEJ-539] 'Inheritance' arrow disappear after compilation (triggered with ExtensionClassTargetPainter)
When I was developing a new extension to extend the support of UML in class diagram, I found that a newly created inheritance dependency can disappear after the first time compilation and appear again after the second time compilation.
The fault is related to a statement "bClassTarget.getBClass().getFields();" which can be involved in "ExtensionClassTargetPainter.drawClassTargetForeground(...)"
h2. Bug Triggering Procedure
The fault can be triggered by the following extension with some steps:
CREATE AN INHERITANCE
- Install the following extension (see the codes or attached JAR)
- Create two classes in the project
- Add an 'inheritance' dependency between them
- Click compile button on the left-hand side panel The bug is triggered and the 'inheritance' dependency DISAPPEARS now.
- Right click on the 'child' class and select compile The 'inheritance' dependency appears now.
REMOVE AN INHERITANCE 6. Right click on the 'inheritance' dependency and select remove 7. Click compile button on the left-hand side panel The bug is triggered again. The 'inheritance' dependency, which should be removed, APPEARS now. 8. Right click on the 'child' class and select compile The 'inheritance' dependency disappears now.
Here is the complete source codes of the bug-triggering extension: {noformat} public class SimpleExtension extends Extension implements ExtensionClassTargetPainter {
public void startup (BlueJ bluej) {
bluej.setClassTargetPainter(this);
}
public String getName () { return ("ExtensionClassTargetPainter Bug"); }
@Override
public void drawClassTargetBackground(BClassTarget bClassTarget,
Graphics2D graphics, int width, int height) {}
@Override
public void drawClassTargetForeground(BClassTarget bClassTarget,
Graphics2D graphics, int width, int height) {
try {
// Trigger the bug
bClassTarget.getBClass().getFields();
} catch (ProjectNotOpenException | ClassNotFoundException
| PackageNotFoundException e) {
}
}
@Override
public boolean isCompatible() { return true; }
@Override
public String getVersion() { return "1.0"; }
}
{noformat}
h2. Observation (workaround)
Renew the ClassLoader after ClassTarget compilation can resolve this problem. However, I'm not sure if there is any side-effect.
Here is the code. I added 'getPackage().getProject().removeClassLoader();' before Package object invoking 'getProject().getClassLoader()' in 'loadClass(...)' method. And then the problem is solved. {noformat} public void endCompile() { getPackage().getProject().removeClassLoader(); // the added code Class<?> cl = getPackage().loadClass(getQualifiedName());
determineRole(cl);
analyseDependencies(cl);
}
{noformat}
I guess that the ClassLoader, which is removed before compilation and should only be reloaded after compilation, is reloaded before the completion of the compilation. And that unexpected reloading action may be caused by the extension which indirectly invokes 'Project.getClassLoader()' in the interface 'ExtensionClassTargetPainter.drawClassTargetForeground(...)' and breaks the assumed reloading sequence. As a result, the mechanism which reflects source code into class diagram applies the outdated class information.
h2. Environment BlueJ run started: Fri Nov 28 12:47:56 CST 2014
BlueJ version 3.1.4
Java version 1.8.0_20
Virtual machine: Java HotSpot(TM) Client VM 25.20-b23 (Oracle Corporation)
Running on: Windows 7 6.1 (x86)
Java Home: C:\Program Files (x86)\BlueJ-314\jdk\jre
Issue metadata
- Issue type: Bug
- Priority: Medium