Monday 9 July 2012

Realignment for JD-Eclipse

Update: I have posted details about a new release of my plugin here.

In Eclipse, when debugging a Java program or simply trying to explore some code, it is very frustrating when you hit a class without source.



There are a small number of open source Java decompilers which promise to improve this by generating some source code based on the class file. The best one which I have tried is called JD-Eclipse. However, JD-Eclipse has a couple of key limitations:


  1. The generated source code doesn’t line up with the debug line numbers because the generated code can’t include the original comments.
  2. If you choose to associate the “*.class” file type within Eclipse with the “Class File Editor” then you always get decompiled output even if you have real source attached.
I recently came across a project Realignment for JD-Eclipse which partially fixes (1) by properly lining up methods and lines within methods. I have forked this project and made some further enhancements to fix both (1) and (2). In particular, I have added the following:


  • Enhance the re-alignment process to handle enums and fields.
  • Automatically attempt to setup the “correct” file associations.
    • On first start:
      • On Eclipse Juno there is a new “class without source” file type, register to decompile this and restore the built in Class Viewer for classes with source so that attached source can be viewed.
      • On Eclipse Indigo and below register to handle the “class” file type. This can be undone in Window -> Preferences -> General -> Editors -> File Associations.
    • On every other start:
      • If the default “JD Eclipse” editor is registered to handle “class” or “class without source” update the mapping to use the realignment enabled JD Eclipse editor.
  • Add a context menu for choosing which editor to open a class with (see picture below).
  • Add entry to this context menu to allow the attached source to be changed.


If you are interested in trying this out you can download both JD-Eclipse along with my fork of Realignment for JD-Eclipse from my update site: http://mchr3k-eclipse.appspot.com/

Obligatory warning: This code has had very little testing so you please do report any weird behavior to me or raise an issue (https://github.com/mchr3k/jdeclipse-realign/issues).

Implementation Wrinkle

One of the trickiest parts of this project so far has been trying to make it possible to switch quickly between the built in Class Viewer (to view attached source) and the JD Eclipse Class Viewer (to view decompiled source). It turns out that there are two mechanisms which make this tricky when you open a Class in the JD Eclipse Class Viewer.

Firstly the IClassFile is associated with the decompiled source in the BufferManager. With this mapping in place this means that even the built in Class Viewer will display decompiled source. However, the BufferManager is a 60 element LRU cache so if you open enough other files the decompiled source will drop out of the cache.

Secondly the SourceMapper which is used to generate the decompiled source is registered with the IClassFile's parent PackageFragmentRoot. This means that even when the decompiled source is not cached in the BufferManager the built in Class Viewer will still get hold of the cached SourceMapper and generate and then display decompiled source!

To solve both of these issues I added some code to the dispose() method of the Realigned JD Eclipse Class Viewer to both remove the entry from the BufferManager and remove the SourceMapper.

Why does this matter? One of the frustrations with using a decompiler is that once you have one installed you can only view decompiled source even if you have real source attached. I added an "Open Class With" menu to allow a class file to be quickly opened in the regular class viewer to view attached source.

Eclipse Juno makes this much better as it introduces a "class without source" file type so that you can associate your decompiler with only those classes for which you don't have real source.