JVM Dynamic Languages Metaobject Protocol 0.3

This library aims to make it possible for objects created by a runtime for one dynamic language to be passed to and manipulated by a different dynamic language, running within the same JVM.

See:
          Description

Packages
org.dynalang.mop This package defines the metaobject protocol interfaces.
org.dynalang.mop.beans This package defines a metaobject protocol implementation that follows the JavaBeans specification.
org.dynalang.mop.collections This package defines metaobject protocol implementations that expose standard Java lists and maps as dynamic objects, with the usually expected semantics (lists act as number-indexed associative arrays, maps act as generic associative arrays).
org.dynalang.mop.impl This package defines classes that help in implementing MOPs as well as creating (mostly composite) MOP instances.

 

This library aims to make it possible for objects created by a runtime for one dynamic language to be passed to and manipulated by a different dynamic language, running within the same JVM. More generally, it aims to provide a facility where an arbitrary system (usually a language runtime) can intuitively manipulate any arbitrary object model built atop of Java objects (usually the native object model of some other language).

Basically, it provides a unified mechanism that all dynamic languages on the JVM can use to inter-operably manipulate their own objects as well as objects from any other language that also uses this mechanism.

It strives to achieve this goal not by defining "One True Object", a single interface to be implemented by all Java objects that represent objects of the dynamic languages in the JVM, but rather by providing an extensible metaobject protocol (MOP) mechanism, as first formulated in the "In-process cross-language object interaction: adapters or navigators?" article. The idea is to completely throw away the idea of a dedicated interface on objects themselves, and having to wrap foreign objects into adapter objects that expose the expected interface. Instead, the operations on objects themselves are encapsulated behind MOP objects (you can also think about them as being the "navigators" and "manipulators" for the objects they know about), with usually only a single MOP required per language implementation.

The basic usage difference is that a dynamic language runtime will retrieve a property on an object not by using code like this: ((MyDynamicInterface)obj).get("foo"); but rather it will use a MOP: metaobjectProtocol.get(obj, "foo");

The real strength of the approach lies in extensibility and pluggability of MOPs. MOPs can be easily composed, so if you compose your language's native MOP with other languages' MOPs, your code will be able to natively manipulate those other languages' objects. You can have a MOP for DOM objects as well to natively add XML manipulating abilities into your languages. Finally, a JavaBeans MOP is provided as standard component in the library - you can add it as the last element of your composite MOP so that your language can manipulate any POJO directly if no other MOP recognizes the object. Full range of Java amenities, including optimized runtime resolution of overloaded methods and support for JDK 1.5 variable arguments is available.

The secret of composability is MOPs ability to declare it has no authority to perform an operation on an object. When an operation is attempted in a composite MOP, all its element MOPs will be attempted in turn while they claim no authority for it. Only when one MOP either performs the operation or authoritatively decides it must fail is the operation outcome final. Note that the authority declaration is very fine-grained: it is per operation and per object. It is therefore much more versatile than the wrapper interfaces approach: when using interfaces, a wrapper class must decide up-front which interfaces to implement on the object. A MOP can decide based on the actual state of the object whether it can perform an operation. This can also be handily used to extend any objects with language specific meta-properties. Since the API allows any object, not just strings, to be used as property identifiers, it is easy to use implementation-private objects as property IDs for things like ECMAScript "prototype" property and similar. A theoretical ECMAScript MOP would thus answer the get and put requests for the prototype property of a POJO, but would claim no authority for get and put requests for other properties, letting those fall through to the JavaBeans MOP.

Getting started

The StandardMetaobjectProtocolFactory is most likely all you need to get started using MOPs. A suitable code snippet for obtaining a MOP capable of handling all known object models in the current thread's class loader is:

import org.dynalang.mop.MetaobjectProtocol;
import org.dynalang.mop.impl.StandardMetaobjectProtocolFactory;
...

MetaobjectProtocol compositeMop = 
    StandardMetaobjectProtocolFactory.createStandardMetaobjectProtocol(true,false);
In case you're developing a library that supplies its own native metaobject protocol for some native object model (most likely, you are developing a language runtime), then you'd create an instance of your native MOP and pass it to be merged with other available MOPs into a single composite MOP as:
import org.dynalang.mop.MetaobjectProtocol;
import org.dynalang.mop.impl.StandardMetaobjectProtocolFactory;
...
MetaobjectProtocol nativeMop = new MyLanguageMop();
MetaobjectProtocol compositeMop = 
    StandardMetaobjectProtocolFactory.createStandardMetaobjectProtocol(nativeMop, true, false);

If you are developing your own MOP, you'll probably want to subclass MetaobjectProtocolBase.

Developer resources

The project is hosted at SourceForge, under http://www.sf.net/projects/dynalang.

If you check out the latest version from SVN, try running ant test. This produces both a JUnit test report at build/test/report/index.html and test coverage report at build/coverage/report/index.html. To build this JavaDoc, use ant doc, and then open build/doc/index.html.