Saturday, February 18, 2006

A prototype of Jython ScriptFactory for Spring Framework

SpringFramework 2.0 M2 does not include Jython support for its scripting framework. I don't know the reason. So I decide to create a prototype to prove it is doable.

Suppose we have a Java interface Messenger:

package org.yweng.spike.Spring;

public interface Messenger {
String getMessage();

And we have a Jython Script,, which implementes this interface:

from org.yweng.spike.Spring import Messenger

class PythonMessenger(Messenger):
def getMessage(self):
return 'Message from Python Messenger'

def getInstance():
return PythonMessenger()

Notice the getInstance method in the Jython module. The idea is using "naming convention" to help the Jython ScriptFactory instantiate Jython object.

The Spring xml configuration:

<bean class=""/>
<bean id="PyMessenger" class="org.yweng.spike.Spring.JythonScriptFactory">
value="classpath:org/yweng/spike/Spring/" />
value="org.yweng.spike.Spring.Messenger" />

The JythonScriptFactory class looks like this:

package org.yweng.spike.Spring;


import org.springframework.scripting.ScriptCompilationException;
import org.springframework.scripting.ScriptFactory;
import org.springframework.scripting.ScriptSource;
import org.springframework.util.Assert;
import org.apache.log4j.Logger;

import org.python.util.PythonInterpreter;

public class JythonScriptFactory implements ScriptFactory {
private static Logger logger =

private final String scriptSourceLocator;
private final Class[] scriptInterfaces;

public JythonScriptFactory(String scriptSourceLocator,
Class[] scriptInterfaces) {
this.scriptSourceLocator = scriptSourceLocator;
this.scriptInterfaces = scriptInterfaces;

public String getScriptSourceLocator() {
return this.scriptSourceLocator;

public Class[] getScriptInterfaces() {
return this.scriptInterfaces;

public boolean requiresConfigInterface() {
return true;

public Object getScriptedObject(ScriptSource scriptSourceLocator,
Class[] scriptInterfaces)
throws IOException, ScriptCompilationException {
String strScript = scriptSourceLocator.getScriptAsString();

if (scriptInterfaces.length > 0) {
try {
PythonInterpreter interp = new PythonInterpreter();
interp.exec("this = getInstance()");
return interp.get("this", scriptInterfaces[0]);
} catch (Exception ex) {
throw new ScriptCompilationException(ex.getMessage());
logger.error("No scriptInterfaces provided. ");
return null;

Junit Test case:

package org.yweng.spike.Spring;

import junit.framework.TestCase;

import org.springframework.context.ApplicationContext;
import org.apache.log4j.Logger;

public class TestJythonScriptFactory extends TestCase {
private static Logger logger = Logger.getLogger(TestJythonScriptFactory.class);

private ApplicationContext ctx =
new ClassPathXmlApplicationContext("org/yweng/spike/Spring/ApplicationContext.xml");

public void testPyMessenger() {
Messenger messenger = (Messenger)ctx.getBean("PyMessenger");
String msg = messenger.getMessage();;

It's not pretty but it works. :)


At 12:03 PM, Blogger James said...

Awesome! Are you willing to contribute this code to the Spring project? If so, then you can create an issue in JIRA and attach the code.

I recently sent them a JavaScriptFactory using Rhino.

At 11:11 PM, Blogger reyt said...

if wow gold and maple story mesos wow gold


Post a Comment

<< Home