Handly — Support for legacy models
by Vladimir Piskarev
You might ask… Handly looks interesting, but can it be of any use if I already have a (handle-based) code model with a well-established API? (Or, perhaps, you’d like to use Handly in a greenfield, but are a bit uncomfortable about the leakage of Handly API to your model’s clients.)
If this sort of questions makes you delay considering Handly adoption, perhaps you should wait no longer. Handly can support legacy models while still providing the benefits of a uniform handle-based API. Now when the dust settled after the Handly 0.3 release, let me show you how.
Although Handly imposes almost no restrictions on the model shape or on the languages modeled, it still requires that model elements implement some of the provided interfaces such as
ISourceFile, which might be enough to break API compatibility with an existing model. However, a handle-based design makes it straightforward to implement lightweight adapter elements to the existing model API and expose this fully backwards compatible adapter model to clients. As long as those adapter elements can adapt themselves to underlying Handly-based model elements, they can be fully supported by the generic IDE infrastructure built on top of the uniform Handly API. The adapter model does incur some additional overhead in both time and space, but the approach is architecturally sound and in many cases the overhead should be manageable.
To make it more concrete and as a proof of concept, I have implemented a subset of the JDT Java model API atop the example model for Java and pushed it to the javamodel.jdt branch in the project’s repository. (I’m hesitant about merging it to
master as I think it can unnecessarily complicate the Java model example. However, I’m open to reconsidering this decision based on the community feedback.)
Once the adapter model had been in place, it was very easy to use existing JDT UI classes to build an almost fully functional Java Navigator. I said almost because, since the adapter model was based on the deliberately contrived example model, many of its methods just throw
UnsupportedOperationException. However, navigation does work, and you can see all the usual actions in the context menu (although it is not recommended to actually use those actions since, as mentioned above, the underlying adapter model is incomplete and not all operations are supported; you can still use the JDT’s Package Explorer for performing the actions). I must say that implementing such an adapter to the JDT Java model API was an exciting (if a bit short) experience!
In the end, it’s all about loose coupling. Your model API may depend on Handly, which can be convenient in many cases but is not strictly required: instead, you can treat your Handly-based model as an implementation detail, exposing only the adapter model to clients. Generic IDE components (such as those already provided by Handly) may depend on the uniform Handly API, but can know nothing about specifics of a model. Finally, there may be (in theory, at least) alternative implementations of the Handly API in addition to the one provided by the project itself.
Support for legacy models as well as overall API quality are going to be important themes on our way to the Handly 0.4 release. As always, feedback is most welcome and can be directed to the project’s forum or right to the developer mailing list.