Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Groovy Goodness: Creating an Extra Method Supporting Named Arguments

DZone's Guide to

Groovy Goodness: Creating an Extra Method Supporting Named Arguments

Groovy 2.5.0 introduces the @NamedVariant annotation to help with named arguments. Come find out exactly how to use it.

· Java Zone ·
Free Resource

The CMS developers love. Open Source, API-first and Enterprise-grade. Try BloomReach CMS for free.

Groovy supports named arguments for methods. In fact, Groovy collects all named arguments (defined using the name followed by a : and the value) into a Map. The Map must be the first parameter of the method to make it all work. Since Groovy 2.5.0, we can use the @NamedVariant AST transformation annotation to let Groovy create a method where the first parameter is a Map that supports named arguments for an existing method. The existing method is still available, but Groovy adds an extra method to our generated class.

By default, Groovy will make the first parameters of the original method part of the new method for supporting named arguments. If the first parameters are a class type, then the properties of the class can be used as named arguments. We can also explicitly define which parameters of our original method should be named arguments using the annotations @NamedParam and @NamedDelegate. These annotations need to be defined for each parameter. The newly created method by the AST transformation invokes the original method.

In the following example, we use @NamedVariant for the ConferenceMaker.copy method:

import groovy.transform.NamedVariant
import groovy.transform.NamedDelegate

class Conference {
    String name, location
}

class ConferenceMaker {
    // First parameter's properties will be the 
    // named arguments we can use. Optionally
    // we could add @NamedDelegate before the
    // parameter definition.
    @NamedVariant
    static Conference copy(Conference conf) {
        new Conference(name: conf.name, location: conf.location)
    }

    // We use @NamedDelegate to let the properties of the
    // second parameter be named arguments for the newly
    // created method.
    @NamedVariant
    static Conference copy(boolean upper, @NamedDelegate Conference conf) {
        upper ? new Conference(name: conf.name.toUpperCase(), location: conf.location.toUpperCase())
              : new Conference(name: conf.name, location: conf.location)
    }
}

// All properties of the type of the argument (Conference)
// can be used as named arguments.
def greach = ConferenceMaker.copy(name: 'Greach', location: 'Madrid')

assert greach.name == 'Greach'
assert greach.location == 'Madrid'

// Parameter upper in original method definition is not
// part of the named arguments.
def gr8conf = ConferenceMaker.copy(name: 'Gr8Conf', true, location: 'Copenhagen')

assert gr8conf.name == 'GR8CONF'
assert gr8conf.location == 'COPENHAGEN'


In the next example, we use @NamedParam to define the parameters that need to be used as named arguments. We can use the attribute required to indicate the named argument that must be provided; otherwise, an error is thrown:

import static groovy.test.GroovyAssert.shouldFail

import groovy.transform.NamedVariant
import groovy.transform.NamedParam

class Conference {
    String name, location
}

class ConferenceMaker {
    // Using @NamedVariant to create
    // also an implementation of the make 
    // method with a Map argument to 
    // support named arguments.
    @NamedVariant
    static Conference make(
        @NamedParam(required = true) String name, 
        @NamedParam String location) {

        new Conference(name: name, location: location)
    }
}

// The named argument 'name' is required,
// 'location' is optional.
def gr8Conf = ConferenceMaker.make(name: 'Gr8Conf')

assert gr8Conf.name == 'Gr8Conf'

def required = shouldFail(AssertionError) {
    // If we don't specify the required named
    // argument an exception is thrown.
    ConferenceMaker.make(location: 'Copenhagen')
}
assert required.message.contains("Missing required named argument 'name'.")

// With named arguments the order of the arguments
// is not important.
def gr8ConfEU = ConferenceMaker.make(location: 'Copenhagen', name: 'Gr8Conf')

assert gr8ConfEU.name == 'Gr8Conf'
assert gr8ConfEU.location == 'Copenhagen'

shouldFail(MissingMethodException) {
    // Because the original make method is
    // invoked by the generated named arguments make 
    // method, so we get an exception when
    // the type of the named argument is incorrect.
    ConferenceMaker.make(name: 'G' as char)
}


Written with Groovy 2.5.0.

BloomReach CMS: the API-first CMS of the future. Open-source & enterprise-grade. - As a Java developer, you will feel at home using Maven builds and your favorite IDE (e.g. Eclipse or IntelliJ) and continuous integration server (e.g. Jenkins). Manage your Java objects using Spring Framework, write your templates in JSP or Freemarker. Try for free.

Topics:
java ,groovy ,annotation ,feature ,arguments ,map ,method

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}