Wednesday, February 4, 2009

JDT won't do that!

AspectJ is a language that is very close to Java, but it isn't Java. One might expect that since AspectJ is an extension of Java, Eclipse tooling for AspectJ would just be an extension of the Java Development Tools. But it's not that easy. This post describes the problems that we have faced when integrating AspectJ tooling into Eclipse, and motivates a solution that I will elaborate on in future posts.

JDT has not been engineered to be extensible, and rightly so. It is a set of tools that are finely tuned towards making the Java development experience as smooth and convenient as possible. Focusing on extensibility would be to the detriment of the JDT users who program in Java only.

However, this makes life difficult for us tool developers. Users expect high quality tooling for Java-like languages (i.e., languages that run on the JVM) because that is the bar set by JDT. Furthermore, they want tooling that integrates seamlessly with Java tooling. But, JDT won't do that! So, how can we provide good programmer experience in AJDT?

We want to make editing AspectJ look and feel as much like editing Java where it makes sense, and at the same time provide additional functionality so that the user is aware of AspectJ-specific issues. Up until AJDT 1.6.2, there have been limited options to integrate with JDT.

One example of successful integration is the AspectJEditor, which behaves mostly like JDT's CompilationUnitEditor, providing eager error detection, syntax highlighting, content assist, some refactoring support, etc.





The AspectJEditor should be a subclass of the CompilationUnitEditor, But the CompilationUnitEditor is not public API and AJDT really shouldn't be touching it. Or, at least, the responsibility is on us to maintain compatibility in future versions. In addition to using private APIs, the AspectJEditor uses some reflection to access private fields of its super class and copies some code, where reflection isn't practical. Through this combination of techniques, we have been able to largely implement JDT's behavior in AJDT. But, there is some functionality that we want AJDT to provide, but is not possible using private APIs, reflection, or code copying.

Let's take a look at the Open Type Dialog.




We would really like to see our aspect types in the standard Java Open Type Dialog. But this is unfortunately not possible. There is no API (public or private) that we can use to do this. Even the use of reflection or code copying will not help. What we really need is to gain access to JDT's Java indexer and somehow convince it to index aspect files.

This is a big problem, and one that we have run into many times during our development of AJDT. JDT is not engineered to be compatible with Java-like languages. But, tools for languages such as Groovy, Scala, and JRuby are gaining in popularity and require the same kind of JDT integration that is just not available. There is a long standing JDT bug to address this, but it does not seem like it will be fixed any time soon.

However, there is a solution! Since AJDT 1.6.2, we have been able to provide deep integration with JDT by using AspectJ on JDT itself. We are using Equinox Aspects to weave into the platform and expose functionality in a structured way through the use of Eclipse extension points. In future posts, I will describe how we have designed our JDT weaving service to expose otherwise inaccessible functionality in JDT and how this weaving service is generic enough to be used by tool developers for other languages.

You can also hear more about this at my EclipseCon talk: Aspects Everywhere: Using Equinox Aspects to Provide Language Developers with Deep Eclipse Integration.

6 comments:

  1. Sounds cool indeed!

    ReplyDelete
  2. I took a look at your previous posts, the presentation and the example project you have. The example project works, but it is too simple to serve as a starting point for anything serious. For example the compilation unit provider just creates an empty compilation unit. Also, the source provider is very careful to maintain the offsets of the class and member names which is not possible for a more complex language. Do you have any more information or a more elaborate example that could help me in using weaving. Without more info I feel like giving up on the whole JDT weaving idea!

    ReplyDelete
  3. Take a look at the source code for AJDT, or the Scala Eclipse plugin.

    It's true that the example I used was simplistic. In addition to supplying your own CompilationUnit, you will need to supply your own editor. It should be a subclass of CompilationUnitEditor. You will need to provide it with a subclass of JavaSourceViewerConfiguration. You will have to override methods such as getCodeScanner() and getReconciler().

    To start off with, I'd recommend replacing each method of the configuration class with a no-op (ie, returns null, an empty array, or an object that does nothing). Then, you can fill things in (either borrow from JDT, sub-class your own, or start from scratch).

    This is just a very general way to get started.

    Please post the the ajdt-dev mailing list if you have any more questions:
    https://dev.eclipse.org/mailman/listinfo/ajdt-dev

    ReplyDelete
  4. This approach only seems to work for languages which can be transformed in to valid Java source via simple string transformations. The Scala plugin appears to define a whole slew of its own aspects to hack around this by intercepting the Java builder and forcing it to ignore Scala files. Are you aware of any projects besides AJDT which use JDT weaving as-is without defining their own aspects on top of it?

    ReplyDelete
  5. At this point, AJDT and the Scala plugin are the only two tool suites that use JDT weaving that I am aware of.

    The Scala plugin adds extra aspects for building because its own builder cannot handle java files. The AJDT builder, however, does. Scala's extra aspects for building code has nothing to do with Scala code not being able to be easily translated into Java code, but rather because of the limitations with the Scala builder.

    There are other aspects that it defines to deal with indexing and classfile processing. Neither of which are issues for AJDT.

    JDT Weaving was created to solve a problem with AJDT and try to be as general purpose in solving those problems as possible. It has provided a good starting point for the Scala plugin. Some of the aspects provided by JDT weaving have been useful (eg- the one for compilation unit providers and the other for image providers), whereas others are less so (eg- the one for source provider).

    The Scala plugin also needs to solve problems that AJDT does not (eg- indexing, building java files, etc), and so provides its own aspects for it.

    So, I am not sure that I agree with you that JDT only works for languages that can be transformed into valid Java. But rather, JDT Weaving is a good starting point for those kinds of languages that cannot be transformed.

    ReplyDelete