Over a million developers have joined DZone.

Groovy Goodness: Using Package Scoped Methods, Fields and Classes

· Java Zone

Navigate the Maze of the End-User Experience and pick up this APM Essential guide, brought to you in partnership with CA Technologies

Groovy uses the Java package protected scope visibility rules to turn methods and classes into public scoped variants and fields into properties. In Java package scope visibility is applied to any field, method or class that has no explicit scope set, like publicprotected or private. To get the same scope in Groovy we must use the AST transformation @PackageScope to explicitly define a field, method or class to have package scope.

In the following code we want to define a simple User class with an accessor method to change the username property. Only classes in the same package as the User class must be allowed to use this method. The method may not be invoked by classes in other packages or subclasses.

package com.mrhaki.groovy.domain

import groovy.transform.*

class User {
    private String username
    
    User(final String username) {
        this.username = username
    }

    @PackageScope 
    void changeUsername(final String newUsername) {
        this.username = newUsername
    }

    String getUsername() {
        username
    }
}

If we create a new class in another package and we want to invoke the method changeUsername() we get an error if we use @CompileStatic. We can also write a Java class to use our Groovy User class and then the compiler will also give an error.

// File: App.groovy
package com.mrhaki.groovy.app

import groovy.transform.*
import com.mrhaki.groovy.domain.User

@CompileStatic
def changeUsername() {
    final User user = new User('mrhaki')
    user.changeUsername 'Hubert A. Klein Ikkink'
}

changeUsername()

If we run the script with Groovy we get an IllegalAccessError:

$ groovyc User.groovy
$ groovy App.groovy
Caught: java.lang.IllegalAccessError: tried to access method com.mrhaki.groovy.domain.User.changeUsername(Ljava/lang/String;)V from class com.mrhaki.groovy.app.App
java.lang.IllegalAccessError: tried to access method com.mrhaki.groovy.domain.User.changeUsername(Ljava/lang/String;)V from class com.mrhaki.groovy.app.App
at com.mrhaki.groovy.app.App.changeUser(App.groovy:10)
at com.mrhaki.groovy.app.App.run(App.groovy:13)

If we write a Java class to invoke the package scoped method we get an error when we compile the class:

package com.mrhaki.groovy.app;

import com.mrhaki.groovy.domain.User;

public class Application {
    public static void main(final String[] args) {
        final User user = new User("mrhaki");
        user.changeUsername("Hubert A. Klein Ikkink");
    }
}

The compilation error:

$ javac -cp . Application.java
Application.java:8: error: changeUsername(String) is not public in User; cannot be accessed from outside package
user.changeUsername("Hubert A. Klein Ikkink");
^
1 error

The @PackageScope annotation can be used at class, field and method level. We can also add an argument to the annotation if applied at class level. We can then use the constants in groovy.transform.PackageScopeTarget to make all fields package scoped with FIELDS, all methods withMETHODS and the class with CLASS.

Code written with Groovy 2.2.1.

Thrive in the application economy with an APM model that is strategic. Be E.P.I.C. with CA APM.  Brought to you in partnership with CA Technologies.

Topics:

Published at DZone with permission of Hubert Klein Ikkink, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
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.
Subscribe

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

{{ parent.tldr }}

{{ parent.urlSource.name }}