About Adam Warski

Adam is one of the co-founders of SoftwareMill, a company specialising in delivering customised software solutions. He is also involved in open-source projects, as a founder, lead developer or contributor to: Hibernate Envers, a Hibernate core module, which provides entity versioning/auditing capabilities; ElasticMQ, an SQS-compatible messaging server written in Scala; Veripacks, a tool to specify and verify inter-package dependencies, and others.

Automatic generation of delegate methods with Macro Annotations

Macro Annotations are a new type of macros, which are one of the candidates for inclusion (see also comment by Eugene below) in the upcoming Scala 2.11 release. However, thanks to the recently released Macro Paradise Scala 2.10 compiler plugin, with an extra option in the compiler/SBT settings, you can use them today, while still using a stable Scala version at runtime.

One of the Macro Annotations use-cases mentioned in the manual is compile-time AOP. I decided to try implementing something similar, but a bit simpler for a start: automatic generation of delegate methods (decorator pattern/proxy pattern). In fact, some years ago there was a similar effort using a compiler plugin (autoproxy plugin). As an additional motivation, Łukasz recently asked on our technical room if Scala has this exact functionality – instead of saying “No”, I should have said “Not yet” .

The results of the POC are available on GitHub, in the scala-macro-aop repository: https://github.com/adamw/scala-macro-aop. If you have SBT, you can play with the implementation just by invoking run from the SBT console.

How does it work? Let’s say we have an interface Foo with three methods (with very original names: method1, method2 and method3), each taking some parameters. We have a default implementation:

trait Foo {
   def method1(param1: String): Int
   def method2(p1: Int, p2: Long): Float
   def method3(): String
}

class FooImpl extends Foo {
   def method1(param1: String) = param1.length
   def method2(p1: Int, p2: Long) = p1 + p2
   def method3() = "Hello World!"
}

Now we would like to create a wrapper for a Foo instance, which would delegate all method calls to the given instance, unless the method is defined in the wrapper.

The traditional solution is to create a delegate for each method by hand, e.g.:

class FooWrapper(wrapped: Foo) extends Foo {
   def method1(param1: String) = wrapped.method1(param1)
   def method2(p1: Int, p2: Long) = wrapped.method2(p1, p2)
   def method3() = wrapped.method3()
}

But that’s a lot of work. Using the @delegate macro, the delegate methods will now be automatically generated at compile time! That is, the wrapper now becomes:

class FooWrapper(@delegate wrapped: Foo) extends Foo {
   // method1, method2 and method3 are generated at compile time
   // and delegate to the annotated parameter
}

What if we want to implement some methods? The macro will generate only the missing ones:

class FooWrapper(@delegate wrapped: Foo) extends Foo {
   def method2(p1: Int, p2: Long) = p1 - p1
   // only method1 and method3 are generated
}

As the implementation is just a POC, it will only work in simple cases, that is for methods with a single parameter list, without type parameters and when the method is not overloaded. Plus the code of the macro is, let’s say, “not yet polished”.

As mentioned before, the code is on GitHub: https://github.com/adamw/scala-macro-aop, available under the Apache2 license.
 

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

4 Responses to "Automatic generation of delegate methods with Macro Annotations"

  1. JLJunk says:

    I would like to see a macro that does essentially what the Project Lombok @delegate method does in Java.

    If I understand correctly the delegate macro shown here requires the delegating class to share an interface with the delegate – in your example they both extend Foo.

    What I am looking for is a way to share behaviour without sharing types – Lombok does this for me in Java.
    In Lombok the annotation causes the annotated class to acquire the behaviour of the other class (via a private field that holds the delegate and a set of generated delegate methods) without sharing its type.

  2. Nepomuk says:

    Hi,

    This is pretty neat. However IMHO this seems pretty similar to the newly introduced implicit classes, right?
    http://docs.scala-lang.org/overviews/core/implicit-classes.html

    With the macro you have more freedom where to declare you wrapper class, but the result is the same.

    cheers,
    Muki

    • Implicit classes are for “adding” a new method to an existing object via a wrapper with implicit conversions.

      Delegates are for overriding some of the existing methods in the object’s class.

      Adam

Leave a Reply


× 9 = seventy two



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close