Skip to: Site menu | Main content

Groovy 

      Download | Documentation | Developers | Community

An agile dynamic language for the Java Platform

JN3535-Reflection Add comment to Wiki View in Wiki Edit Wiki page Printable Version

We can examine classes in Groovy to find out information in the form of strings.

Examining Classes

To find out a class's name and superclasses:

class A{}
assert A.name == 'A'
assert new A().class.name == 'A'
assert A.class.name == 'A' //'class' is optionally used here

class B extends A{}
assert B.name == 'B'

class C extends B{}
def hierarchy= []
def s = C
while(s != null){ hierarchy << s.name; s= s.superclass }
assert hierarchy == [ 'C', 'B', 'A', 'java.lang.Object' ]

To examine the interfaces:

interface A1{}
interface A2{}
class A implements A1, A2{}
def interfacesA = [] as Set  //use a set because interfaces are unordered
A.interfaces.each{ interfacesA << it.name }
assert interfacesA == [ 'A1', 'A2', 'groovy.lang.GroovyObject' ] as Set

interface B1{}
class B extends A implements B1{}
def interfacesB = [] as Set
B.interfaces.each{ interfacesB << it.name }
assert interfacesB == [ 'B1' ] as Set
  //only immediately implemented interfaces are reported

We can check if a class is a class or an interface:

assert Observer.isInterface()
assert ! Observable.isInterface()

We can examine public fields and their types:

class A{
  def adyn //if no modifier, field is private
  String astr
  public apdyn
  public String apstr
  protected aqdyn
}
interface B1{}
interface B2{}
class B extends A implements B1, B2{
  def bdyn
  int bint
  public bpdyn
  public int bpint
  protected bqdyn
}
def dets = [] as Set
B.fields.each{ //public fields only
  dets << [ it.name, it.type.name ] //name of field and name of type
}
assert dets == [
  [ 'apstr', 'java.lang.String' ],
  [ 'apdyn', 'java.lang.Object' ],
  [ 'bpint', 'int' ],
  [ 'bpdyn', 'java.lang.Object' ],
  [ '__timeStamp', 'java.lang.Long' ], //added by Groovy
] as Set

We can look at a certain field of a class:

assert Math.fields.name as Set == [ 'E', 'PI' ] as Set
assert Math.class.getField('PI').toString() ==
  'public static final double java.lang.Math.PI'
assert Math.class.getField('PI').getDouble() == 3.141592653589793
  //we must know the type of the value

We can also look at the constructors and methods of a class:

assert HashMap.constructors.collect{ it.parameterTypes.name } as Set ==
  [ ['int'], [], ['java.util.Map'], ['int', 'float'] ] as Set
GroovyObject.methods.each{ println it }
  //to print full details of each method of a class
assert GroovyObject.methods.name as Set ==
  ['invokeMethod', 'getMetaClass', 'setMetaClass',
   'setProperty', 'getProperty'] as Set
assert GroovyObject.getMethod('getMetaClass').toString() ==
 'public abstract groovy.lang.MetaClass groovy.lang.GroovyObject.getMetaClass()'

Some code to find out all the getters for a class:

getters= {
  it.methods.name.findAll{ it =~ /^get[A-Z]/ }.
        collect{ it[3].toLowerCase()+it[4..-1] }.join(', ')
}
assert getters( GroovyObject ) == 'metaClass, property'

To see all nested classes for a particular class (eg, of Character):

assert Character.classes.name as Set ==
  [ 'java.lang.Character$Subset', 'java.lang.Character$UnicodeBlock' ] as Set

To query a particular nested class (eg, Character.UnicodeBlock):

Character.UnicodeBlock.fields.name.each{ println it }
  //to list all public constants

Reflecting the Reflection classes themselves

We can use reflection on the reflection classes themselves. For example:

assert Class.methods[0].class == java.lang.reflect.Method
    //find the class of any method of any class...
java.lang.reflect.Method.methods.each{ println it.name }
    //...then find its method names...

//...to help us build a custom-formatted listing of method details
HashMap.class.methods.each{
  println """$it.name( ${it.parameterTypes.name.join(', ')} ) returns \
$it.returnType.name ${it.exceptionTypes.size()>0?'throws ':''}\
${it.exceptionTypes.name.join(', ')}"""
}

We can look at the modifiers of methods and classes:

import java.lang.reflect.Modifier
Modifier.methods.name.sort{}.each{ println it }
  //use reflection on the reflection classes themselves...

//...to help us build a custom-formatted listing of modifier details
[           (ArrayList.getMethod( 'remove', [Object] as Class[] )):
                                              [ 'public' ] as Set,
  (Collections.getMethod( 'synchronizedList', [List] as Class[] )):
                                              [ 'public', 'static' ] as Set,
                                      (Math): [ 'public', 'final' ] as Set,
                               (ClassLoader): [ 'public', 'abstract' ] as Set,
 ].each{ key, val->
  def m= key.modifiers
  def mods= [
    ({Modifier.isPublic(it)}):       'public',
    ({Modifier.isProtected(it)}):    'protected',
    ({Modifier.isPrivate(it)}):      'private',
    ({Modifier.isInterface(it)}):    'interface',
    ({Modifier.isAbstract(it)}):     'abstract',
    ({Modifier.isFinal(it)}):        'final',
    ({Modifier.isStatic(it)}):       'static',
    ({Modifier.isVolatile(it)}):     'volatile',
    ({Modifier.isNative(it)}):       'native',
    ({Modifier.isStrict(it)}):       'strict',
    ({Modifier.isSynchronized(it)}): 'synchronized',
    ({Modifier.isTransient(it)}):    'transient',
  ].collect{ k, v-> k(m)? v: null } as Set
  mods.removeAll( [null] )
  assert mods == val
}

Manipulating Objects

When a class is unknown at compile time (eg, we only have a string representation of a class name), we can use reflection to create objects:

assert Class.forName("java.util.HashMap").newInstance() == [:]

def constructor = Class.forName("java.util.HashMap").
                                   getConstructor( [ int, float ] as Class[] )
assert constructor.toString() == 'public java.util.HashMap(int,float)'
assert constructor.newInstance( 12, 34.5f ) == [:]

We can examine and change public fields for a class refering using a String for the name:

class A{
  public value1
  protected value2
  A( int v ){ value1= v; value2 = v }
}
def a= new A( 100 )
assert A.getField( 'value1' ).get( a ) == 100 //public fields only

try{ A.getField( 'value2' ).get( a ); assert false }
catch(Exception e){ assert e instanceof NoSuchFieldException }

A.getField( 'value1' ).set( a, 350 )
assert a.value1 == 350

And we can call methods using a string for the name:

assert String.getMethod( 'concat', [ String ] as Class[] ).
  invoke( 'Hello, ', [ 'world!' ] as Object[] ) == 'Hello, world!'

Working with Arrays

We can examine and manipulate arrays. To enquire the public array fields of a class:

class A{
  public boolean alive
  public int[] codes
  public Date[] dates
  protected boolean[] states
}
//find all public array fields
def pubFields= new A().class.fields.findAll{ it.type.isArray() }.
                                       collect{ [it.name, it.type.name] }
assert pubFields == [
  [ 'codes', '[I' ], //'[I' means array of int
  [ 'dates', '[Ljava.util.Date;' ], //means array of object java.util.Date
]

To enquire the component type/s of an array:

[             (int[]): [ '[I', 'int' ],
             (Date[]): [ '[Ljava.util.Date;', 'java.util.Date' ],
  (new Date[6].class): [ '[Ljava.util.Date;', 'java.util.Date' ],
                                                           //instantiated class
         (String[][]): [ '[[Ljava.lang.String;', '[Ljava.lang.String;' ],
].each{
  k, v -> assert [ k.name, k.componentType.name ] == v
}

We can create and copy arrays when their component type and size is unknown at compile time:

import java.lang.reflect.Array
def a1 =  [55, 66] as int[]

//component type and size unknown at compile time...
def a2 = Array.newInstance( a1.class.componentType, a1.size() * 2 )
assert a2.class.componentType == int
assert a2.size() == 4
System.arraycopy( a1, 0, a2, 0, a1.size() )
assert a2 as List == [55, 66, 0, 0] as List

We can create multi-dimensional arrays in a similar way, where component type and array sizes can be unknown at compile time:

import java.lang.reflect.Array

//assertion checking code...
assert1D= {x,y->
  assert x.size() == y.size()
  for( int i: x.size() - 1 ) assert x[ i ] == y[ i ]
}
assert2D= {x,y->
  assert x.size() == y.size()
  for( int i: x.size() - 1 ){
    assert x[ i ].size() == y[ i ].size()
    for( int j: x[ i ].size() - 1 ) assert x[ i ][ j ] == y[ i ][ j ]
  }
}

//each is a 1-D int array with 3 elts
def a0= new char[ 3 ]
def a1= Array.newInstance( char, 3 )
def a2= Array.newInstance( char, [ 3 ] as int[] )
assert1D( a0, a1 )
assert1D( a0, a2 )

//both are a 2-D 3x4 array of String elts
def b0= new String[3][4]
def b1= Array.newInstance( String, [ 3, 4 ] as int[] )
assert2D( b0, b1 )

//both are a 2-D array of 6 char arrays, with undefined tail dimension
def c0 = new char[6][]
def c1 = Array.newInstance( char[], [ 6 ] as int[] )
assert1D( c0, c1 )

We can use set() and get() to copy the contents of one array index to another:

import java.lang.reflect.Array
def a= [ 12, 78 ] as int[], b= new int[ 4 ]
Array.set( b, 0, Array.get( a, 0 ) )
assert b[ 0 ] == 12

This tutorial is loosely based on Sun's tutorial on Java Reflection, but using Groovy code instead.