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
b
declared in plug-inb
- an extension for classes from package
c
declared 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 aTransformer
instance delegates the transformationfallback
: a fallback lambda expression if no transformer is found;doFallback
could also be override insteadregister
an 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
doFallback
methods 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
register
method that registers to the root template - declare dispatch methods for each template to override; these methods must have the same signature than the
transform
method
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.