This document describes Groovy-Eclipse's DSL descriptors. DSL descriptors (or DSLDs) are groovy files that describe domain-specific extensions to Groovy-Eclipse's inferencing engine and content assist. They allow end-users to script extensibility to Groovy-Eclipse's editing support. This document is up to date for Groovy-Eclipse 2.5.2.
- The Problem
- New Features in Groovy-Eclipse 2.5.2
logexpressionssupportsVersionandassertVersiondelegatesTochanges- Use
contributeinstead ofaccept namedParamsandoptionalParams- New pointcuts
isDeprecated- The infrastructure
- An Overview
- A deep dive
- Pointcuts
- Semantic pointcuts
- Filtering pointcuts
- Lexical pointcuts
- Structural pointcuts
- Combinatorial pointcuts
- Binding pointcuts
- User-defined pointcuts
- Other pointcuts
- Assigning pointcuts to variables
- Contribution Blocks
- Binding
- SupportsVersion and AssertVersion
- Register pointcut
- Wormhole
- Some larger examples
The Problem
The Groovy language is an excellent platform for the easy creation of domain specific languages (DSLs). However, these DSLs are not directly supported by the Groovy editor. When DSLs are used heavily, standard IDE features like content assist, search, hovers, and navigation lose their value. For a while now, it has been possible to write an Eclipse plugin to extend Groovy-Eclipse, which requires specific knowledge of the Eclipse APIs. This is no longer necessary. Creating a DSL descriptor for a DSL is a way to make DSLs become first class citizens of Groovy-Eclipse.
As an example, Joachim Baumann describes how to implement a simple DSL for working with distances . Using this DSL, you can write things like this to calculate the total distance travelled:
This is a simple and expressive DSL, but when you type this into a Groovy Editor in Groovy-Eclipse:

You see underlines and no hovers. Using a DSLD, it is possible teach the editor some of the semantics behind these custom DSLs. It is also possible to provide documentation hovers:

This document will describe how to extend Groovy-Eclipse through DSLDs.
New Features in Groovy-Eclipse 2.5.2
In Groovy-Eclipse 2.5.2, we have introduced quite a few new features. A brief description of these new features are in this section, and they are described in more detail below, mixed in with the rest of the documentation
log expressions
For debugging and logging inside of DSLDs, there is now the log method. Like println, the log method takes a (g)string. Instead of printing to sysout, it prints the string to the Groovy console if it is open. log is a no-op method if the console is closed.
supportsVersion and assertVersion
Previously, supportsVersion prevented the script from running if the version test had failed. Now, it returns a boolean and is therefore suitable for use inside of if statements so that different functionality can be run depending on the current version. assertVersion now behaves the way that supportsVersion used to. It will prevent the script from being applied.
delegatesTo changes
The delegatesTo operation has become more flexible. It now accepts a set of named arguments, including type, asCategpry, useNamed, except, and isDeprecated.
Here is an example:
This snippet will add all methods from MyCategory to the current type as category methods. In other words, MyCategory is treated like a category. Only static methods whose first argument type matches the current type will be included in the delegation. And the except clause will exclude all methods named in the list. This is useful for when these particular methods are handle by some other means.
The old style of calling delegatesTo with a single type name is still applicable.
Use contribute instead of accept
The use of accept has been deprecated and is replaced by contribute, with a slightly different syntax. Here are some examples:
New:
Old:
The accept style of connecting a pointcut to a contribution group is still available, but may go away in future versions.
namedParams and optionalParams
A method contribution now recognizes three kinds of parameters: regular, named and optional. Regular and named parameters appear in content assist, and optional does not. Named and optional parameters are inserted with the argument name prefixed.
Here is an example:
Note that this new feature deprecates the useNamedArgs parameter.
New pointcuts
Quite a few new pointcuts have been introduced. Some are fairly restrictive in the locations they can be used.
hasArgument: available inside ofenclosingMethodandenclosingCallto match on declared arguments. Useful to combine with thetype,name, andvaluepointcuts.hasAttribute: available inside ofannotatedByto match on attributes. Useful to combine with thetype,name, andvaluepointcuts.type: available to match on the declared type of method arguments, annotation parameters, field types, and method (return) types.value: available to match on the value of an annotationisThisType: this pointcut supersedes thecurrentTypeIsEnclosingTypepointcut, which is now deprecated.
isDeprecated
It is now possible to mark contributions as deprecated. In the UI, these contributions will be displayed with a line running through them (just like other kinds of deprecated references).
There is a new isDeprecated argument available to method, property, and delegatesTo contributions.
The infrastructure
To create a DSLD file inside of Eclipse, go to File -> New -> Groovy DSL Descriptor.

Choose a location if a suitable one has not been selected by default. In order to get content assist and hover support for your DSLD, it is recommended to choose a location inside of a source folder, but this is not required.
Groovy-Eclipse's DSL support will process all DSLD files that are in the project as well as all DSLD files that are on the project's classpath in a package named DSLD (this could be in a jar file an external class folder, or in coming from another project). Note that each project has its own set of DSLD files and they are not shared unless there is an explicit dependency and DSLD files are placed in the dsld package. In the future, we will have a single location where global scripts can reside, but this is not yet implemented.
To see what scripts are currently available for each project, you can go to Preferences -> Groovy -> DSLD. Here, you can see a list of all projects and their DSLDs:

Each file can be disabled by deselecting it from the tree viewer. Also, the set of DSLD files can be refreshed (i.e., the current set of files are dropped and the entire workspace is searched again for DSLD files) and all scripts can be recompiled from this page using the buttons on the right. In the normal workflow, these last two options should not be necessary to use, but if you are seeing problems with your DSLDs, then you may want to try use them.
For development work on DSLDs themselves, it is strongly recommended that you place them in a source folder. This will give you editing features like hover support and content assist, and additionally, many syntax errors will appear in the Problems view. If you want to consume a DSLD in your project, then it is not necessary to place them in a source folder.
Lastly, when doing DSLD work, it is recommended that you open up both the Groovy Event Trace Console and the Eclipse Error Log. If there are syntax errors or other kinds of problems with your script, they will be printed to the Groovy Event Trace Console. If there are problems with the DSL infrastructure itself, there will be entries in the error log (these exceptions are likely bugs in Groovy-Eclipse and should be reported to the mailing list or in the issue tracker).
| Reminder When doing DSLD work, it is recommended that you place your DSLDs in a source folder. Also, you will benefit by opening up both the Groovy Event Trace console and the Eclipse Error Log view. However, when consuming existing DSLDs, they do not need to be in a source folder. They can be in any folder in the project. Alternatively, DSLDs can live in jars or class folders in the |
An Overview
The DSLD language is an aspect-oriented domain specific language. The main components of a DSLD script are:
pointcuts |
A query that describes a set of Groovy expressions in a program, for example the following is a simple pointcut that "matches" for all expressions whose the type is a subtype of |
contribution blocks |
A code block that describes the extra properties and methods available when a pointcut matches. Contribution blocks are analogous to advice in AspectJ. A pointcut is ignored unless it is associated with a contribution block (and vice versa). Here is a simple contribution block: This block adds a new property called |
To associate a pointcut with a contribution block, you call the contribute method. For example, this adds the cm property to all Numbers:
The contribute method takes a pointcut and a closure. Inside that closure, you can specify a set of methods or properties that should be added to the type of the expression being analyzed.
When this script is copied into a Groovy project, cm will be included in content assist of all Numbers and their subclasses. Also, references to cm on Numbers will not be underlined as we showed in the example above. Finally, hovering over these references will display the doc defined in the contribution block.
Under the hood
The pointcuts and contribution blocks are used by Groovy-Eclipse's inferencing engine. The inferencing engine walks the AST and delegates the calculation of expression types to type lookup objects. The type lookups have some capacity for sharing state. DSLD is implemented as a type lookup.
There are two phases for DSLD files.
- The initial compile and processing: at startup or whenever a DSLD file is added or changed, the file is (re-)compiled and the resulting script is executed. Calls to
contributewill store the pointcut and its associated contribution block in a table per project. - Invocation by the inferencing engine: for each expression in the file, each pointcut stored by the project is evaluated. If any pointcut evaluates to true, then that pointcut's contribution block(s) is evaluated and all contributions are added to the current type being evaluated.
More formally
We previously showed the core of the DSLD language, which we can now describe slightly more formally in terms of a join point model. As defined by Masuhara, et al, a Join Point model requires 3 things:
- A set of reference points that can be referred to; these are the join points.
- A means of identifying (a set of) join points; these are the pointcuts.
- A way to specify semantics at a particular set of join points; such as through advice, intertype declarations, or contribution blocks.
The DSLD language uses a syntactic join point model, where the join points are expression nodes in a Groovy abstract syntax tree (AST). DSLD affects the edit-time semantics of a program by contributing properties and methods to types in the IDE. This is different from most other AOP languages that affect a program's the semantics at runtime or compile time.
The individual components of a join point model are matched to concepts in the DSLD language as follows:
- The join points are expression AST nodes in a Groovy file
- DSLD defines a pointcut language to specify a sub-set of expression node join points
- And Contribution blocks augment the semantics of Groovy-Eclipse's inferencing engine to be enhanced with new type suggestions
A deep dive
In this section, we go into more detail on the DSLD language and document all of its features.
Pointcuts
There are a fixed set of standard pointcuts which can be composed using '&' or '|' and negated using '~'. All pointcuts define their own javadoc and will be displayed when hovered over (but only if the DSLD meta script is available in the current project). Pointcuts are generally self documenting using content assist and hovers inside of the DSLD file, but here we describe the more important ones.
The parts of a pointcut are as follows:
- Arguments: in the DSLD script the text inside of a pointcut's '( )' are the arguments. Most pointcuts take one or zero arguments.
- Evaluation arguments: during evaluation, a pointcut is passed a value to match on. This value is called the evaluation argument. For example,
currentType(annotatedBy(Delegate)),currentTypeis the top-level pointcut and is always passed in the current type as a ClassNode object.annotatedByis passed in what is matched by its surrounding pointcut, in this case it iscurrentType. - Return values: the value returned when a match happens. This is typically, a collection of AST nodes. These return values can be bound to names that are available in a contribution block.
When a match is found, all pointcuts return the objects that are matched in a java.util.Collection object. For consistency, a collection is returned even when a single object is matched.
Semantic pointcuts
These are pointcuts that are directly dependent on the inferencing engine. All semantic pointcuts are top level pointcuts only and expect the current type as a class node as an evaluation argument.
currentType
Matches if the current type matches the pointcut argument. The type erasure is used, so the match will be the same if either List<String> or List<Class> are passed in.
Pointcut Arguments
Expects a string, Class, or ClassNode corresponding to the type to match against. Alternatively, a filtering pointcut can be used.
Evaluation arguments
Always a top-level pointcut.
Return values
The current type as a singleton ClassNode collection.
Example
isThisType
(Deprecated, use isThisType instead)
Matches when the current type is the same as the enclosing type. In other words, the current type is this.
Pointcut Arguments
None
Evaluation arguments
Always a top-level pointcut.
Return values
The current type as a singleton ClassNode collection.
Example
currentTypeIsEnclosingType
(Deprecated, use isThisType instead)
Matches when the current type is the same as the enclosing type.
Pointcut Arguments
None
Evaluation arguments
Always a top-level pointcut.
Return values
The current type as a singleton ClassNode collection.
Example
In the following code, this pointcut will match on this and x(), but not substring:
sourceFolderOfCurrentType
Matches when the source folder that the current type is declared in the source folder of the argument. This pointcut does not match for binary types.
Pointcut Arguments
A string specifying the source folder to match on.
Evaluation arguments
Always a top-level pointcut.
Return values
The source folder as a singleton string.
Example
Matches when the current type is defined in src/main/groovy:
Matches on all source types:
Filtering pointcuts
These are pointcuts that are typically used as arguments to other pointcuts and can further filter a result to refine what exactly matches. They can be used as a top-level pointcut, but in this case they are implicitly passed in the current type.
field/method/property
Matches on a set of fields, methods, or properties.
Pointcut Arguments
A string corresponding to the field/method/property name, or another filtering pointcut to further refine the match.
Evaluation arguments
These pointcuts expect either a ClassNode or a Collection of class members. If passed in a ClassNode, then all of the fields/methods/properties will be extracted to match against.
Return values
Returns a collection of fields/methods/properties that have the characteristics specified by pointcut argument.
Example
Matches if the current type has any fields:
Matches if any method in the current type is named "myMethod". Returns all matched methods as a collection:
Matches if the current type is a sub type of a class that defines a method "myMethod":
Note that currentType is optional and if omitted, then the current type is implicitly passed in. So, the following are identical pointcuts to the previous
subType
Matches if the type passed in as an evaluation argument is a sub type of the pointcut argument.
Pointcut Arguments
A string, Class, or ClassNode corresponding to the type that the current type will be checked against.
Evaluation arguments
A ClassNode, collection of ClassNodes to match against. Alternatively, a MethodNode, FieldNode, PropertyNode, or collection of them can be matched against. In this case, the declaring type of the declarations will be used.
Return values
A collection of super-types that match the conditions described in the pointcut argument
Example
Matches when the current type is a sub type of something annotated by @Delegate:
Matches when the enclosing type is a subtype of TestCase:
isStatic/isPublic/isPrivate/isSynchronized/isStatic/isFinal
Matches when one or more of the evaluation arguments is declared with the given modifier.
Pointcut Arguments
None.
Evaluation arguments
Expecting a collection of AnnotatedNodes.
Return values
A subset of the evaluation arguments that all have the given modifier.
Example
Matches if the current type has any static fields:
annotatedBy
Matches when the evaluation arguments correspond to the pointcut argument.
Pointcut Arguments
A string, Class, or ClassNode corresponding to the annotation to match. Alternatively, another pointcut can be used to further constrain the match.
Evaluation arguments
A collection of AnnotatedNodes.
Return values
A collection of all AnnotationNodes matched inside of the evaluation arguments.
Example
Matches when the current type is annotated by @Deprecated:
Matches when the current type has any field with any annotation
Matches when the current type is annotated by an annotation with the @Retention meta-annotation:
hasAttribute
Matches when an annotation passed in has an attribute with the appropriate name, type, or value.
Pointcut Arguments
A string corresponding to the name of the annotation to match, or a combination of name, type, and value pointcuts to match against.
Evaluation arguments
A collection of AnnotationNodes.
Return values
The value or values of the attribute(s) that are matched as a collection. Values that are constants will be reified so that the constants will be available to the DSLD as primitives and strings.
Example
Matches if a field in the current type is annotated by an annotation with an attribute called value.
Matches if a field in the current type is annotated by an annotation with an attribute called value and this attribute's value is true.
Matches if a field in the current type is annotated by an annotation with an attribute called value and this attribute's type is java.lang.Boolean. Additionally, the value of the attribute is bound to val.
type
Matches on the type of a field, argument, parameter, annotation attribute, or method return type. See hasAttribute and hasArgument for examples.
declaringType
Matches on the declaring type of a field, method, or property. See methodCall and hasArgument for an example.
value
Matches on the value of an argument or annotation attribute. See hasAttribute and hasArgument for examples. If the matched value is bound to a name, then the value is reified. This means that the value can be used inside of the DSLD as a primitive or a string. For example:
In the example above, the bound values can be directly compared to primitives or strings in the DSLD.
name
Matches on the fully qualified name of an element.
Pointcut Arguments
A string corresponding to the name to match
Evaluation arguments
A collection of any objects can be passed in. The pointcut argument will be matched against the name of the AST node if a method, field, property, or class declaration. Else, toString() will be called on the evaluation argument.
Return values
The name or names that were matched as a collection.
Example
Matches if the name of the current type is "p.Bar" and it has a method named "foo":
Lexical pointcuts
These are pointcuts that depend on the lexical structure of the surrounding AST.
enclosingScript/enclosingClass
Matches when the enclosing type is a script/class.
Pointcut Arguments
A string, Class, or ClassNode corresponding to the type name to match on. Alternatively, a pointcut argument can be used.
Evaluation arguments
These pointcuts are top-level only.
Return values
The type that was matched.
Example
Matches when inferring inside of a script:
Matches when inferring inside of a script named "pack.MyScript":
Matches when inferring inside of a class that has a @Singleton annotation
enclosingField/enclosingMethod
Matches when enclosed by a field or method of the given characteristics. A code block is enclosed by a field if it is inside of a field initializer. For example, the print statement is enclosed by the x field:
Pointcut Arguments
A string, Class, or ClassNode corresponding to the type name to match on. Alternatively, a pointcut argument can be used.
Evaluation arguments
These pointcuts are top-level pointcuts only.
Return values
A singleton collection of the enclosing method/field if the current location matches.
Example
Matches when the enclosing method or field has the given annotation:
enclosingCall
Matches on the enclosing method call. The enclosing method call is the method call of which the current expression is an argument. There are multiple enclosing calls if the current expression is nested inside of multiple method calls (e.g., foo(bar(arg))).
Pointcut Arguments
Inner pointcuts are required. The inner pointcuts accepted are: name to match on the method name, type to match on the return type, declaringType to match on the method's declaring type, and hasArgument to match on the method call's arguments.
Evaluation arguments
This pointcut is top-level only.
Return values
The method call expression as a Groovy AST node.
Example
Matches when the enclosing method call is named "myMethod" and the declaring type is Bar and the call has a named argument of either "first" or "second":
hasArgument
Matches on an argument to the enclosing method call or the enclosing method declaration. Note that for method calls, this pointcut is only applicable on named arguments. Also, when this pointcut is used in a method declaration, the value inner pointcut cannot be used.
Pointcut Arguments
If a string is passed as the pointcut argument, then the match is against the name of the parameter. Alternatively, any of name, value, and type can be used as enclosed pointcuts.
Evaluation arguments
This pointcut must be used inside of enclosingCall or enclosingMethod.
Return values
The value of a named argument if matching on a named argument in a method call, otherwise the name of the parameter if matching on a method declaration.
Example
Matches when the enclosing method call is named "myMethod" and the declaring type is Bar and the call has a named argument of first whose type is String. Additionally, binds val to a the value of the named argument.
Matches when the enclosing method declaration is named "myMethod" and the declaring type is Bar and the call has a named argument of first whose type is String. Note that here, the value pointcut is not applicable since there is no value to match on.
enclosingCallName/enclosingCallDeclaringType
Matches when the enclosing method call has the given name or the given type. The enclosing method call is the method call of which the current expression is an argument. For example:
In the code above, bar and baz are enclosed by the someMethod method call. Additionally, all expressions in the closure are enclosed. The reference to inside is enclosed by two method calls: someMethod and otherMethod.
Pointcut Arguments
enclosingCallName takes a string corresponding to the name of the method call. enclosingCallDeclaringType takes a string, Class, ClassNode, or other pointcut to describe the type to match on.
Evaluation arguments
This pointcut is top-level only.
Return values
Returns all enclosing method name/declaring types as an ordered set. The ordering is from the lexically closest call to the furthest. In the example above, the ordering would be otherMethod and then someMethod.
Example
Matches when enclosed by a method call foo declared by com.bar.MyClass:
enclosingClosure
Matches when enclosed by a closure.
Pointcut Arguments
No arguments.
Evaluation arguments
This pointcut is top-level only.
Return values
An ordered collection of ClosureExpressions corresponding to the lexically closest closure to the furthest. For example:
In the previous code snippet, when inferring on the print method call, enclosingClosure would return two closure expressions: first the closure attached to tryThis and then the closure attached to constraints.
Example
Here is a pointcut describing when inside of a SwingBuilder closure:
Structural pointcuts
These are pointcuts that depend on the structure and naming conventions of the file system.
nature
Matches on the Eclipse project nature of the current project. For
Pointcut Arguments
A string corresponding to the desired project nature. Examples are:
- Grails:
com.springsource.sts.grails.core.nature - GWT nature:
com.google.gwt.eclipse.core.gwtNature
Evaluation arguments
This pointcut is top level only.
Return values
Returns the name of the nature as a singleton collection.
Example
Matches domain classes in grails projects:
fileName/fileExtension
Matches on the full file name or on the file extension of the current file being inferred.
Pointcut Arguments
A string corresponding to the file name or extension (excluding the '.') to match.
Evaluation arguments
This pointcut is top level only.
Return values
Returns the name of the file that was matched.
Example
Matches on gradle files:
Matches on MyScript.groovy:
sourceFolderOfCurrentFile
Matches on the source folder of the file currently being inferred. Note that this is different from sourceFolderOfCurrentType that will match on the current type. sourceFolderOfCurrentFile will return the same value for the entire file, whereas sourceFolderOfCurrentType will have a different value depending on the type of the current expression.
Pointcut Arguments
A string corresponding to the source folder to match on.
Evaluation arguments
This pointcut is top level only.
Return values
The matches source folder as a singleton collection.
Example
Matches when in the src folder:
Combinatorial pointcuts
No need to explicitly invoke these pointcuts. They are included here for completeness and are implicitly created when using &, |, and ~ (meaning the and, or, and not pointcuts respectively).
and/or/not
Pointcut Arguments
These are the only pointcuts that can take more than one argument. The arguments must be other pointcuts.
Evaluation arguments
These pointcuts can take any evaluation arguments. They are simply passed on to their contained pointcuts.
Return values
For or and and, a collection of all elements matched by the containing pointcuts. For not, this will return a singleton collection with an Object value if the containing pointcut does not match.
Example
It is generally good to use parens around the pointcut argument of not. Matches when the current type has no fields:
Matches when inside a deprecated class, and there is a field or method in the class named "bar":
| Things to be careful about Due to Groovy's operator precedence rules, parens muse be used around not ('~') or else the ~ will apply to the pointcut name (without the parens), instead of the pointcut expression (with the parens). You should do this: instead of this: |
Binding pointcuts
There is only one binding pointcut, called bind. This pointcut explicitly binds the return value to a name to make it available in a contribution block.
The explicit use of the bind pointcut can be omitted when it is surrounded by another pointcut. There is a bigger discussion of this pointcut below.
bind
Pointcut Arguments
A single pointcut
Evaluation arguments
Any evaluation arguments. They are passed to the contained pointcut.
Return values
Returns the value returned by the contained pointcut.
Example
Binds a collection of deprecated annotations:
Binds to deprecated fields in the current type. In this case, bind is necessary:
User-defined pointcuts
It is possible to register your own pointcuts that will be available in the current DSLD script only. See the registerPointcut section below.
Other pointcuts
The DSLD language is a work in progress. Here are some pointcuts that are not yet implemented, but may be based on the needs of the community: regex, instanceof, superType, enclosingType, enclosingEnum, and others.
| Some subtleties about java.lang.Class references Even though the DSLD script is being edited in the context of your project, the script is actually loaded by Groovy-Eclipse. And so, the runtime classpath of the script corresponds to Groovy-Eclipse's classpath, rather than the classpath of your project. Consequently, you cannot reference class objects for types defined in your project. However, you can reference class objects that are available to Groovy-Eclipse. This might be confusing since the compiler will not show compile errors when types defined in your project are referenced as class objects, but it will show compile errors when Groovy-Eclipse types are referenced. This is because the Groovy-Eclipse compiler works off of the project's classpath. It is not yet aware that DSLD files will be run with a different classpath. More specifically:
|
Assigning pointcuts to variables
Sometimes it is useful to assign pointcuts to variables. For example, here is how we might describe a Grails domain class and a controller class:
Notice how it is possible to use a closure so that pointcut components can be shared and parameterized.
We can use the domainClass pointcut above as a component in a larger pointcut that describes where the Grails constraints DSL is applicable:
Let's break this down a bit:
- The first thing to notice is that the
domainClassreference doesn't require and parens. This is because parens have already been used when the pointcut was first declared. - Next, notice the
enclosingFieldpointcut. This component matches when the enclosing field name isconstraintsand the field is static. - Usually, the
name()pointcut is implicit and optional, but since '&' requires pointcuts on either side, we need to wrap the"constraints"string inside of a poincut. - Next, the expression must be inside of a closure
- The
currentTypeIsEnclosingType()pointcut means that the type of the current expression must be the type of the enclosing class. Thus, references tothiswill match, but references to other types (such asnew String()will not).
Contribution Blocks
Now that we have described the pointcut language, we can delve into what happens in contribution blocks.
You have already been introduced to the following form, which adds a property to the type of the expression matched in the contributing pointcut:
The full form of property is:
A few notes:
nameis the only required argumenttypedefaults tojava.lang.Objectand the argument can be of typejava.lang.String,java.lang.Class, ororg.codehaus.groovy.ast.ClassNode.declaringTypedefaults to the currentType and can accept a String, Class, or ClassNodedocis the javadoc that will show up in hovers and accepts html syntaxprovideris a human readable name for the current DSL and appears in content assist to give hints as to how the given completion proposal was calculated
The following methods are available (for completeness, we include property again):
property |
declares a new property. The full form is like this. Name is the only required field: |
method |
declares a new method. The full form is like this. Name is the only required field: A note on parameter kinds:
|
delegatesTo |
adds all of the public methods in the delegated type to the current type. For example: will add all public methods of list to the current type for content assist, underlining, hovers, and navigation. |
delegatesTo |
(alternative form with named arguments) adds all of the public methods in the delegated type to the current type. There is a possibility to parameterize using named arguments:
|
For example:
delegatesToUseNamedArgs |
(deprecated, |
And the following properties
provider |
sets the provider for the entire contribution block. Eg, will ensure that "My Groovy DSL" appears in content assist next to all contributions added by this block. |
currentNode |
Accesses the current Groovy AST node (an expression node) |
enclosingNode |
Accesses the Groovy AST node (an expression node) that encloses the currentNode. This is the parent node of the currentNode in the AST. |
wormhole |
A means to pass state between contribution blocks. An example is given below. |
This list of available properties and methods will likely change as we continue to work on DSLD.
Binding
Sometimes, the items matched in the contributing pointcut are required in the contribution block. You can use named arguments for pointcuts to bind a name to the object that the pointcut matched. This binding is available inside of the contribution block.
For example, here is the DSL for the @Delegate AST transform:
The fields argument is bound to all of the fields in the current type with the Delegate annotation. If there is only one field, then the result is a single Groovy FieldNode, if there are multiple matches, then fields is bound to an object of type List<FieldNode>. As a general rule, bound variables are never null inside of a contribution block. If they were null, then that would imply that a match had not occurred.
Sometimes, it might be necessary to bind on the outermost pointcut component. In this case, you can use the bind() pointcut. For example, the following is the syntax for the @Singleton AST transform
SupportsVersion and AssertVersion
To ensure that a script only runs when particular features are installed, you can use the assertVersion top-level method. This method call should go at the top of a script to prevent any other part of the script from executing if the script is not supported.
The syntax looks like this:
This means that the script is only active if all components are active with a version greater than or equal to the ones supplied. If anything does not match, then the entire script is disabled.
Currently, only 'groovy', 'groovyEclipse', and 'grailsTooling' are supported, but we may add other component kinds later. A real example is here:
Alternatively, you can use the supportsVersion top-level method for a similar purpose. This method returns a boolean (true iff the current version matches the version requirements in the method arguments). This allows you to execute different contribution blocks depending on version constraints. For example:
Register pointcut
It is possible to create and register a locally defined pointcut. You can do so by invoking the registerPointcut closure at the top level of a DSLD file. registerPointcut takes two arguments: the name of the pointcut to register and a closure that serves as the test to see whether or not the pointcut matches.
For example, the following defines twoArgs, a pointcut that matches when the evaluation argument is a MethodNode with two arguments with the proper names:
This pointcut can be used as follows:
This will match on the following code:
Notice that when there is a match, the return value is a collection of all of the matched parameter types. This return value can be bound to a name and made available in a contribution block, like so:
Now, the generated method will have the same parameter names and types as the method declaration that encloses it. We need to iterate through paramNameTypeCollection because all named bindings are collections. Note that the default groovy method collectEntries is only available in Groovy 1.8 or greater.
There is more that you can do with registerPointcut. The pointcut closure recognizes all named arguments that are passed in to it. For example:
This matches the following code:
Wormhole
It is possible to pass state between contribution blocks using the wormhole. More about this later...
| The dark side of DSLDs Since DSLDs are running in the same process as your current Eclipse is, there is some danger. Unless you really know what you are doing, some things that you should not try:
I think you get the point. We give you the power and you must decide what to do with it. Just like many parts of the Groovy eco-system, the DSLD language gives you all the rope you need to hang yourself. In the future, it is likely that DSLDs will be executed in the context of a security manager to prevent these kinds of problems. |
Some larger examples
Some larger examples can be found at DSLD examples.