JOI - Java Object Inspector

Version : 3.0


Table Of Contents

  1. Overview
  2. Usage
  3. Extensibility
    1. Object Rendering
    2. Specialized Inspectors
    3. Object Exporter
  4. Release Notes
  5. Future Features
  6. Feedback
  7. Download






Object Rendering

By default the value of an object or an attribute is shown as the result of its toString() method. If a different, self-created string representation of own objects is desired, the corresponding class can implement the method inspectString() which will be used by the inspector instead of toString() to display the objects's value.

There are two ways to do this:

  1. Define that the class implements the interface That is a public method inspectString().
  2. Just implement inspectString() with any visibility (default | public | protected | private ) you like.

However, the first variant makes your code dependent on JOI at compile-time, whereas the second variant will compile without having any JOI classes in the classpath!
JOI automatically finds the method utilizing the reflection API.

Another alternative is to provide an object renderer that is able to provide the string representation for the instances of a specific class.
Let's assume the value of a java.awt.Color object should be #000000 rather than the default java.awt.Color[r=0,g=0,b=0] from the toString() method.
Of course this class can't be extended with a inspectString() method. So the solution is to write a class that implements and tell JOI to use it to render all instances of java.awt.Color. (
Telling JOI about an object renderer is quite simple. Just put the mapping of the classes into a file 'META-INF/joi.renderer' and ensure that this file is in the classpath.

Here's an example of such a file:

Since V2.1 it is also possible to provide a visual component renderer in addition to the string representation. Such a renderer must implement the interface That is an extension of which simply adds the method
public Component inspectComponent( Object obj ).
As an example the PropertiesRenderer is delivered with JOI. It will be used automatically whenever a Properties object is inspected. Then it is rendered to a JTable containing the key/value pairs (see

Specialized Inspectors

From the very beginning JOI was designed in a way that enables programmers to extend it with more specialized inspectors. Now here's a short guide how to do that.

JOI comes with a basic inspector ( class BasicInspector ), that shows all instance variables of any object it was opened on. However, for debugging sometimes it is more convenient to see a slightly different representation of an object's internals. For example Hashtable instances are much better to understand, if we can see the keys and their associated values rather than all the internal variables. Therefore a special inspector class named MapInspector is registered in the JOI framework to handle all instances of classes that implement the java.util.Map interface (e.g. java.util.Hashtable).
The following entry in 'META-INF/joi.inspector' installs that special inspector:

Of course everybody can create and install his/her own inspectors for classes and/or interfaces. Just put the appropriate class mapping in a 'META-INF/joi.inspector' file and ensure that it will be found in the classpath. The best is to just deliver the inspector classes and their corresponding 'META-INF/joi.inspector' file together in a JAR.

Example for a inspector mapping:

The key on the left is the class or interface the inspector should be used for. The value on the right is the associated inspector class wich must be a subclass of

Before that really works, you have to programm the new inspector class. Here are the steps you have to follow, using the implementation of StringInspector as example.

  1. Create a subclass of AbstractObjectSpy ( ==> StringSpy )
  2. Define the constructor that gets the object to be inspected
          public StringSpy( Object obj )
            throws SecurityException
          	super( obj ) ;
          } // StringSpy()
  3. Create a method that provides a type-cast access to the inspected object
          protected String getString()
          	return (String)this.getObject() ;
          } // getString()
  4. Implement the method addAllElements()
    In this method all internal elements of the inspectee must be wrapped in an ElementSpy instance and then be added to the list of element holders.
    Only the elements, that are added in this method will be displayed in the inspector.
          protected void addAllElements()
            throws SecurityException
            ElementSpy elementSpy = null ;
            Object element        = null ;
            String str            = null ;
            int index             = 0 ;
            str = this.getString() ;
            for ( index = 0 ; index < str.length() ; index++ )
              elementSpy = new ArrayElementSpy( this, index,
                                                new Character( str.charAt( index ) ),
                                                Character.TYPE ) ;
              this.getElementHolders().add( elementSpy ) ;
          } // addAllElements()
  5. Create a new inspector class as subclass of BasicInspector (StringInspector)
  6. Add the method objectSpyFor() that returns an instance of the new spy class with the object to inspect.
          protected AbstractObjectSpy objectSpyFor( Object obj )
            return ( new StringSpy( obj ) ) ;
          } // objectSpyFor()
  7. Add the method getInspectorId() that returns the public id of the inspector.
          protected String getInspectorId()
            return "StringInspector" ;
          } // getInspectorId()
  8. Finally propagate the existence of the new inspector for the associated class (in 'META-INF/joi.inspector'):

From now on the a StringInspector instance will be used for inspecting strings.
However, it is always still possible to open a basic inspector on a string that shows the real fields.

Object Exporter

This plugin is a little extension to the file menu of each opened inspector. Each implemented and plugged-in object exporter creates one extra menu item that allows to export the current object to wherever the implementation puts it.

So to keep an object's state persistent it is possible to write your own class that must implement For details see ExportProvider Javadoc


Release Notes


Future Features

Here is a list of things that might be supported in a future version: