On some project, I generate code from EMF models. And I’ve been faced to the following issue: overriding a template for classes in different EMF meta-models which are in separated Eclipse plug-ins.
It was similar to the following example: the template Foo
which needs to be override for each class in that class hierarchy (colors correspond to different Eclipse plug-ins)
First try: multiple dispatch
With Xtend, a classical approach is to use the multiple dispatch feature:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
It works fine but all template specializations have to be declared in the same Xtend class. And it might not be possible. For instance, in the example, we would have created an additional Eclipse plug-in containing all templates.
Second try: Eclipse extension point / extensions
As I want to group template specializations per Eclipse plug-in, I looked at the extension point / extensions mechanism.
For the example, I would have declared:
- an extension point for the root template declared in plug-in
a - an extension for classes from package
bdeclared in plug-inb - an extension for classes from package
cdeclared in plug-inc
It would work but it is quite tedious: tons of XML and lots of plumbing code; not manageable if you have several templates to override.
Final try: a combination of lambda expression and multiple dispatch
Since the previous attempts have some drawbacks, I’ve defined the following technique which combines lambda expressions and multiple dispatch with the help of two small classes.
First helper class: Transformer
First, I have declare the class Transformer that transforms an object instance into another one:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
It contains the following members:
transfomers: a map of lambda expressions to which aTransformerinstance delegates the transformationfallback: a fallback lambda expression if no transformer is found;doFallbackcould also be override insteadregisteran helper method used to register a transformer lambda expression; the first parameter of that method corresponds to the root class that the lambda expression is able to transformtransform: the method that does the transformation
Second helper class: Template
The second helper class is the class Template which specializes the class Transformer by trasforming into a CharSequence.
1 2 3 4 5 6 7 8 9 | |
Some conventions and that’s it
Finally, when I need a template, I
- declare a singleton class which extends
Template - declare dispatch
doFallbackmethods for each class in the root package - declare an helper method with this convention
<template-name>_<root-class-name>
For instance, the template Foo would be:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
Then, if I need to override the default templates in another Eclipse plug-in, I
- declare a class with the same name as the helper class in the root template
- declare a
registermethod that registers to the root template - declare dispatch methods for each template to override; these methods must have the same signature than the
transformmethod
For instance, the extension of Foo in Eclipse plug-in b would be:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
Last words
With that technique, overriding templates is quite easy.
The only constraint is to respect the signature of the lambda expression required by the Transformer class.
Furthermore, you are free to organize your template extensions the way you want.