Javadoc API Documentation
One of the things I have always liked about Java is the ready availability of its standard API documentation. Fortunately, Groovy's GDK extensions and the Groovy distribution classes are similarly well documented. I find myself frequently using these generated HTML pages to discover new APIs that are available to me in the standard Groovy distribution.
Object.toString()
Groovy inherits positive Java features including the ability for object's to easily provide their state via a standard approach by explicitly overriding Object.toString(). This is a valuable tactic in Java (see Item 9 in Effective Java) and continues to be valuable in Groovy. The most significant downside of the
toString()
approach is that its value relies completely on the author of the class. There are several things a developer can do to make more effective toString() methods, but there's no guarantee any of those things have been done.In fact, there's no guarantee that a
toString()
metho for a given class whose instance is being used even provides an explicit overridden toString()
method. The next code listing is of a simple Groovy class that fails to explicitly override toString()
./** * Simple Groovy class used in demonstration of Groovy detecting methods without * explicitly overridden inspect() method, toString() method, or dump() method. * * @author Dustin */ class Person { String lastName String firstName Person(final String newLastName, final String newFirstName) { this.lastName = newLastName this.firstName = newFirstName } }
When an instance of this simple Groovy class has it's
toString()
invoked (whether implicitly or explicitly), the output is the same as for a Java class with no explicit toString()
(and as defined by Object.toString() Javadoc). It will look something like this:Person@149eb9f
Object.inspect()
Groovy's GDK Object class specifies an inspect() method for which the Javadoc states: "Inspects returns the String that matches what would be typed into a terminal to create this object." I rarely find this method very useful, but do cover it briefly here.
The
inspect()
method is often not implemented. When this is the case, the same object's toString()
method is invoked. If the object's toString()
method is not explicitly implemented, Java's Object.toString() is invoked.This is demonstrated in the next screen snapshots for the Java Date class and for the Groovy AntBuilder class (the latter of which does not have an explicit
inspect()
or an explicit toString()
implementation).The Groovy
Object.inspect()
method suffers the same weakness as Java's (and Groovy's) Object.toString()
: the method is only as good as what the author of the class implemented (which might be nothing). In the worst case, an author might not have overridden the inspect()
method or the toString()
method (as was the case for AntBuilder
in the example above) and then very little information is provided.The next code listing is for a simple Groovy class that implements
toString()
but fails to implement inspect()
.PersonWithToString.groovy
/** * Simple Groovy class used in demonstration of Groovy detecting methods without * explicitly overridden inspect() method, but with an explicitly overridden * toString() method. * * @author Dustin */ class PersonWithToString { String lastName String firstName PersonWithToString(final String newLastName, final String newFirstName) { this.lastName = newLastName this.firstName = newFirstName } @Override String toString() { return this.firstName + " " + this.lastName; } }
If the above class is instantiated, it will return the same String whether
toString()
is explicitly or implicitly called or if inspect()
is called. For example, suppose the class is instantiated and invoked as shown in the next code listing.def person2 = new PersonWithToString("Rubble", "Barney") doToString(person2) doInspect(person2) def doToString(obj) { println "toString(): ${obj}\n" } def doInspect(obj) { // Inspect println "inspect(): ${obj.inspect()}\n" }
The output when the above is executed looks like this:
toString(): Barney Rubble inspect(): Barney Rubble
We can explicitly override
inspect()
to make it useful and to meet its advertised reason for existence. An example of how this might be done is demonstrated in the next code listing.PersonWithInspect.groovy
/** * Simple Groovy class used in demonstration of Groovy detecting methods with * explicitly overridden inspect() method but without explicitly overridden * dump() method. * * @author Dustin */ class PersonWithInspect { String lastName String firstName PersonWithInspect(final String newLastName, final String newFirstName) { this.lastName = newLastName this.firstName = newFirstName } @Override String toString() { return this.firstName + " " + this.lastName } @Override String inspect() { return "new Person(" + this.lastName + ", " + this.firstName + ")" } }
When this code has its
toString()
and inspect()
methods called similarly to how the last Groovy class's methods were called, the output is now different:toString(): Barney Rubble inspect(): new Person(Rubble, Barney)
Overriding the
inspect()
method made it more useful and made it so that it not only provides more/different information than already available via toString()
, but also helped it achieve the declared (in comments) reason for its existence: to "return the String that matches what would be typed into a terminal to create this object."Object.dump()
The Object.dump() method often provides more details than
Object.inspect()
. Its Javadoc documentation states about this method: "Generates a detailed dump string of an object showing its class, hashCode and fields."The next screen snapshot shows what the
dump
method displays for a new Java Date
instance.The next screen snapshot shows the
AntBuilder.dump()
results, which are far more descriptive than the AntBuilder.inspect()
method provided.The
Object.dump()
method works even when the class whose instance it is being invoked against has not even overridden the dump
method. For example, suppose that the Groovy class PersonWithInspect
used above had dump()
called against it. Even though that class never explicitly defines such a method, calling it leads to results like this:<PersonWithInspect@1bbd7b2 lastName=Rubble firstName=Barney>
Although no
dump()
method was explicitly written, calling dump()
worked and returned the name of the class with its hash code and with its two attributes (lastName and firstName).A significant advantage of Groovy's
Object.dump()
is that it does provide more details about an object's current state without the class author implementing or overriding any specific methods. A Groovy developer is still free to override dump()
if so desired, but this is probably rarely needed or even recommended because the existing dump()
method is a reasonable implementation.The next code listing provides a simple Groovy class in which the author has chosen (perhaps poorly) to explicitly override
Object.dump()
.PersonWithDump.groovy
/** * Simple Groovy class used in demonstration of Groovy detecting methods with * explicitly overridden dump() method. This is typically not necessary or even * desirable as the dump() method is standardly supported. * * @author Dustin */ class PersonWithDump { String lastName String firstName PersonWithDump(final String newLastName, final String newFirstName) { this.lastName = newLastName this.firstName = newFirstName } @Override String toString() { return this.firstName + " " + this.lastName } @Override String inspect() { return "new Person(" + this.lastName + ", " + this.firstName + ")" } @Override String dump() { return toString() } }
When an instantiation of the above Groovy class has its
toString()
, inspect()
, and dump()
methods called, the output appears as follows.toString(): Barney Rubble inspect(): new Person(Rubble, Barney) dump(): Barney Rubble
The above example demonstrates that
dump()
can be overridden if desired. In this exmaple, it was overridden to simply provide the result of the toString(), which is obviously less information than the default dump()
implementation provides.Before leaving discussion of the Groovy's
dump()
method, one might ask oneself, "How, or even does, it work for instances of Java classes used in a Groovy context?" That's a great question. The answer to it begins with the next code listing, which shows a small piece of code that instantiates a Java String, queries it for its class and attempts to dump its contents.def string = "Dustin was here." println string.class doDump(string) def doDump(obj) { println "dump(): ${obj.dump()}\n" }
The output when the above code is executed is shown next.
class java.lang.String dump(): <java.lang.String@796944de value=Dustin was here. offset=0 count=16 hash=2036942046>
Nice! Even the instantiated class, which is unsurprisingly treated as a Java String, has support for the Groovy-provided
dump()
method. That is the beauty or black magic of Groovy's dynamic metadata support in action.Direct Reflection
So far, I've looked at detection of what a particular Groovy class has to offer via some ways that are standard to Java as well (Javadoc documentation and
Object.toString()
) and have also looked at two approaches that are specific to Groovy (
Object.inspect()
and Object.dump()
). Another way to inspect a particular object in Groovy is to use Java's reflection capabilities. Groovy makes it a little easier to use Java's reflection capabilities directly. This is a powerful technique that can require more effort than some of the other approaches, but can be used programatically and can be used to find a plethora of details about a given object's underlying class, method, and attribute structure.The next code listing demonstrates access of a Groovy class's name, methods names, and fields names via direct Java reflection on the instance of class
PersonWithDump
shown above.def doReflection(obj) { println("Reflection:") println "\tClass Name: ${obj.class.name}" def methods = obj.class.declaredMethods def methodsNames = new StringBuilder() methods.each { methodsNames << it.name << " " } println "\tMethods Names: ${methodsNames}" def fields = obj.class.declaredFields def fieldsNames = new StringBuilder() fields.each { fieldsNames << it.name << " " } println "\tFields Names: ${fieldsNames}" }
When the above reflection-based code is executed against an instance of
PersonWithDump
, the output appears as shown next.Reflection: Class Name: PersonWithDump Methods Names: invokeMethod getMetaClass setMetaClass inspect $getCallSiteArray $createCallSiteArray class$ $getStaticMetaClass $get$$class$groovy$lang$MetaClass this$dist$invoke$2 $get$$class$java$lang$String this$dist$set$2 this$dist$get$2 super$1$wait super$1$wait super$1$wait super$1$toString super$1$notify super$1$notifyAll super$1$getClass super$1$equals super$1$clone super$1$hashCode super$1$finalize getLastName setLastName getFirstName setFirstName $get$$class$PersonWithDump setProperty getProperty toString dump Fields Names: lastName firstName $staticClassInfo metaClass __timeStamp __timeStamp__239_neverHappen1295139333183 $callSiteArray $class$groovy$lang$MetaClass $class$java$lang$String $class$PersonWithDump
This example has shown that reflection can be easily applied directly in Groovy as it is applied in Java. In fact, Groovy's use of Java reflection even supports the identification of internal Groovy-only metadata methods and fields.
Object.getProperties()
Groovy offers an additional convenience method for determining information on a Groovy class's properties. The output shown next is what one can expect to see when an instance has its
getProperties()
method called either by calling the method explicitly or using Groovy's syntactic sugar to access it simply with .properties
.[class:class PersonWithDump, firstName:Barney, lastName:Rubble, metaClass:org.codehaus.groovy.runtime.HandleMetaClass@14dd758[groovy.lang.MetaClassImpl@14dd758[class PersonWithDump]]]
Note that no
getProperties()
method was explicitly provided in the PersonWithDump
class, but calling person4.properties
still leads to the properties information being made available in name/value pairs. Like Object.dump()
, Object.getProperties()
provides useful details without needing to specifically implement/override that method.Does this nice Groovy
getProperties()
approach work for Java classes used in Groovy? To find out, we start with this code listing for a simple Java class called JavaPerson
.JavaPerson.java
/** * Simple Java class with no set methods for its data members. * * @author Dustin */ public class JavaPerson { private final String lastName; private final String firstName; public JavaPerson(final String newLastName, final String newFirstName) { this.lastName = newLastName; this.firstName = newFirstName; } public String getLastName() { return this.lastName; } public String getFirstName() { return this.firstName; } }
The Java class just shown does not have an explicitly overridden
toString()
method. Because it's not Groovy, it doesn't override inspect()
either. Of course, it is not typical to override Object.dump()
or Object.getProperties()
in Groovy classes, so it is really not surprising that this Java class does not override those either. Now, let's suppose that some simple Groovy code invoked these methods on an instance of the Java class JavaPerson
. This might look like the code shown in the next code listing.def person5 = new JavaPerson("Rubble", "Barney") doToString(person5) doInspect(person5) doReflection(person5) doDump(person5) doProperties(person5) // The methods shown above with names starting with "do" have // been defined in previous code listings in this post, but // doProperties is first shown here. def doProperties(obj) { println ".properties: ${obj.properties}" }
When the code is executed in Groovy, the results on the instance of the Java class are as shown next.
toString(): JavaPerson@18622f3 inspect(): JavaPerson@18622f3 dump(): <JavaPerson@18622f3 lastName=Rubble firstName=Barney> Reflection: Class Name: JavaPerson Methods Names: getLastName getFirstName Fields Names: lastName firstName dump(): &lr;JavaPerson@18622f3 lastName=Rubble firstName=Barney> .properties: [class:class JavaPerson, firstName:Barney, lastName:Rubble]
As expected,
toString()
and inspect()
are not very interesting or useful because neither is implemented/overridden. However, dump()
and .properties
(Groovy approaches) are useful. Not surprisingly, reflection is useful on the Java class as well.javap
I have blogged before on the utility of the javap tool provided with the HotSpot SDK. It is easy to compile a Groovy class or script to a
.class
file explicitly with the groovyc command and then javap can be applied against that generated .class
file.The next screen snapshot demonstrates compiling the
PersonWithInspect
Groovy class shown above with groovyc
and then running javap
against the generated PersonWithInspect.class
file.There are numerous methods in the output that were not explicitly part of the class's definition. This
javap
output is a nice mechanism for peeking into the methods the Groovy class provides and the types of parameters each method expects.As an interesting side note here, let's look at what the
javap
output looks like for a Java class compiled via traditional javac as compared to the javap
output for a Java class compiled via groovyc
. To illustrate this, the pure Java JavaPerson
class will be compiled both with javac
(Java compiling) and with groovyc
(Groovy/Java combination compilation). The output from running the javap
tool against each generated .class
file is then displayed in the screen snapshots.javap Output for javac-Generated JavaPerson
javap Output for groovyc-Generated JavaPerson
The two images just shown demonstrate quite different output. The output from
javap
for the javac
-compiled Java class shows the methods we expected: a constructor and two "get" methods for the two attributes. We can also see that the class simply extends the Java Object
class that is extended directly or indirectly by all Java classes. The output from the groovyc
-compiled Java class shows that it not only extends Object
, but that it also implements the groovy.lang.GroovyObject interface. We can also observe that there are many more methods available in the version compiled with groovyc
, including the automatically added "set" methods and the "meta" infrastructure methods added by Groovy.groovy.inspect.Inspector
Groovy makes its introspection capabilities accessible via a single interface encapsulated within the groovy.inspect.Inspector class. The following code snippet shows how this handy class might be used to easily access data about a particular object (whichever object is accepted in the method call under the name 'obj').
def doInspector(obj) { def inspector = new groovy.inspect.Inspector(obj) def inspectorReport = new StringBuilder() inspectorReport <<<< "Object under inspection " inspectorReport <<<< (inspector.isGroovy() ? "IS" : "is NOT") <<<< " Groovy!\n" inspectorReport <<<< "METHODS\n" def methods = inspector.methods methods.each { inspectorReport <<<< "\t" <<<< it.toString() <<<< "\n" } inspectorReport <<<< "\nMETA METHODS\n" def metaMethods = inspector.metaMethods metaMethods.each { inspectorReport <<<< "\t" <<<< it.toString() <<<< "\n" } inspectorReport <<<< "\nPROPERTY INFO\n" def properties = inspector.propertyInfo properties.each { inspectorReport <<<< "\t" <<<< it.toString() <<<< "\n" } println inspectorReport }
If the above code is invoked and an instance of
PersonWithInspect
is passed to it, the output looks like the following:Object under inspection IS Groovy! METHODS [JAVA, public, PersonWithInspect, Object, invokeMethod, String, Object, ] [JAVA, public, PersonWithInspect, MetaClass, getMetaClass, , ] [JAVA, public, PersonWithInspect, void, setMetaClass, MetaClass, ] [JAVA, public, PersonWithInspect, String, inspect, , ] [JAVA, public, PersonWithInspect, Object, this$dist$invoke$2, String, Object, ] [JAVA, public, PersonWithInspect, void, this$dist$set$2, String, Object, ] [JAVA, public, PersonWithInspect, Object, this$dist$get$2, String, ] [JAVA, public, PersonWithInspect, void, super$1$wait, long, int, ] [JAVA, public, PersonWithInspect, void, super$1$wait, long, ] [JAVA, public, PersonWithInspect, void, super$1$wait, , ] [JAVA, public, PersonWithInspect, String, super$1$toString, , ] [JAVA, public, PersonWithInspect, void, super$1$notify, , ] [JAVA, public, PersonWithInspect, void, super$1$notifyAll, , ] [JAVA, public, PersonWithInspect, Class, super$1$getClass, , ] [JAVA, public, PersonWithInspect, boolean, super$1$equals, Object, ] [JAVA, public, PersonWithInspect, Object, super$1$clone, , ] [JAVA, public, PersonWithInspect, int, super$1$hashCode, , ] [JAVA, public, PersonWithInspect, void, super$1$finalize, , ] [JAVA, public, PersonWithInspect, String, getLastName, , ] [JAVA, public, PersonWithInspect, void, setLastName, String, ] [JAVA, public, PersonWithInspect, String, getFirstName, , ] [JAVA, public, PersonWithInspect, void, setFirstName, String, ] [JAVA, public, PersonWithInspect, void, setProperty, String, Object, ] [JAVA, public, PersonWithInspect, Object, getProperty, String, ] [JAVA, public, PersonWithInspect, String, toString, , ] [JAVA, public final native, Object, void, wait, long, InterruptedException] [JAVA, public final, Object, void, wait, , InterruptedException] [JAVA, public final, Object, void, wait, long, int, InterruptedException] [JAVA, public, Object, boolean, equals, Object, ] [JAVA, public native, Object, int, hashCode, , ] [JAVA, public final native, Object, Class, getClass, , ] [JAVA, public final native, Object, void, notify, , ] [JAVA, public final native, Object, void, notifyAll, , ] [JAVA, public, PersonWithInspect, PersonWithInspect, PersonWithInspect, String, String, ] META METHODS [GROOVY, public, Object, Collection, collect, Collection, Closure, n/a] [GROOVY, public, Object, List, getMetaPropertyValues, , n/a] [GROOVY, public, Object, Object, eachWithIndex, Closure, n/a] [GROOVY, public, Object, void, print, PrintWriter, n/a] [GROOVY, public, Object, void, addShutdownHook, Closure, n/a] [GROOVY, public, Object, Iterator, iterator, , n/a] [GROOVY, public static, Object, void, sleep, long, n/a] [GROOVY, public, Object, Object, inject, Object, Closure, n/a] [GROOVY, public, Object, int, findLastIndexOf, Closure, n/a] [GROOVY, public, Object, void, setMetaClass, MetaClass, n/a] [GROOVY, public, Object, boolean, any, Closure, n/a] [GROOVY, public, Object, Object, use, [Ljava.lang.Object;, n/a] [GROOVY, public, Object, boolean, every, , n/a] [GROOVY, public, Object, void, println, PrintWriter, n/a] [GROOVY, public, Object, MetaClass, getMetaClass, , n/a] [GROOVY, public, Object, Collection, split, Closure, n/a] [GROOVY, public, Object, Collection, findAll, Closure, n/a] [GROOVY, public, Object, List, findIndexValues, Number, Closure, n/a] [GROOVY, public, Object, void, printf, String, Object, n/a] [GROOVY, public, Object, MetaProperty, hasProperty, String, n/a] [GROOVY, public, Object, Object, asType, Class, n/a] [GROOVY, public, Object, String, sprintf, String, Object, n/a] [GROOVY, public, Object, Object, getAt, String, n/a] [GROOVY, public, Object, List, collect, Closure, n/a] [GROOVY, public, Object, boolean, every, Closure, n/a] [GROOVY, public, Object, Collection, grep, Object, n/a] [GROOVY, public, Object, String, dump, , n/a] [GROOVY, public, Object, int, findIndexOf, int, Closure, n/a] [GROOVY, public, Object, Object, use, Class, Closure, n/a] [GROOVY, public, Object, Object, identity, Closure, n/a] [GROOVY, public, Object, Map, getProperties, , n/a] [GROOVY, public, Object, void, println, , n/a] [GROOVY, public, Object, Object, invokeMethod, String, Object, n/a] [GROOVY, public, Object, List, findIndexValues, Closure, n/a] [GROOVY, public, Object, boolean, is, Object, n/a] [GROOVY, public, Object, int, findIndexOf, Closure, n/a] [GROOVY, public, Object, String, inspect, , n/a] [GROOVY, public, Object, boolean, asBoolean, , n/a] [GROOVY, public, Object, Object, with, Closure, n/a] [GROOVY, public, Object, boolean, any, , n/a] [GROOVY, public, Object, void, printf, String, [Ljava.lang.Object;, n/a] [GROOVY, public, GroovyObject, MetaClass, getMetaClass, , n/a] [GROOVY, public, Object, void, println, Object, n/a] [GROOVY, public, Object, MetaClass, metaClass, Closure, n/a] [GROOVY, public, Object, List, respondsTo, String, n/a] [GROOVY, public, Object, Object, each, Closure, n/a] [GROOVY, public, Object, Object, find, Closure, n/a] [GROOVY, public, Object, boolean, isCase, Object, n/a] [GROOVY, public, Object, void, print, Object, n/a] [GROOVY, public, Object, void, putAt, String, Object, n/a] [GROOVY, public static, Object, void, sleep, long, Closure, n/a] [GROOVY, public, Object, int, findLastIndexOf, int, Closure, n/a] [GROOVY, public, Object, String, toString, , n/a] [GROOVY, public, Object, Object, use, List, Closure, n/a] [GROOVY, public, Object, List, respondsTo, String, [Ljava.lang.Object;, n/a] [GROOVY, public, Object, String, sprintf, String, [Ljava.lang.Object;, n/a] PROPERTY INFO [GROOVY, public, n/a, Class, class, class PersonWithInspect] [GROOVY, public, n/a, String, firstName, "Barney"] [GROOVY, public, n/a, String, lastName, "Rubble"] [GROOVY, public, n/a, MetaClass, metaClass, org.codehaus.groovy.runtime.HandleMetaClass@e53220[groovy.lang.MetaClassImpl@e53220[class PersonWithInspect]]]
There is significant data provided by Inspector. The "GROOVY" or "JAVA" portions indicate the origin of the field or method (Groovy or Java source code).
Out of curiosity, what does Inspector report for a Java class compiled with
groovyc
(or compiled implicitly when accessed by a Groovy script)? The following output shows what Inspector reports (including the fact that the underlying class is NOT Groovy, though there are Groovy methods added).Object under inspection is NOT Groovy! METHODS [JAVA, public, JavaPerson, String, getLastName, , ] [JAVA, public, JavaPerson, String, getFirstName, , ] [JAVA, public final native, Object, void, wait, long, InterruptedException] [JAVA, public final, Object, void, wait, , InterruptedException] [JAVA, public final, Object, void, wait, long, int, InterruptedException] [JAVA, public, Object, boolean, equals, Object, ] [JAVA, public, Object, String, toString, , ] [JAVA, public native, Object, int, hashCode, , ] [JAVA, public final native, Object, Class, getClass, , ] [JAVA, public final native, Object, void, notify, , ] [JAVA, public final native, Object, void, notifyAll, , ] [JAVA, public, JavaPerson, JavaPerson, JavaPerson, String, String, ] META METHODS [GROOVY, public, Object, List, collect, Closure, n/a] [GROOVY, public, Object, Map, getProperties, , n/a] [GROOVY, public, Object, boolean, every, , n/a] [GROOVY, public, Object, void, print, Object, n/a] [GROOVY, public, Object, boolean, any, , n/a] [GROOVY, public, Object, MetaClass, metaClass, Closure, n/a] [GROOVY, public static, Object, void, sleep, long, Closure, n/a] [GROOVY, public, Object, String, inspect, , n/a] [GROOVY, public, Object, int, findLastIndexOf, int, Closure, n/a] [GROOVY, public, Object, Collection, split, Closure, n/a] [GROOVY, public, Object, boolean, asBoolean, , n/a] [GROOVY, public, Object, Object, use, Class, Closure, n/a] [GROOVY, public, Object, boolean, every, Closure, n/a] [GROOVY, public, Object, void, println, Object, n/a] [GROOVY, public, Object, List, getMetaPropertyValues, , n/a] [GROOVY, public, Object, String, sprintf, String, [Ljava.lang.Object;, n/a] [GROOVY, public, Object, int, findIndexOf, Closure, n/a] [GROOVY, public, Object, int, findLastIndexOf, Closure, n/a] [GROOVY, public, Object, void, println, , n/a] [GROOVY, public, Object, Object, identity, Closure, n/a] [GROOVY, public, Object, Collection, collect, Collection, Closure, n/a] [GROOVY, public, Object, String, toString, , n/a] [GROOVY, public, Object, MetaClass, getMetaClass, , n/a] [GROOVY, public, Object, String, dump, , n/a] [GROOVY, public, Object, Object, find, Closure, n/a] [GROOVY, public, Object, Object, each, Closure, n/a] [GROOVY, public, Object, MetaProperty, hasProperty, String, n/a] [GROOVY, public, Object, List, findIndexValues, Closure, n/a] [GROOVY, public, Object, Object, use, List, Closure, n/a] [GROOVY, public, Object, Object, inject, Object, Closure, n/a] [GROOVY, public, Object, Collection, grep, Object, n/a] [GROOVY, public, Object, void, println, PrintWriter, n/a] [GROOVY, public, Object, boolean, is, Object, n/a] [GROOVY, public, Object, List, findIndexValues, Number, Closure, n/a] [GROOVY, public, Object, boolean, isCase, Object, n/a] [GROOVY, public, Object, int, findIndexOf, int, Closure, n/a] [GROOVY, public, Object, Object, invokeMethod, String, Object, n/a] [GROOVY, public, Object, Object, asType, Class, n/a] [GROOVY, public static, Object, void, sleep, long, n/a] [GROOVY, public, Object, boolean, any, Closure, n/a] [GROOVY, public, Object, void, addShutdownHook, Closure, n/a] [GROOVY, public, Object, void, printf, String, Object, n/a] [GROOVY, public, Object, void, putAt, String, Object, n/a] [GROOVY, public, Object, void, print, PrintWriter, n/a] [GROOVY, public, Object, List, respondsTo, String, [Ljava.lang.Object;, n/a] [GROOVY, public, Object, Object, eachWithIndex, Closure, n/a] [GROOVY, public, Object, Collection, findAll, Closure, n/a] [GROOVY, public, Object, Iterator, iterator, , n/a] [GROOVY, public, Object, void, printf, String, [Ljava.lang.Object;, n/a] [GROOVY, public, Object, List, respondsTo, String, n/a] [GROOVY, public, Object, Object, getAt, String, n/a] [GROOVY, public, Object, Object, use, [Ljava.lang.Object;, n/a] [GROOVY, public, Object, Object, with, Closure, n/a] [GROOVY, public, Object, void, setMetaClass, MetaClass, n/a] [GROOVY, public, Object, String, sprintf, String, Object, n/a] PROPERTY INFO [GROOVY, public, n/a, Class, class, class JavaPerson] [GROOVY, public, n/a, String, firstName, "Barney"] [GROOVY, public, n/a, String, lastName, "Rubble"]
ObjectBrowser
In this post, I have looked at general Java techniques (Javadoc,
Object.toString()
, javap
) for peeking inside of Groovy objects as well as Groovy-specific approaches. I have saved an extremely useful Groovy-specific approach for last. The Groovy graphical-based ObjectBrowser is a user-friendly approach for seeing the innards of a Groovy object. It is based on Groovy's many inspection techniques including those already discussed here. In fact, it's Javadoc comments state about it: "A little GUI to show some of the Inspector capabilities." In other words, ObjectBrowser provides graphical access to the capabilities provided by groovy.inspect.Inspector.There is more than one way to access ObjectBrowser. When using Groovy Shell, for example, one can type the "inspect" command to invoke ObjectBrowser. This is demonstrated in the next screen snapshot.
The ObjectBrowser can be invoked outside of the Groovy Shell as well. For example, the ObjectBrowser GUI is automatically started when
groovy.inspect.swingui.ObjectBrowser.inspect(obj)
is invoked within Groovy code (and obj is the name of the object to be evaluated).As shown in the image above, the Groovy Object Browser provides details of the public fields and methods as well as the Groovy meta methods. It shows the name, current value, data type, modifier, and declarer for each. It also supplies the origin (Groovy or Java) of each. Advantages of this approach includes its being graphical in nature and easy to use as well as the breadth of information (including current values) that it provides.
Integrated Development Environments
Integrated Development Environments (IDEs) have lagged behind in their support for dynamic languages as compared to their support for static languages. That being stated, IDEs continue to offer improved support and plug-ins for Groovy and can be useful in determining details of what a Groovy class has to offer.
Conclusion
I have discussed and demonstrated several different Groovy-specific and Java-general approaches for determining characteristics of a Groovy object. These approaches overlap (and some even make sure of each other) and have their own advantages and disadvantages. There is no shortage of approaches for learning more about the characteristics of a given Groovy object, so which is best to use often depends on the particular situation and the developer's needs.
Further Reading
⇒ Groovy Introspection: Know What You Have
⇒ Groovy Goodness: Getting Information about Objects
⇒ Difference Between inspect() and dump()
⇒ Background on dump() and inspect()
⇒ Groovy inspect()/Eval for Externalizing Data
No comments:
Post a Comment