Over a million developers have joined DZone.

Putting Proxy-o-Matic to work

· Java Zone

What every Java engineer should know about microservices: Reactive Microservices Architecture.  Brought to you in partnership with Lightbend.

It all started a couple of weeks ago when Alex Tkachman submitted the following code to the Groovy dev list

as(MouseListener) {
println "Clicked: $it"

mousePressed {
println "Pressed: $it"

This little piece of code should create an instance of something (an unknown class) that implements the MouseListener interface, in other words, it creates a proxy of MouseListener. But before we get into topic let's revisit what Groovy already offers: the ability to create a proxy from some predefined structure, in this case a Map or a Closure, given the following rules

  • you must use the as keyword
  • when coercing a Closure, the target interface should define one method only
  • when coercing a Map, the target may be an interface, an abstract or concrete class

Those rules allow you to create a proxy easily and though maps let you proxy 3 different targets they come with two drawbacks

  • maps must hold a unique key per method name, you can't proxy overloaded method definitions
  • you can't call a proxied method within another proxied method

 Fortunately Groovy includes a very handy alternative to dynamic beans: Expandos. If you haven't seen expandos before think of them as JSON objects. Yes, I meant exactly that. You can add properties at will to an Expando, if a value of a property happens to be a closure then that property will be treated as a method definition, let's look at the following example

def bean = new Expando()
bean.foo = {-> "foo" }
bean.bar = {-> "bar" }
bean.foobar = {-> foo()+bar() }
assert bean.foo() == "foo"
assert bean.bar() == "bar"
assert bean.foobar() == "foobar"

Alright, expandos can overcome restriction #2 on maps, but as they are also map based restriction #1 still applies, and sadly expandos do not come with a proxy friendly mechanism wired through the as keyword (which actually works by calling asType(Class) on the target).

Enter Proxy-o-Matic.

Proxy-o-Matic's main class (aptly named ProxyOMatic) exposes a very simple API to homogeneoslycreate proxies from the three sources we have outlined: Closures, Maps and Expandos, and provides features that overcome some of the limitations that the aforementioned rules can't break. Proxies create with ProxyOMatic.proxy() share the following features

  • call proxied methods from within other proxied methods
  • may proxy more than one interface at the same time

Proxies created from closures may

  • define method implementations with syntax similar to how classes are defined
  • define method implementations for overloaded methods

Proxies created from maps may

  •  define method implementations for overloaded methodsprovided they use ProxyMethodKey as keys instead of Strings

Expandos don't gain much other that the shared features so far. But enough theory, code should show you a better picture, let's take the following interface definitions for example

interface Foo { String foo() }
interface Bar { String bar() }
interface FooBar extends Foo, Bar {
String foobar()
interface Fooz extends Foo {
String foo( String n )

Creating proxies from closures and Maps for the first three is as simple as

import static org.kordamp.groovy.util.ProxyOMatic.proxy

def fc = proxy( Foo ) {
foo { -> "Foo" }
def fbc = proxy( FooBar ) {
foo { -> "Foo" }
bar { -> "Bar" }
foobar { -> foo() + bar() }

def fm = proxy( Foo, [
foo: { -> "Foo" }
def fbm = proxy( FooBar, [
foo: { -> "Foo" },
bar: { -> "Bar" },
foobar: { -> foo() + bar() }

// assert proxies are of the required type
assert fc instanceof Foo
assert fm instanceof Foo
assert fbc instanceof FooBar
assert fbm instanceof Foobar

// assert methods return expected results
assert [fc.foo(),fm.foo()] == ["Foo","Foo"]
assert [fbc.bar(),fbm.bar()] == ["Bar","Bar"]
assert [fbc.foobar(),fbm.foobar()] == ["FooBar","FooBar"]

You are probably wondering about the overloaded method version, without further ado

// don't forget to add the following line
// import static org.kordamp.groovy.util.ProxyOMatic.methodKey

def fzc = proxy( Fooz ) {
foo { -> "Foo" }
foo { String n -> "Foo" + n }
def map = [:]
map[methodKey("foo")] = { -> "Foo" }
map[methodKey("foo",[String])] = { String n -> "Foo" + n }
def fzm = proxy( Fooz, map )

assert fzc.foo() == "Foo"
assert fzc.foo("Groovy") == "FooGroovy"
assert fzm.foo() == "Foo"
assert fzm.foo("Groovy") == "FooGroovy"

A word of caution, methodKey is only available in the current development version (0.6-SNAPSHOT), while we are at it, let me show you what is in store for the soon to be released version. You probably have figured out by now that these proxies rely on java.lang.reflect.Proxy to do their thing, so they are bound by the laws that govern Proxy, but these guys want to be Groovy, so they automaticall implement the GroovyObject interface, which gives them access to the following groovylicious methods: 

  • getProperty
  • setProperty
  • methodMissing
  • propertyMissing (get mode)
  • propertyMissing (set mode)
  • getMetaClass
  • setMetaClass (read-only, can't change it)

By convention if a method implementation has not been given the proxy will call methodMissing, which by default throws an UnsupportedOperationException, this means the following code passes the green test

import static org.kordamp.groovy.util.ProxyOMatic.proxy

def shouldFail = { Class ex, code ->
try {
throw new RuntimeException()
}catch( Exception x ) {
assert x.class == ex

interface Foo { String foo() }

def f1 = proxy( Foo ) { }
shouldFail( UnsupportedOperationException ) {

What happens if you call a method for which not even a definition has been made in any of the proxied interfaces?

import static org.kordamp.groovy.util.ProxyOMatic.proxy

interface Foo { String foo() }

def f2 = proxy( Foo ) {
foo { -> bar() }
methodMissing { String name, value -> "oops" }
assert f2.foo() == "oops"
assert f2.bar() == "oops"

Properties work very much alike, for instance here is how you may expose a local variable as a property on the proxy

import static org.kordamp.groovy.util.ProxyOMatic.proxy

interface Foo { String foo() }

def f3 = proxy( Foo ) {
def count = 0
foo { -> count++ }
propertyMissing { String name -> count }
assert f3.foo() == 0
assert f3.foo() == 1
assert f3.count == 2

But you may define a whole set of properties by using a special properties node

import static org.kordamp.groovy.util.ProxyOMatic.proxy

interface Foo { String foo() }

def f4 = proxy( Foo ) {
foo { -> "${id}:${name}".toString() }

properties {
f4.name = "Duke"
assert f4.foo() == "1:Duke"

The properties node works for the 3 sources (Closures, Maps and Expandos). If you define a value for a property definition, then that value will be assigned as the initial value of the property, as you can atest by looking at how the id property was defined. You may intercept property access by defining setProperty/getProperty but there is a catch. You can't call them directly (at least not while testing inside a script) reason being that the enclosing script defines its own getProperty/setProperty, so whenever the closure that calls any of those method is called, it willactually call the script's methods, not the ones you defined. Regular classes don't have that problem, and if it is ambiguous you may qualify the call with this.Clearly that won't work as well (using this) so what now? proxies expose a read-only property named self, which pretty much works as this.

import static org.kordamp.groovy.util.ProxyOMatic.proxy

interface Foo { String foo( String n ) }

def f5 = proxy( Foo ) {
def props = [:]
foo { String n -> self.setProperty(n,n); n }
getProperty { String name -> props[name] }
setProperty { String name, value -> props[name] = value }
assert f5.name == null
assert f5.foo("name") == "name"
assert f5.name == "name"

You are probably thinking by now "proxies are great, but why go over all this hassle?" well here are some reasons 

  • You may pass an Expando or even a Map to a Groovy class that favors duck typing, sadly you can't do the same for a Java class that expects an specific type
  • Current proxy creation mechanisms in Groovy do not support overloaded methods
  • Groovy doesn't support inner class definitions (yet, anonymous inner classes are schedule for 1.7)

While we wait for inner class support, proxies are our best alternative to anonymous inner classes. Of course you can code a top level class instead, in order to avoid creating a proxy, but then your namespace may get cluttered by tiny classes meant for an specific point in your code.

Going back to Alex's suggestions, Proxy-o-Matic is very close. Now to figure out how to create proxies from abstract and concrete classes.

Microservices for Java, explained. Revitalize your legacy systems (and your career) with Reactive Microservices Architecture, a free O'Reilly book. Brought to you in partnership with Lightbend.


The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}