Skip to content

Reflection

When developing in Ignition, it is often helpful to take a close look at the data types of objects available in jython, whether those types are imports from Java, or a native Jython types, or some exotic wrapper applied to a particular java object for best behavior in Jython.

These script functions are the successor to shared.inspect.introspect(), a workhorse written in jython that dates back to 2008 and the FactoryPMI predecessor to Ignition. (It is still available as inspect.py if you need it.)

Certain data types are misleading when reflection is executed purely within jython–this set of functions resolves that difficulty.

object()

Plain Java Reflection

The function signature of object() below triggers generic conversion of Jython values to Java equivalents, so that reflection occurs with a native java object where applicable (for the most part). When jython has wrapped a generic Java object for the interpreter’s use, this generic conversion simply yields the original java object, for no surprises.

For native Jython types, you get some subclass of PyObject as it appears to native java code. These are rather busy and the output is long even when verbose is False.

system.reflect.object(javaObject, verbose=False) returns String

javaObject Any java object to be examined in detail with reflection.
verbose A boolean flag to trigger a complete walk of the subject's java class hierarchy, reporting non-public methods and fields, and where possible, the current (possibly abbreviated) value of those fields.

coerced()

Coerced Java Reflection

When jython is passing objects as arguments to java methods, it it naively selects a method overload based on number of parameters, then attempts to coerce the supplied arguments to the data types needed by the java method. Some of the coercion decisions are complex, and the plain java introspection above may not correspond to what really happens in specific cases.

If you know a java method’s parameter types, you can have the jython object coerced into the target type just as if it were being handed to that method by the interpreter.

system.reflect.coerced(pyObject, class, verbose=False) returns String

pyObject Any jython object that you might supply to a java method and for which you need to examine the coerced form in detail, via reflection.
class A java data type (instance of Class<?>) that corresponds to the method parameter type. You can use reflection before this call to obtain the correct type.
verbose A boolean flag to trigger a complete walk of the subject's java class hierarchy, reporting non-public methods and fields, and where possible, the current (possibly abbreviated) value of those fields.

pyObject()

Jython PyObject Reflection

Jython’s own objects’ structure is hidden from jython scripts as implementation details. Some of those implementation details, particularly of wrapper types, may be important. The jython object itself, and its multiple inheritance hierarchy (in method resolution order) can be examined in detail.

system.reflect.pyObject(pyObject, verbose=False) returns String

pyObject Any jython object to be examined in detail with reflection.
verbose A boolean flag to trigger reporting of the current (possibly abbreviated) attribute values.

asThrowable()

Jython Exception Conversion

Jython’s native exceptions do not play well with Java’s Throwable heirarchy. In particular, Jython exceptions cannot be passed to loggers to produce clean tracebacks, and cannot be added to an outer Java exception as a cause.

To correct these issues, the following function takes a Jython Exception, or traceback from the environment, and constructs a Java-friendly Throwable instance (really a RuntimeException).

The resulting object is very similar to the PythonAsJavaException class provided by Automation Professionals’ later.py utility script, but with two key enhancements:

  • Serializable, due to its pure Java implementation, and

  • Includes full script module paths where available.

system.reflect.asThrowable(e, tb) returns PyAsJavaException

system.reflect.asThrowable(tb, cause) returns PyAsJavaException

e A Jython Exception (any subclass of BaseException).
tb A Jython Traceback object, or None. If not supplied, it will be extracted from the thread context.
cause Any Java Throwable object to be attached as the cause of the outer exception's traceback. This form of asThrowable() will return just this cause if there is no traceback supplied nor in the jython environment.

getModulePath()

Ignition’s project library scripts do not have reliable access to their own full path via python’s normal __package__ and __name__ module globals. However, Ignition does put this full path into a virtual file name for the module, which can be extracted from Jython’s interpreter frame.

A determined coder can raise a dummy Jython exception in order to gain access to the necessary frame, but this function does it without the exception overhead.

system.reflect.getModulePath() returns String