Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
interface A1{}
interface A2{}
class A implements A1, A2{}
def interfacesA = [] as Set 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 examine public fields and their types:

Code Block
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

...

Code Block
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:

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

...

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

To query a particular nested class , we must use a special syntax for the nested class name(eg, Character.UnicodeBlock):

Code Block
def cub= Class.forName('java.lang.Character$UnicodeBlock')
cub.Character.UnicodeBlock.fields.name.each{ println it } //to list all public constants

...

Code Block
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(', ')}"
}

...

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

//...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
}


Packages

...

Code Block
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 ] as Object[] ) == [:] 

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

Code Block
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

...

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

...

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

Code Block
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:

Code Block
[                          (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
}

...

Code Block
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

...

Code Block
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 )

...

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