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>If you've been using Groovy for a while, you're certainly familiar with the concept of Categories. It's a mechanism to extend existing types (even final classes from the JDK or third-party libraries), to add new methods to them. This is also a technique which can be used when writing Domain-Specific Languages. Let's consider the example below:</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> final class Distance { def number String toString() { "${number}m" } } class NumberCategory { static Distance getMeters(Number self) { new Distance(number: self) } } use(NumberCategory) { def dist = 300.meters assert dist instanceof Distance assert dist.toString() == "300m" } </pre></td></tr></table> <p>We have a simplistic and fictive Distance class which may have been provided by a third-party, who had the bad idea of making the class final so that nobody could ever extend it in any way. But thanks to a Groovy Category, we are able to decorate the Distance type with additional methods. Here, we're going to add a getMeters() method to numbers, by actually decorating the Number type. By adding a getter to a number, you're able to reference it using the nice property syntax of Groovy. So instead of writing 300.getMeters(), you're able to write 300.meters.</p> <p>The downside of this category system and notation is that to add instance methods to other types, you have to create static methods, and furthermore, there's a first argument which represents the instance of the type we're working on. The other arguments are the normal arguments the method will take as parameters. So it may be a bit less intuitive than a normal method definition we would have added to Distance, should we have had access to its source code for enhancing it. Here comes the @Category annotation, which transforms a class with instance methods into a Groovy category:</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> @Category(Number) class NumberCategory { Distance getMeters() { new Distance(number: this) } } </pre></td></tr></table> <p>No need for declaring the methods static, and the this you use here is actually the number on which the category will apply, it's not the real this of the category instance should we create one. Then to use the category, you can continue to use the use(Category) {} construct. What you'll notice however is that these kind of categories only apply to one single type at a time, unlike classical categories which can be applied to any number of types.</p> <p>Now, pair @Category extensions to the @Mixin transformation, and you can mix in various behavior in a class, with an approach similar to multiple inheritance:</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> @Category(Vehicle) class FlyingAbility { def fly() { "I'm the ${name} and I fly!" } } @Category(Vehicle) class DivingAbility { def dive() { "I'm the ${name} and I dive!" } } interface Vehicle { String getName() } @Mixin(DivingAbility) class Submarine implements Vehicle { String getName() { "Yellow Submarine" } } @Mixin(FlyingAbility) class Plane implements Vehicle { String getName() { "Concorde" } } @Mixin([DivingAbility, FlyingAbility]) class JamesBondVehicle implements Vehicle { String getName() { "James Bond's vehicle" } } assert new Plane().fly() == "I'm the Concorde and I fly!" assert new Submarine().dive() == "I'm the Yellow Submarine and I dive!" assert new JamesBondVehicle().fly() == "I'm the James Bond's vehicle and I fly!" assert new JamesBondVehicle().dive() == "I'm the James Bond's vehicle and I dive!" </pre></td></tr></table> <p>You don't inherit from various interfaces and inject the same behavior in each subclass, instead you mixin the categories into your class. Here, our marvelous James Bond vehicle gets the flying and diving capabilities through mixins.</p> <p>An important point to make here is that unlike @Delegate which can <em>inject</em> interfaces into the class in which the delegate is declared, @Mixin just does runtime mixing — as we shall see in the metaprogramming enhancements further down in this article.</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