Skip to content
Skip to breadcrumbs
Skip to header menu
Skip to action menu
Skip to quick search
Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Sign Up
Dashboard
Groovy
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<p>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.</p><p><img class="editor-inline-macro" src="/plugins/servlet/confluence/placeholder/macro?definition=e3RvY30&locale=en_GB&version=2" data-macro-name="toc"></p><h3>The Problem</h3><p>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.</p><p>As an example, Joachim Baumann describes how to implement <a href="http://joesgroovyblog.blogspot.com/2007/09/and-miles-to-go-before-i-sleep.html">a simple DSL for working with distances </a>. Using this DSL, you can write things like this to calculate the total distance travelled:</p><table class="wysiwyg-macro" data-macro-name="code" data-macro-parameters="language=groovy" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGU6bGFuZ3VhZ2U9Z3Jvb3Z5fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>3.m + 2.yd + 2.mi - 1.km </pre></td></tr></table><p>This is a simple and expressive DSL, but when you type this into a Groovy Editor in Groovy-Eclipse:</p><p><img class="confluence-embedded-image confluence-content-image-border image-center" src="/download/attachments/231082353/underlines.png?version=1&modificationDate=1371653507735" data-image-src="/download/attachments/231082353/underlines.png?version=1&modificationDate=1371653507735" data-linked-resource-id="231377124" data-linked-resource-type="attachment" data-linked-resource-default-alias="underlines.png" data-base-url="http://docs.codehaus.org" data-linked-resource-container-id="231082353" title="null > underlines.png" data-element-title="underlines.png"></p><p>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:</p><p><img class="confluence-embedded-image confluence-content-image-border image-center" src="/download/attachments/231082353/no_underline_with_hover.png?version=1&modificationDate=1371653507734" data-image-src="/download/attachments/231082353/no_underline_with_hover.png?version=1&modificationDate=1371653507734" data-linked-resource-id="231377123" data-linked-resource-type="attachment" data-linked-resource-default-alias="no_underline_with_hover.png" data-base-url="http://docs.codehaus.org" data-linked-resource-container-id="231082353" title="null > no_underline_with_hover.png" data-element-title="no_underline_with_hover.png"></p><p>This document will describe how to extend Groovy-Eclipse through DSLDs.</p><h3>New Features in Groovy-Eclipse 2.5.2</h3><p>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</p><h5><code>log</code> expressions</h5><p>For debugging and logging inside of DSLDs, there is now the <code>log</code> method. Like <code>println</code>, the <code>log</code> method takes a (g)string. Instead of printing to sysout, it prints the string to the Groovy console if it is open. <code>log</code> is a no-op method if the console is closed.</p><h5><code>supportsVersion</code> and <code>assertVersion</code></h5><p>Previously, <code>supportsVersion</code> 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. <code>assertVersion</code> now behaves the way that <code>supportsVersion</code> used to. It will prevent the script from being applied.</p><h5><code>delegatesTo</code> changes</h5><p>The <code>delegatesTo</code> operation has become more flexible. It now accepts a set of named arguments, including <code>type</code>, <code>asCategpry</code>, <code>useNamed</code>, <code>except</code>, and <code>isDeprecated</code>.</p><p>Here is an example:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>delegatesTo type:"com.foo.MyCategory", asCategory:true, except:["ignoredMethodA", "ignoredMethodB"] </pre></td></tr></table><p>This snippet will add all methods from <code>MyCategory</code> to the current type as <em>category</em> methods. In other words, <code>MyCategory</code> is treated like a category. Only static methods whose first argument type matches the current type will be included in the delegation. And the <code>except</code> clause will exclude all methods named in the list. This is useful for when these particular methods are handle by some other means.</p><p>The old style of calling <code>delegatesTo</code> with a single type name is still applicable.</p><h5>Use <code>contribute</code> instead of <code>accept</code></h5><p>The use of <code>accept</code> has been deprecated and is replaced by <code>contribute</code>, with a slightly different syntax. Here are some examples:</p><p>New:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>contribute(currentType("com.foo.Sumthin")) { // and contributions here. } </pre></td></tr></table><p>Old:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>currentType("com.foo.Sumthin").accept { // and contributions here. } </pre></td></tr></table><p>The <code>accept</code> style of connecting a pointcut to a contribution group is still available, but may go away in future versions.</p><h5><code>namedParams</code> and <code>optionalParams</code></h5><p>A <code>method</code> 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.</p><p>Here is an example:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>method name:"meth", params: [first:String, second: "foo.MyObj", namedParams:[third:Integer, fourth:Long], optionalParams:[fifth:"foo.Optional", sixth:"foo.OtherOptional"] </pre></td></tr></table><p>Note that this new feature deprecates the <code>useNamedArgs</code> parameter.</p><h5>New pointcuts</h5><p>Quite a few new pointcuts have been introduced. Some are fairly restrictive in the locations they can be used.</p><ul><li><strong><code>hasArgument</code></strong> : available inside of <code>enclosingMethod</code> and <code>enclosingCall</code> to match on declared arguments. Useful to combine with the <code>type</code>, <code>name</code>, and <code>value</code> pointcuts.</li><li><strong><code>hasAttribute</code></strong> : available inside of <code>annotatedBy</code> to match on attributes. Useful to combine with the <code>type</code>, <code>name</code>, and <code>value</code> pointcuts.</li><li><strong><code>type</code></strong> : available to match on the declared type of method arguments, annotation parameters, field types, and method (return) types.</li><li><strong><code>value</code></strong> : available to match on the value of an annotation</li><li><strong><code>isThisType</code></strong> : this pointcut supersedes the <code>currentTypeIsEnclosingType</code> pointcut, which is now deprecated.</li></ul><h5><code>isDeprecated</code></h5><p>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).</p><p>There is a new <code>isDeprecated</code> argument available to method, property, and delegatesTo contributions.</p><h3>The infrastructure</h3><p>To create a DSLD file inside of Eclipse, go to <em>File -> New -> Groovy DSL Descriptor</em>.</p><p><img class="confluence-embedded-image confluence-content-image-border image-center" src="/download/attachments/231082353/DSLD_wizard.png?version=1&modificationDate=1371653507733" data-image-src="/download/attachments/231082353/DSLD_wizard.png?version=1&modificationDate=1371653507733" data-linked-resource-id="231377122" data-linked-resource-type="attachment" data-linked-resource-default-alias="DSLD_wizard.png" data-base-url="http://docs.codehaus.org" data-linked-resource-container-id="231082353" title="null > DSLD_wizard.png" data-element-title="DSLD_wizard.png"></p><p>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.</p><p>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 <code>dsld</code> package. In the future, we will have a single location where global scripts can reside, but this is not yet implemented.</p><p>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:</p><p><img class="confluence-embedded-image confluence-content-image-border image-center" src="/download/attachments/231082353/preferences_page.png?version=1&modificationDate=1371653507733" data-image-src="/download/attachments/231082353/preferences_page.png?version=1&modificationDate=1371653507733" data-linked-resource-id="231377121" data-linked-resource-type="attachment" data-linked-resource-default-alias="preferences_page.png" data-base-url="http://docs.codehaus.org" data-linked-resource-container-id="231082353" title="null > preferences_page.png" data-element-title="preferences_page.png"></p><p>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.</p><p>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.</p><p>Lastly, when doing DSLD work, it is recommended that you open up both the <a href="http://groovy.codehaus.org/Groovy-Eclipse+2.1.1+New+and+Noteworthy#Groovy-Eclipse2.1.1NewandNoteworthy-GroovyEventConsole">Groovy Event Trace Console</a> 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).</p><table class="wysiwyg-macro" data-macro-name="tip" data-macro-parameters="title=Reminder" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e3RpcDp0aXRsZT1SZW1pbmRlcn0&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="RICH_TEXT"><tr><td class="wysiwyg-macro-body"><p>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 <strong><a href="http://groovy.codehaus.org/Groovy-Eclipse+2.1.1+New+and+Noteworthy#Groovy-Eclipse2.1.1NewandNoteworthy-GroovyEventConsole">Groovy Event Trace console</a></strong> and the <strong>Eclipse Error Log view</strong>.</p><p>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 <code>/dsld</code> package. If this jar or class folder is on the classpath project, then these DSLDs will be used by the project (but only if they are in the <code>/dsld</code> package.</p></td></tr></table><h3>An Overview</h3><p>The DSLD language is an <a href="http://www.jroller.com/colyer/entry/the_ted_neward_challenge_aop">aspect-oriented</a> <a href="http://www.martinfowler.com/bliki/DomainSpecificLanguage.html">domain specific language</a>. The main components of a DSLD script are:</p><table class="confluenceTable"><tbody><tr><td class="confluenceTd"><p><strong>pointcuts</strong></p></td><td class="confluenceTd"><p>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 <code>Number</code>.</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>currentType(subType(Number)) </pre></td></tr></table></td></tr><tr><td class="confluenceTd"><p><strong>contribution blocks</strong></p></td><td class="confluenceTd"><p>A code block that describes the extra properties and methods available when a pointcut matches. Contribution blocks are analogous to <a href="http://www.eclipse.org/aspectj/doc/released/progguide/semantics-advice.html">advice in AspectJ</a>. A pointcut is ignored unless it is associated with a contribution block (and vice versa). Here is a simple contribution block:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>{ property name:"cm", type:"Distance", doc: """A <code>cm</code> from <a href=\"http://joesgroovyblog.blogspot.com/2007/09/and-miles-to-go-before-i-sleep.html\"> http://joesgroovyblog.blogspot.com/2007/09/and-miles-to-go-before-i-sleep.html</a>""" } </pre></td></tr></table><p>This block adds a new property called <code>cm</code> with a type of <code>Distance</code>. The javadoc is specified in the GString and can use standard HTML tags. However, without being associated with a pointcut, this contribution block will be used and will not add the method to any type.</p></td></tr></tbody></table><p>To associate a pointcut with a contribution block, you call the <code>contribute</code> method. For example, this adds the <code>cm</code> property to all <code>Numbers</code>:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>contribute(currentType(subType(Number))) { property name:"cm", type:"Distance", doc: """A <code>cm</code> from <a href=\"http://joesgroovyblog.blogspot.com/2007/09/and-miles-to-go-before-i-sleep.html\"> http://joesgroovyblog.blogspot.com/2007/09/and-miles-to-go-before-i-sleep.html</a>""" } </pre></td></tr></table><p>The <code>contribute</code> 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.</p><p>When this script is copied into a Groovy project, <code>cm</code> will be included in content assist of all <code>Numbers</code> and their subclasses. Also, references to <code>cm</code> on <code>Numbers</code> 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.</p><h5>Under the hood</h5><p>The pointcuts and contribution blocks are used by Groovy-Eclipse's <a href="http://contraptionsforprogramming.blogspot.com/2009/11/how-type-inferencing-for-groovy-in.html">inferencing engine</a>. The inferencing engine walks the AST and delegates the calculation of expression types to <em>type lookup</em> objects. The type lookups have some capacity for sharing state. DSLD is implemented as a type lookup.</p><p>There are two phases for DSLD files.</p><ol><li><em>The initial compile and processing:</em> at startup or whenever a DSLD file is added or changed, the file is (re-)compiled and the resulting script is executed. Calls to <code>contribute</code> will store the pointcut and its associated contribution block in a table per project.</li><li><em>Invocation by the inferencing engine:</em> 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.</li></ol><h5>More formally</h5><p>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 <a href="http://www.graco.c.u-tokyo.ac.jp/~masuhara/papers/foal2002.pdf">Join Point model</a> requires 3 things:</p><ol><li>A set of reference points that can be referred to; these are the <em>join points</em>.</li><li>A means of identifying (a set of) join points; these are the pointcuts.</li><li>A way to specify semantics at a particular set of join points; such as through advice, intertype declarations, or contribution blocks.</li></ol><p>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.</p><p>The individual components of a join point model are matched to concepts in the DSLD language as follows:</p><ol><li>The join points are expression AST nodes in a Groovy file</li><li>DSLD defines a pointcut language to specify a sub-set of expression node join points</li><li>And Contribution blocks augment the semantics of Groovy-Eclipse's <a href="http://contraptionsforprogramming.blogspot.com/2009/11/how-type-inferencing-for-groovy-in.html">inferencing engine</a> to be enhanced with new type suggestions</li></ol><h3>A deep dive</h3><p>In this section, we go into more detail on the DSLD language and document all of its features.</p><h4>Pointcuts</h4><p>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.</p><p>The parts of a pointcut are as follows:</p><ul><li><em>Arguments:</em> in the DSLD script the text inside of a pointcut's '( )' are the arguments. Most pointcuts take one or zero arguments.</li><li><em>Evaluation arguments:</em> during evaluation, a pointcut is passed a value to match on. This value is called the evaluation argument. For example, <code>currentType(annotatedBy(Delegate))</code>, <code>currentType</code> is the top-level pointcut and is always passed in the current type as a ClassNode object. <code>annotatedBy</code> is passed in what is matched by its surrounding pointcut, in this case it is <code>currentType</code>.</li><li><em>Return values:</em> 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.</li></ul><p>When a match is found, all pointcuts return the objects that are matched in a <code>java.util.Collection</code> object. For consistency, a collection is returned even when a single object is matched.</p><h5>Semantic pointcuts</h5><p>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.</p><p><strong>currentType</strong></p><p>Matches if the current type matches the pointcut argument. The type erasure is used, so the match will be the same if either <code>List<String></code> or <code>List<Class></code> are passed in.</p><p><em>Pointcut Arguments</em></p><p>Expects a string, Class, or ClassNode corresponding to the type to match against. Alternatively, a filtering pointcut can be used.</p><p><em>Evaluation arguments</em></p><p>Always a top-level pointcut.</p><p><em>Return values</em></p><p>The current type as a singleton ClassNode collection.</p><p><em>Example</em></p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>// matches always currentType() </pre></td></tr></table><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>// matches if the current type is a GString currentType(GString) </pre></td></tr></table><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>// matches if the current type is a sub type of java.lang.Number currentType(subType(Number)) </pre></td></tr></table><p><strong>isThisType</strong></p><p>Matches when the current type is the same as the enclosing type. In other words, the current type is <em>this</em>.</p><p><em>Pointcut Arguments</em></p><p>None</p><p><em>Evaluation arguments</em></p><p>Always a top-level pointcut.</p><p><em>Return values</em></p><p>The current type as a singleton <code>ClassNode</code> collection.</p><p><em>Example</em></p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>isThisType() </pre></td></tr></table><p><strong>currentTypeIsEnclosingType</strong></p><p>(Deprecated, use <code>isThisType</code> instead) <br /> Matches when the current type is the same as the enclosing type.</p><p><em>Pointcut Arguments</em></p><p>None</p><p><em>Evaluation arguments</em></p><p>Always a top-level pointcut.</p><p><em>Return values</em></p><p>The current type as a singleton <code>ClassNode</code> collection.</p><p><em>Example</em></p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>currentTypeIsEnclosingType() </pre></td></tr></table><p>In the following code, this pointcut will match on <code>this</code> and <code>x()</code>, but not <code>substring</code>:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>class Foo { def x() { "l" } def y() { this.x().substring(0) } } </pre></td></tr></table><p><strong>sourceFolderOfCurrentType</strong></p><p>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.</p><p><em>Pointcut Arguments</em></p><p>A string specifying the source folder to match on.</p><p><em>Evaluation arguments</em></p><p>Always a top-level pointcut.</p><p><em>Return values</em></p><p>The source folder as a singleton string.</p><p><em>Example</em></p><p>Matches when the current type is defined in <code>src/main/groovy</code>:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>sourceFolderOfCurrentType("src/main/groovy") </pre></td></tr></table><p>Matches on all source types:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>sourceFolderOfCurrentType() </pre></td></tr></table><h5>Filtering pointcuts</h5><p>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.</p><p><strong>field/method/property</strong></p><p>Matches on a set of fields, methods, or properties.</p><p><em>Pointcut Arguments</em></p><p>A string corresponding to the field/method/property name, or another filtering pointcut to further refine the match.</p><p><em>Evaluation arguments</em></p><p>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.</p><p><em>Return values</em></p><p>Returns a collection of fields/methods/properties that have the characteristics specified by pointcut argument.</p><p><em>Example</em></p><p>Matches if the current type has any fields:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>currentType(fields()) </pre></td></tr></table><p>Matches if any method in the current type is named "myMethod". Returns all matched methods as a collection:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>currentType(methods("myMethod")) </pre></td></tr></table><p>Matches if the current type is a sub type of a class that defines a method "myMethod":</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>currentType(subType(methods("myMethod"))) </pre></td></tr></table><p>Note that <code>currentType</code> is optional and if omitted, then the current type is implicitly passed in. So, the following are identical pointcuts to the previous</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>fields() methods("myMethod") subType(methods("myMethod")) </pre></td></tr></table><p><strong>subType</strong></p><p>Matches if the type passed in as an evaluation argument is a sub type of the pointcut argument.</p><p><em>Pointcut Arguments</em></p><p>A string, Class, or ClassNode corresponding to the type that the current type will be checked against.</p><p><em>Evaluation arguments</em></p><p>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.</p><p><em>Return values</em></p><p>A collection of super-types that match the conditions described in the pointcut argument</p><p><em>Example</em></p><p>Matches when the current type is a sub type of something annotated by <code>@Delegate</code>:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>currentType(subType(annotatedBy(Delegate))) // or subType(annotatedBy(Delegate)) </pre></td></tr></table><p>Matches when the enclosing type is a subtype of TestCase:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>enclosingClass(subType("junit.framework.TestCase")) </pre></td></tr></table><p><strong>isStatic/isPublic/isPrivate/isSynchronized/isStatic/isFinal</strong></p><p>Matches when one or more of the evaluation arguments is declared with the given modifier.</p><p><em>Pointcut Arguments</em></p><p>None.</p><p><em>Evaluation arguments</em></p><p>Expecting a collection of AnnotatedNodes.</p><p><em>Return values</em></p><p>A subset of the evaluation arguments that all have the given modifier.</p><p><em>Example</em><br /> Matches if the current type has any static fields:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>fields(isStatic()) </pre></td></tr></table><p><strong>annotatedBy</strong></p><p>Matches when the evaluation arguments correspond to the pointcut argument.</p><p><em>Pointcut Arguments</em></p><p>A string, Class, or ClassNode corresponding to the annotation to match. Alternatively, another pointcut can be used to further constrain the match.</p><p><em>Evaluation arguments</em></p><p>A collection of AnnotatedNodes.</p><p><em>Return values</em></p><p>A collection of all AnnotationNodes matched inside of the evaluation arguments.</p><p><em>Example</em></p><p>Matches when the current type is annotated by @Deprecated:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>annotatedBy("java.lang.Deprecated") </pre></td></tr></table><p>Matches when the current type has any field with any annotation</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>fields(annotatedBy()) </pre></td></tr></table><p>Matches when the current type is annotated by an annotation with the @Retention meta-annotation:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>annotatedBy(annotatedBy("java.lang.annotation.Retention")) </pre></td></tr></table><p><strong>hasAttribute</strong></p><p>Matches when an annotation passed in has an attribute with the appropriate name, type, or value.</p><p><em>Pointcut Arguments</em></p><p>A string corresponding to the name of the annotation to match, or a combination of <code>name</code>, <code>type</code>, and <code>value</code> pointcuts to match against.</p><p><em>Evaluation arguments</em></p><p>A collection of AnnotationNodes.</p><p><em>Return values</em></p><p>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.</p><p><em>Example</em></p><p>Matches if a field in the current type is annotated by an annotation with an attribute called <code>value</code>.</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>currentType(field(annotatedBy(hasAttribute("value")))) </pre></td></tr></table><p>Matches if a field in the current type is annotated by an annotation with an attribute called <code>value</code> and this attribute's value is <em>true</em>.</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>currentType(field(annotatedBy(hasAttribute(name("value") & value(true))))) </pre></td></tr></table><p>Matches if a field in the current type is annotated by an annotation with an attribute called <code>value</code> and this attribute's type is <code>java.lang.Boolean</code>. Additionally, the value of the attribute is bound to <code>val</code>.</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>currentType(field(annotatedBy(hasAttribute(name("value") & type(Boolean) & bind(val : value()))))) </pre></td></tr></table><p><strong>type</strong></p><p>Matches on the type of a field, argument, parameter, annotation attribute, or method return type. See <code>hasAttribute</code> and <code>hasArgument</code> for examples.</p><p><strong>declaringType</strong></p><p>Matches on the declaring type of a field, method, or property. See <code>enclosingCall</code> and <code>hasArgument</code> for an example.</p><p><strong>value</strong></p><p>Matches on the value of an argument or annotation attribute. See <code>hasAttribute</code> and <code>hasArgument</code> for examples. If the matched value is bound to a name, then the value is <em>reified</em>. This means that the value can be used inside of the DSLD as a primitive or a string. For example:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>contribute(enclosingCall(hasArgument(name("flar") & bind(vals : value())))) { vals.each { val -> if (val > 9) { log "val is greater than 9" } else { log "val is less than 9" } } </pre></td></tr></table><p>In the example above, the bound values can be directly compared to primitives or strings in the DSLD.</p><p><strong>name</strong></p><p>Matches on the fully qualified name of an element.</p><p><em>Pointcut Arguments</em></p><p>A string corresponding to the name to match</p><p><em>Evaluation arguments</em></p><p>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, <code>toString()</code> will be called on the evaluation argument.</p><p><em>Return values</em></p><p>The name or names that were matched as a collection.</p><p><em>Example</em></p><p>Matches if the name of the current type is "p.Bar" and it has a method named "foo":</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>currentType(name("p.Bar") & methods("foo")) </pre></td></tr></table><h5>Lexical pointcuts</h5><p>These are pointcuts that depend on the lexical structure of the surrounding AST.</p><p><strong>enclosingScript/enclosingClass</strong></p><p>Matches when the enclosing type is a script/class.</p><p><em>Pointcut Arguments</em></p><p>A string, Class, or ClassNode corresponding to the type name to match on. Alternatively, a pointcut argument can be used.</p><p><em>Evaluation arguments</em></p><p>These pointcuts are top-level only.</p><p><em>Return values</em></p><p>The type that was matched.</p><p><em>Example</em></p><p>Matches when inferring inside of a script:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>enclosingScript() </pre></td></tr></table><p>Matches when inferring inside of a script named "pack.MyScript":</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>enclosingScript("pack.MyScript") </pre></td></tr></table><p>Matches when inferring inside of a class that has a @Singleton annotation</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>enclosingClass(annotatedBy(Singleton)) </pre></td></tr></table><p><strong>enclosingField/enclosingMethod</strong></p><p>Matches when enclosed by a field or method of the given characteristics. A code block is <em>enclosed</em> by a field if it is inside of a field initializer. For example, the print statement is <em>enclosed</em> by the <em>x</em> field:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>class F { def x = { print "I am enclosed!" } } </pre></td></tr></table><p><em>Pointcut Arguments</em></p><p>A string, Class, or ClassNode corresponding to the type name to match on. Alternatively, a pointcut argument can be used.</p><p><em>Evaluation arguments</em></p><p>These pointcuts are top-level pointcuts only.</p><p><em>Return values</em></p><p>A singleton collection of the enclosing method/field if the current location matches.</p><p><em>Example</em></p><p>Matches when the enclosing method or field has the given annotation:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>enclosingMethod(annotatedBy("com.foo.MyAnnotation")) | enclosingField(annotatedBy("com.foo.MyAnnotation")) </pre></td></tr></table><p><strong>enclosingCall</strong></p><p>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., <code>foo(bar(arg))</code>).</p><p><em>Pointcut Arguments</em></p><p>Inner pointcuts are required. The inner pointcuts accepted are: <code>name</code> to match on the method name, <code>type</code> to match on the return type, <code>declaringType</code> to match on the method's declaring type, and <code>hasArgument</code> to match on the method call's arguments.</p><p><em>Evaluation arguments</em></p><p>This pointcut is top-level only.</p><p><em>Return values</em></p><p>The method call expression as a Groovy AST node.</p><p><em>Example</em></p><p>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":</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>enclosingCall(name("myMethod") & declaringType("com.foo.Bar") & (hasArgument("first") | hasArgument("second"))) </pre></td></tr></table><p><strong>hasArgument</strong></p><p>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 <code>value</code> inner pointcut cannot be used.</p><p><em>Pointcut Arguments</em></p><p>If a string is passed as the pointcut argument, then the match is against the name of the parameter. Alternatively, any of <code>name</code>, <code>value</code>, and <code>type</code> can be used as enclosed pointcuts.</p><p><em>Evaluation arguments</em></p><p>This pointcut must be used inside of <code>enclosingCall</code> or <code>enclosingMethod</code>.</p><p><em>Return values</em></p><p>The <em>value</em> 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.</p><p><em>Example</em></p><p>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 <em>val</em> to a the value of the named argument.</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>enclosingCall(name("myMethod") & declaringType("com.foo.Bar") & (hasArgument(name("first") & type(String) & bind( val : value())))) </pre></td></tr></table><p>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 <code>value</code> pointcut is not applicable since there is no value to match on.</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>enclosingCall(name("myMethod") & declaringType("com.foo.Bar") & (hasArgument(name("first") & type(String)))) </pre></td></tr></table><p><strong>enclosingCallName/enclosingCallDeclaringType</strong></p><p>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:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>myVariable.someMethod(bar, baz) { it.otherMethod(inside) } </pre></td></tr></table><p>In the code above, <code>bar</code> and <code>baz</code> are enclosed by the <code>someMethod</code> method call. Additionally, all expressions in the closure are enclosed. The reference to <code>inside</code> is enclosed by two method calls: <code>someMethod</code> and <code>otherMethod</code>.</p><p><em>Pointcut Arguments</em></p><p><code>enclosingCallName</code> takes a string corresponding to the name of the method call. <code>enclosingCallDeclaringType</code> takes a string, Class, ClassNode, or other pointcut to describe the type to match on.</p><p><em>Evaluation arguments</em></p><p>This pointcut is top-level only.</p><p><em>Return values</em></p><p>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 <code>otherMethod</code> and then <code>someMethod</code>.</p><p><em>Example</em></p><p>Matches when enclosed by a method call <code>foo</code> declared by <code>com.bar.MyClass</code>:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>enclosingCallName("foo") & enclosingCallDeclaringType("com.bar.MyClass") </pre></td></tr></table><p><strong>enclosingClosure</strong></p><p>Matches when enclosed by a closure.</p><p><em>Pointcut Arguments</em></p><p>No arguments.</p><p><em>Evaluation arguments</em></p><p>This pointcut is top-level only.</p><p><em>Return values</em></p><p>An ordered collection of ClosureExpressions corresponding to the lexically closest closure to the furthest. For example:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>def constraints = { tryThis { print "Me" } } </pre></td></tr></table><p>In the previous code snippet, when inferring on the print method call, enclosingClosure would return two closure expressions: first the closure attached to <code>tryThis</code> and then the closure attached to <code>constraints</code>.</p><p><em>Example</em></p><p>Here is a pointcut describing when inside of a <code>SwingBuilder</code> closure:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>enclosingClosure() & enclosingCallDeclaringType("groovy.swing.SwingBuilder") & enclosingCallName("edt") </pre></td></tr></table><h5>Structural pointcuts</h5><p>These are pointcuts that depend on the structure and naming conventions of the file system.</p><p><strong>nature</strong></p><p>Matches on the Eclipse project nature of the current project. For</p><p><em>Pointcut Arguments</em></p><p>A string corresponding to the desired project nature. Examples are:</p><ul><li>Grails: <code>com.springsource.sts.grails.core.nature</code></li><li>GWT nature: <code>com.google.gwt.eclipse.core.gwtNature</code></li></ul><p><em>Evaluation arguments</em></p><p>This pointcut is top level only.</p><p><em>Return values</em></p><p>Returns the name of the nature as a singleton collection.</p><p><em>Example</em></p><p>Matches domain classes in grails projects:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>nature("com.springsource.sts.grails.core.nature") & sourceFolderOfCurrentType("grails-app/domain") </pre></td></tr></table><p><strong>fileName/fileExtension</strong></p><p>Matches on the full file name or on the file extension of the current file being inferred.</p><p><em>Pointcut Arguments</em></p><p>A string corresponding to the file name or extension (excluding the '.') to match.</p><p><em>Evaluation arguments</em></p><p>This pointcut is top level only.</p><p><em>Return values</em></p><p>Returns the name of the file that was matched.</p><p><em>Example</em></p><p>Matches on gradle files:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>fileExtension("gradle") </pre></td></tr></table><p>Matches on <code>MyScript.groovy</code>:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>fileName("MyScript.groovy") </pre></td></tr></table><p><strong>sourceFolderOfCurrentFile</strong></p><p>Matches on the source folder of the file currently being inferred. Note that this is different from <code>sourceFolderOfCurrentType</code> that will match on the current type. <code>sourceFolderOfCurrentFile</code> will return the same value for the entire file, whereas <code>sourceFolderOfCurrentType</code> will have a different value depending on the type of the current expression.</p><p><em>Pointcut Arguments</em></p><p>A string corresponding to the source folder to match on.</p><p><em>Evaluation arguments</em></p><p>This pointcut is top level only.</p><p><em>Return values</em></p><p>The matches source folder as a singleton collection.</p><p><em>Example</em></p><p>Matches when in the <code>src</code> folder:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>sourceFolderOfCurrentFile("src") </pre></td></tr></table><h5>Combinatorial pointcuts</h5><p>No need to explicitly invoke these pointcuts. They are included here for completeness and are implicitly created when using <code>&</code>, <code>|</code>, and <code>~</code> (meaning the <code>and</code>, <code>or</code>, and <code>not</code> pointcuts respectively).</p><p><strong>and/or/not</strong></p><p><em>Pointcut Arguments</em></p><p>These are the only pointcuts that can take more than one argument. The arguments must be other pointcuts.</p><p><em>Evaluation arguments</em></p><p>These pointcuts can take any evaluation arguments. They are simply passed on to their contained pointcuts.</p><p><em>Return values</em></p><p>For <code>or</code> and <code>and</code>, a collection of all elements matched by the containing pointcuts. For <code>not</code>, this will return a singleton collection with an <code>Object</code> value if the containing pointcut does not match.</p><p><em>Example</em></p><p>It is generally good to use parens around the pointcut argument of <code>not</code>. Matches when the current type has no fields:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>~(fields()) // equivalent to: not(fields()) </pre></td></tr></table><p>Matches when inside a deprecated class, and there is a field or method in the class named "bar":</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>enclosingClass(annotatedBy(Deprecated)) & (fields("bar") | methods("bar")) // equivalent to: and(enclosingClass(annotatedBy(Deprecated)), or(fields("bar"), methods("bar"))) </pre></td></tr></table><table class="wysiwyg-macro" data-macro-name="tip" data-macro-parameters="title=Things to be careful about" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e3RpcDp0aXRsZT1UaGluZ3MgdG8gYmUgY2FyZWZ1bCBhYm91dH0&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="RICH_TEXT"><tr><td class="wysiwyg-macro-body"><p>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:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>(~ isPublic() ) | name("java.lang.String") </pre></td></tr></table><p>instead of this:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>~ isPublic() | name("java.lang.String") </pre></td></tr></table><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> </pre></td></tr></table></td></tr></table><h5>Binding pointcuts</h5><p>There is only one binding pointcut, called <code>bind</code>. This pointcut explicitly binds the return value to a name to make it available in a contribution block.</p><p>The explicit use of the <code>bind</code> pointcut can be omitted when it is surrounded by another pointcut. There is a bigger discussion of this pointcut below.</p><p><strong>bind</strong></p><p><em>Pointcut Arguments</em></p><p>A single pointcut</p><p><em>Evaluation arguments</em></p><p>Any evaluation arguments. They are passed to the contained pointcut.</p><p><em>Return values</em></p><p>Returns the value returned by the contained pointcut.</p><p><em>Example</em></p><p>Binds a collection of deprecated annotations:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>fields(bind(dep : annotatedBy(Deprecated))) // this fully is equivalent to: fields(dep : annotatedBy(Deprecated)) </pre></td></tr></table><p>Binds to deprecated fields in the current type. In this case, bind is necessary:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>bind(dep : fields(annotatedBy(Deprecated))) </pre></td></tr></table><h5>User-defined pointcuts</h5><p>It is possible to register your own pointcuts that will be available in the current DSLD script only. See the <code>registerPointcut</code> section below.</p><h5>Other pointcuts</h5><p>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: <code>regex</code>, <code>instanceof</code>, <code>superType</code>, <code>enclosingType</code>, <code>enclosingEnum</code>, and others.</p><table class="wysiwyg-macro" data-macro-name="info" data-macro-parameters="title=Some subtleties about java.lang.Class references" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2luZm86dGl0bGU9U29tZSBzdWJ0bGV0aWVzIGFib3V0IGphdmEubGFuZy5DbGFzcyByZWZlcmVuY2VzfQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="RICH_TEXT"><tr><td class="wysiwyg-macro-body"><p>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.</p><p>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.</p><p>More specifically:</p><ul><li>Instead of referencing the class <code>MyLocalType</code> directly, you can reference it as a String <code>"com.mycompany.MyLocalType"</code></li><li>Standard JDK, GDK, and all types defined in groovy-all are available directly in your DSLD and will show compile errors.</li><li>It is possible to reference types in packages beginning with <code>org.eclipse.jdt.</code><strong> and <code>org.codehaus.groovy.eclipse.</code></strong> if all references are fully qualified. However, this is not recommended unless you really know what you are doing.</li></ul></td></tr></table><h5>Assigning pointcuts to variables</h5><p>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:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>def grailsArtifact = { String folder -> sourceFolderOfCurrentType("grails-app/"+ folder) & nature("com.springsource.sts.grails.core.nature") & (~enclosingScript()) } def domainClass = grailsArtifact("domain") def controllerClass = grailsArtifact("controllers") </pre></td></tr></table><p>Notice how it is possible to use a closure so that pointcut components can be shared and parameterized.</p><p>We can use the <code>domainClass</code> pointcut above as a component in a larger pointcut that describes where the Grails constraints DSL is applicable:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>contribute(domainClass & enclosingField(name("constraints") & isStatic()) & inClosure() & currentTypeIsEnclosingType() & (bind(props : properties()))) { ... } </pre></td></tr></table><p>Let's break this down a bit:</p><ol><li>The first thing to notice is that the <code>domainClass</code> reference doesn't require and parens. This is because parens have already been used when the pointcut was first declared.</li><li>Next, notice the <code>enclosingField</code> pointcut. This component matches when the enclosing field name is <code>constraints</code> and the field is static.</li><li>Usually, the <code>name()</code> pointcut is implicit and optional, but since '&' requires pointcuts on either side, we need to wrap the <code>"constraints"</code> string inside of a poincut.</li><li>Next, the expression must be inside of a closure</li><li>The <code>currentTypeIsEnclosingType()</code> pointcut means that the type of the current expression must be the type of the enclosing class. Thus, references to <code>this</code> will match, but references to other types (such as <code>new String()</code> will not).</li></ol><h4>Contribution Blocks</h4><p>Now that we have described the pointcut language, we can delve into what happens in contribution blocks.</p><p>You have already been introduced to the following form, which adds a property to the type of the expression matched in the contributing pointcut:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>contribute(...) { property name : "cm", type: Number, doc : "..." } </pre></td></tr></table><p>The full form of <code>property</code> is:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>property name : "cm", type: "Distance", declaringType: Number, isStatic : false, doc : "<b>Enter javadoc here</b> html is supported", provider : "A readable name for your DSL (no html)" </pre></td></tr></table><p>A few notes:</p><ul><li><code>name</code> is the only required argument</li><li><code>type</code> defaults to <code>java.lang.Object</code> and the argument can be of type <code>java.lang.String</code>, <code>java.lang.Class</code>, or <code>org.codehaus.groovy.ast.ClassNode</code>.</li><li><code>declaringType</code> defaults to the currentType and can accept a String, Class, or ClassNode</li><li><code>doc</code> is the javadoc that will show up in hovers and accepts html syntax</li><li><code>provider</code> is 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</li></ul><p>The following methods are available (for completeness, we include <code>property</code> again):</p><table class="confluenceTable"><tbody><tr><td class="confluenceTd"><p><strong>property</strong></p></td><td class="confluenceTd"><p>declares a new property. The full form is like this. Name is the only required field:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>property name : "nameOfTask", type: String, declaringType: "java.lang.String", isStatic : false, isDeprecated: false, provider : "A readable name for your DSL", doc : "<b>Enter javadoc here</b> html is supported" </pre></td></tr></table></td></tr><tr><td class="confluenceTd"><p><strong>method</strong></p></td><td class="confluenceTd"><p>declares a new method. The full form is like this. Name is the only required field:</p><table class="wysiwyg-macro" data-macro-name="code" data-macro-parameters="language=groovy|linenumbers=true" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGU6bGluZW51bWJlcnM9dHJ1ZXxsYW5ndWFnZT1ncm9vdnl9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>method name : "nameOfTask", type: String, declaringType: "java.lang.String", params : [ arg1 : String, arg2 : Class], namedParams : [arg3 : Long, arg4 : Short], optionalParams: [arg5: Byte], isStatic : false, isDeprecated: false, // if true, then any uses of this method will have a line through it noParens: false, // if true content assist will assume this is a groovy command chain expression and avoid using parens doc : "<b>Enter javadoc here</b> html and javadoc tags supported", provider : "A readable name for your DSL" </pre></td></tr></table><p>A note on parameter kinds:</p><ul><li><code>params</code> : regular parameters are added via content assist on the method</li><li><code>namedParams</code> : named parameters are added via content assist on the method prefixed by a name. And if content assist is invoked after a paren or a comma (with no text prefix), unused named parameters will be suggested.</li><li><code>optionalParams</code> : optional parameters are only available when performing completion after a paren or comma (with no text prefix). They are not included during normal method content assist.</li></ul><div>Parameter names may include whitespace and special characters as long as the parameter is quoted. For example, it is possible to simulate varargs like this:</div><div><p> </p><table class="wysiwyg-macro" data-macro-name="code" data-macro-parameters="language=groovy" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGU6bGFuZ3VhZ2U9Z3Jvb3Z5fQ&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>method name : "meth", params : ["... values", String]</pre></td></tr></table></div></td></tr><tr><td class="confluenceTd"><p><strong>delegatesTo</strong></p></td><td class="confluenceTd"><p>adds all of the public methods in the delegated type to the current type. For example:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>delegatesTo List </pre></td></tr></table><p>will add all public methods of list to the current type for content assist, underlining, hovers, and navigation.</p></td></tr><tr><td class="confluenceTd"><p><strong>delegatesTo</strong></p></td><td class="confluenceTd"><p>(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:</p><ul><li><code>type</code> : (required) the type to delegate to.</li><li><code>asCategpry</code> : (optional) if true, treat the delegated type as a category and only include static methods where the first parameter matches the type of the current type.</li><li><code>useNamed</code> : (optional) if true, content assist will be applied using named arguments.</li><li><code>except</code> : (optional) a list of method names to exclude from the delegation (useful if these methods are already being added through some other contribution).</li><li><code>isDeprecated</code> : (optional) if true then this contribution is deprecated and all references to delegated methods will appear in the UI with a line through them.</li></ul></td></tr></tbody></table><p>For example:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>delegatesTo type:List, asCategory:false, useNamed:false, except:["addAll", "removeAll"], isDeprecated:true </pre></td></tr></table><table class="confluenceTable"><tbody><tr><td class="confluenceTd"><p><strong>delegatesToUseNamedArgs</strong></p></td><td class="confluenceTd"><p>(<em>deprecated</em>, <code>delegatesTo type:"com.Foo", useNamed:true</code> instead) similar to <code>delegatesTo</code>, but uses named arguments when applying content assist proposals</p></td></tr></tbody></table><p>And the following properties</p><table class="confluenceTable"><tbody><tr><td class="confluenceTd"><p><strong>provider</strong></p></td><td class="confluenceTd"><p>sets the provider for the entire contribution block. Eg,</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>provider = "My Groovy DSL" </pre></td></tr></table><p>will ensure that "My Groovy DSL" appears in content assist next to all contributions added by this block.</p></td></tr><tr><td class="confluenceTd"><p><strong>currentNode</strong></p></td><td class="confluenceTd"><p>Accesses the current Groovy AST node (an expression node)</p></td></tr><tr><td class="confluenceTd"><p><strong>enclosingNode</strong></p></td><td class="confluenceTd"><p>Accesses the Groovy AST node (an expression node) that encloses the currentNode. This is the parent node of the currentNode in the AST.</p></td></tr><tr><td class="confluenceTd"><p><strong>wormhole</strong></p></td><td class="confluenceTd"><p>A means to pass state between contribution blocks. An example is given below.</p></td></tr></tbody></table><p>This list of available properties and methods will likely change as we continue to work on DSLD.</p><h4>Binding</h4><p>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.</p><p>For example, here is the DSL for the @Delegate AST transform:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>contribute(currentType(fields : findField(annotatedBy(Delegate)))) { fields.each { FieldNode field -> delegatesTo type:field.declaringType } } </pre></td></tr></table><p>The <code>fields</code> argument is bound to all of the fields in the current type with the <code>Delegate</code> annotation. If there is only one field, then the result is a single Groovy <code>FieldNode</code>, if there are multiple matches, then <code>fields</code> is bound to an object of type <code>List<FieldNode></code>. 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.</p><p>Sometimes, it might be necessary to bind on the outermost pointcut component. In this case, you can use the <code>bind()</code> pointcut. For example, the following is the syntax for the @Singleton AST transform</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>contribute( bind( type :currentType(annotatedBy(Singleton)))) { method name:"instance", type:type, isStatic:true, declaringType:type, doc:"Get the singleton instance of this Class" } </pre></td></tr></table><h4>SupportsVersion and AssertVersion</h4><p>To ensure that a script only runs when particular features are installed, you can use the <code>assertVersion</code> 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.</p><p>The syntax looks like this:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>assertVersion(component1:"x.y.z", component2:"a.b.c") </pre></td></tr></table><p>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.</p><p>Currently, only 'groovy', 'groovyEclipse', and 'grailsTooling' are supported, but we may add other component kinds later. A real example is here:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>assertVersion(groovy:"1.7.8",groovyEclipse:"2.1.3") </pre></td></tr></table><p>Alternatively, you can use the <code>supportsVersion</code> 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:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>// Power asserts have changed packages between 1.7 and 1.8 if (supportsVersion(groovy:"1.8.0")) { contribute(currentType("org.codehaus.groovy.runtime.powerassert.PowerAssertionError")) { // contribute methods and properties } } else { contribute(currentType("org.codehaus.groovy.transform.powerassert.PowerAssertionError")) { // contribute methods and properties } } </pre></td></tr></table><h4>Register pointcut</h4><p>It is possible to create and register a locally defined pointcut. You can do so by invoking the <code>registerPointcut</code> closure at the top level of a DSLD file. <code>registerPointcut</code> 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.</p><p>For example, the following defines <code>twoArgs</code>, a pointcut that matches when the evaluation argument is a MethodNode with two arguments with the proper names:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>import org.codehaus.groovy.ast.MethodNode import org.codehaus.groovy.ast.Parameter; registerPointcut("twoArgs", { if (it instanceof MethodNode) { Parameter[] params = it.parameters if (params?.length >= 2 && params[0].name == "firstName" && params[1].name == "lastName") { return params.collectEntries{ [it.name, it.type] } } } }) </pre></td></tr></table><p>This pointcut can be used as follows:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>contribute( (enclosingMethod(twoArgs() & name("processName")) & currentTypeIsEnclosingType())) { method name: "checkDatabaseForNames" } </pre></td></tr></table><p>This will match on the following code:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>def processName(String firstName, String lastName, String middleName) { //...in here } </pre></td></tr></table><p>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:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>contribute((enclosingMethod(bind(paramNameTypeCollection : twoArgs()) & name("processName")) & currentTypeIsEnclosingType())) { for (paramNameTypes in paramNameTypeCollection) { method name: "checkDatabaseForNames", params: paramNameTypes } } </pre></td></tr></table><p>Now, the generated method will have the same parameter names and types as the method declaration that encloses it. We need to iterate through <code>paramNameTypeCollection</code> because all named bindings are collections. Note that the default groovy method <code>collectEntries</code> is only available in Groovy 1.8 or greater.</p><p>There is more that you can do with <code>registerPointcut</code>. The pointcut closure recognizes all named arguments that are passed in to it. For example:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>registerPointcut("alsoTwoArgs", { def result = null if (!methods || !current) { return null } // since current and methods are passed in as bindings, they are collections and need an iterator ClassNode type = current?.iterator()?.next() if (type) { for (elt in methods) { if (elt instanceof MethodNode) { Parameter[] ps = elt.parameters if (ps?.length >= 2 && ps[0].name == "firstName" && ps[1].name == "lastName") { return "findProcessorForClass" + type.getNameWithoutPackage() } } } } }) contribute(bind(names : alsoTwoArgs(methods : enclosingMethod("processName"), current : currentTypeIsEnclosingType()))) { for (name in names) { property name:name, type:GroovyObject } } </pre></td></tr></table><p>This matches the following code:</p><table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre>class FullName { def processName(firstName, lastName) { this.findProcessorForClassFullName() } } </pre></td></tr></table><h4>Wormhole</h4><p>It is possible to pass state between contribution blocks using the wormhole. More about this later...</p><table class="wysiwyg-macro" data-macro-name="info" data-macro-parameters="title=The dark side of DSLDs" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2luZm86dGl0bGU9VGhlIGRhcmsgc2lkZSBvZiBEU0xEc30&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="RICH_TEXT"><tr><td class="wysiwyg-macro-body"><p>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 <strong>not</strong> try:</p><ul><li>Add <code>System.exit()</code> to any of your scripts (take a wild guess as to what will happen...)</li><li>Make any changes to global state</li><li>Access <code>org.eclipse.core.internal.runtime.AdapterManager</code> or any other Eclipse singleton.</li></ul><p>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.</p><p>In the future, it is likely that DSLDs will be executed in the context of a security manager to prevent these kinds of problems.</p></td></tr></table><h3>Some larger examples</h3><p>Some larger examples can be found at <a class="confluence-link" href="/display/GROOVY/DSLD+examples" data-linked-resource-id="205783086" data-linked-resource-type="page" data-linked-resource-default-alias="DSLD examples" data-base-url="http://docs.codehaus.org">DSLD examples</a>.</p>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced