Showing posts with label Dynamic Language. Show all posts
Showing posts with label Dynamic Language. Show all posts

27.11.11

Clojure: expectations - scenarios | Javalobby

Clojure: expectations - scenarios | Javalobby

Expectations


expectations is a minimalist's testing framework
  • simply require expectations and your tests will be run on JVM shutdown.
  • what you are testing is inferred from the expected and actual types
  • stacktraces are trimmed of clojure library lines and java.lang lines
  • focused error & failure messages

Clojure

Clojure - home

Clojure is a dynamic programming language that targets the Java Virtual Machine (and the CLR, and JavaScript). It is designed to be a general-purpose language, combining the approachability and interactive development of a scripting language with an efficient and robust infrastructure for multithreaded programming. Clojure is a compiled language - it compiles directly to JVM bytecode, yet remains completely dynamic. Every feature supported by Clojure is supported at runtime. Clojure provides easy access to the Java frameworks, with optional type hints and type inference, to ensure that calls to Java can avoid reflection.

Clojure is a dialect of Lisp, and shares with Lisp the code-as-data philosophy and a powerful macro system. Clojure is predominantly a functional programming language, and features a rich set of immutable, persistent data structures. When mutable state is needed, Clojure offers a software transactional memory system and reactive Agent system that ensure clean, correct, multithreaded designs.

16.7.10

Make My Java Program Supports Dynamic Language(5)

Groovy

  • Problem: Still Slow.

Groovy is my second though, and I am OK with it so far, although I have some performance concern with it. According to my testing, by primitive calculation Groovy, it is about 128 times slower than the native Java program. The difference is significant. However, due to my current use cases, I would probably use Groovy as a glue language to glue up some other Java implementation with programmatic flow control

  • ClassLoader Supports

I am very happy that Groovy provides ClassLoader supports. That means it support a transparent Class.forName().

  • Resource Loader

image

image

I am happy with the implementation. The Composite Design Pattern of Resource Loader gives me a good opportunity to build my own Resource Loader, so that I can search specific PATHs/JARs.

Scala

Scala is popular now a day. But it’s not design to embedded or into Java. http://www.scala-lang.org/node/6966 is a thread talking about Scala Scripting. And here is some except:

Here are two examples:

http://people.apache.org/~mduerig/scala4scripting/

You might probably want to watch his talk from the Scala Days as well.

Here's some code I wrote some time ago (in Java!) which uses Scala for
scripting (I'm not sure which version but definitely pre-2.8):

http://github.com/jrudolph/scolorz/blob/master/src/net/virtualvoid/graph...

Actually it is quite easy to use the Scala interpreter (beware Java
code following):

import scala.tools.nsc.Interpreter;
import scala.tools.nsc.Settings;

final Interpreter interpreter = new Interpreter(new Settings());
final Painter[] painter = new Painter[1];

interpreter.bind("painter", "Array[net.virtualvoid.graphics.Painter]", painter);
String code = "object aPainter extends net.virtualvoid.graphics.Painter{\n"
+ "def paint:Unit = {\n"
+ text.getText() + "\n}\n"
+ "}\n";

interpreter.interpret(code);
interpreter.interpret("painter(0) = aPainter;");

So I defined a Painter interface and bound an array of that variable
to receive the results. Code which I executed got wrapped by code
which implements the interface. After evaluating this, the result is
stored into the array and can be accessed afterwards.

Make My Java Program Supports Dynamic Language (4)

What I want?

What I want is:

  • Transparent Dynamic Language Support.
  • Search specific paths/JARs for the script.

Transparent Dynamic Language Support

For example, I can use:

    Class clazz = Class.forName(“my.hello.World”);
MyWorld world = (MyWorld)clazz.newInstance();
world.sayHello();
MyResult result = world.cal();
System.out.println("Result is : " + result.toString());


Search specific paths/JARs for the script.


I don’t want the script engine to search too many places for the sake of performance. For example:

    MyEngine myEngine = new MyEngine();
myEngine.addScriptPath("scripts");
myEngine.addScriptJAR("lib/scripts.jar");

Candidates



  • BeanShell
  • Groovy
  • Scala

BeanShell



  • Problem: Too Slow

BeanShell is terribly slow according to my test. It’s even slower than the JavaScript version. Can someboy tell me why?


BTW: I just come across an open-source project hosted in GoogleCode names BeanShell2.



  • Problem: Lack of Class support

There is no real Class support in BeanShell. I can create an object to implement an Interface, but I can not define a “static” Class.

  public void sayHello() {
System.out.println("Hello world");
}
public String retrieveResult() {
return "Hello world as result";
}
return this;

Please refer to http://www.beanshell.org/examples.html for more examples.



  • Problem: API

The BeanShell APIs are very similar to JSR 223, It provides .eval() and .source() interface for programming. Another option to use BeanShell is via JDK 6’s Scripting Supports via https://scripting.dev.java.net/


However, none of them could be transparent. Although transparent is not very essential for me, for I am still designing my Software Architecture. However, I need to keep in mind this requirement to avoid some major changes in the previous version.



  • Can be replaced

Yes, BeanShell could be replace totally by Groovy if you just use strict Java language syntax in Groovy. So why BeanShell?

15.7.10

Make My Java Program Supports Dynamic Language (2)

However, when you are thinking about script language support, the first thing you would be concerned might probably not be the performance, but the Java language interoperable. As I mentioned in the previous POST, JDK 6’s script engine only support engine.eval() method. If you have experience with BeanShell, you might probably be comfortable with it. Yes, I can feed the method with a script and return an Object so that I can go further. How about the parameters? OK, there are Bindings I can use.

Invocable

The only access to your script via ScriptEngine is .eval(), however, some ScriptEngine implements another interface:

Invocable

Code Example 7: You can use the Invocable interface to call specific methods in a script.

  jsEngine.eval("function sayHello() {" +
" println('Hello, world!');" +
"}");
Invocable invocableEngine = (Invocable) jsEngine;
invocableEngine.invokeFunction("sayHello");
Just look at the Invocable interface’s description:
















Method Summary




<T> T
getInterface(Class<T> clasz) 
          Returns an implementation of an interface using functions compiled in the interpreter.




<T> T
getInterface(Object thiz, Class<T> clasz) 
          Returns an implementation of an interface using member functions of a scripting object compiled in the interpreter.
 ObjectinvokeFunction(String name, Object... args) 
          Used to call top-level procedures and functions defined in scripts.
 ObjectinvokeMethod(Object thiz, String name, Object... args) 
          Calls a method on a script object compiled during a previous script execution, which is retained in the state of the ScriptEngine.

It looks nice. It’s much better than using the stupid eval() and binding methods in ScriptEngine.

Scripting for the Java Platform

By John O'Conner, July 2006

Articles Index

The Java platform provides rich resources for both desktop and web application development. However, using those resources from outside the platform has been impractical unless you resort to proprietary software solutions. No industry standard has defined or clarified how developers can use Java class files from other programming languages. Scripting languages haven't had a standard, industry-supported way to integrate with Java technologies. However, as Bob Dylan once said, "the times, they are a changin'." One change is Java Specification Request (JSR) 223, which helps developers integrate Java technology and scripting languages by defining a standard framework and application programming interface (API) to do the following:

  1. Access and control Java technology-based objects from a scripting environment
  2. Create web content with scripting languages
  3. Embed scripting environments within Java technology-based applications

This article focuses on the specification's third goal and will show you how to use an embedded scripting environment from a Java platform application. A demo application called ScriptCalc will provide a working example of how to extend your applications with user-defined scripts in the JavaScript programming language.

Note: Any API additions or other enhancements to the Java SE platform specification are subject to review and approval by the JSR 270 Expert Group.

Reasons to Use a Scripting Language

Most scripting languages are dynamically typed. You can usually create new variables without predetermining the variable type, and you can reuse variables to store values of different types. Also, scripting languages tend to perform many type conversions automatically, for example, converting the number 10 to the text "10" as necessary. Although some scripting languages are compiled, most languages are interpreted. Script environments generally perform the script compilation and execution within the same process. Usually, these environments also parse and compile scripts into intermediate code when they are first executed.

These qualities of scripting languages help you write applications faster, execute commands repeatedly, and tie together components from different technologies. Special-purpose scripting languages can perform specific tasks more easily or more quickly than can more general-purpose languages. For example, many developers think that the Perl scripting language is a great way to process text and to generate reports. Other developers use the scripting languages available in bash or ksh command shells for both command and job control. Other scripting languages help to define user interfaces or web content conveniently. Developers might use the Java programming language and platform for any of these tasks, but scripting languages sometimes perform the job as well or better. This fact doesn't detract from the power and richness of the Java platform but simply acknowledges that scripting languages have an important place in the developer's toolbox.

Combining scripting languages with the Java platform provides developers an opportunity to leverage the abilities of both environments. You can continue to use scripting languages for all the reasons you already have, and you can use the powerful Java class library to extend the abilities of those languages. If you are a Java language programmer, you now have the ability to ship applications that your customers can significantly and dynamically customize. The synergy between the Java platform and scripting languages produces an environment in which developers and end users can collaborate to create more useful, dynamic applications.

For example, imagine a calculator with a set of core operations. Although the base calculator may have only four or five fundamental operations, you can provide programmable function keys that the user can customize. Customers can use whatever scripting language they prefer to add mortgage calculations, temperature conversions, or even more complex functionality to the calculator. Another example of this collaboration could be a word processor that allows customers to provide customized filters for generating various file formats. Examples throughout the remainder of this article will show how to use scripting to provide customizable Java applications for your customers.

JSR 223 Implementation

Version 6 of the Java Platform, Standard Edition (Java SE), does not mandate any particular script engine. The Mozilla Rhino engine for the JavaScript programming language, however, is currently included as a feature in the JDK 6 and JRE 6 libraries. The Java SE 6 platform implements the java.script APIs, which allow you to use script engines that comply with JSR 223. The web site scripting.dev.java.net hosts an open project to maintain several script engines that conform to JSR 223. The site also links to engines maintained elsewhere. You can learn more about the the embedded JavaScript technology engine by visiting the Mozilla Rhino web site.

Ways to Use the Scripting API

The scripting API is in the javax.script package available in the Java SE 6 platform. The API is still relatively small, composed of six interfaces and six classes, as Table 1 indicates.

Table 1: Interfaces and Classes in the Java SE 6 Platform

Interface Class
Bindings AbstractScriptEngine
Compilable CompiledScript
Invocable ScriptEngineManager
ScriptContext SimpleBindings
ScriptEngine SimpleScriptContext
ScriptEngineFactory ScriptException

Your starting point should be the ScriptEngineManager class. A ScriptEngineManager object can tell you what script engines are available to the Java Runtime Environment (JRE). It can also provide ScriptEngineobjects that interpret scripts written in a specific scripting language. The simplest way to use this API is to do the following:

  1. Create a ScriptEngineManager object.
  2. Retrieve a ScriptEngine object from the manager.
  3. Evaluate a script using the ScriptEngine object.

That sounds easy enough, but what does the code look like? Code Example 1 performs all three steps, printing Hello, world! to the console.

Code Example 1: Create a ScriptEngine object using the engine name.

  ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");
try {
jsEngine.eval("print('Hello, world!')");
} catch (ScriptException ex) {
ex.printStackTrace();
}

The API is only slightly more complex if you want to query the list of supported scripting engines, to pass values back and forth to the scripting environment, or to compile a script for repeated execution. Additional APIs allow you to query the ScriptEngineManager for engines that associate a particular file extension, to execute the script from a file, and to call a specific function in a script. This article describes many of those features.

Available Script Engines

A ScriptEngineManager object provides the discovery mechanism for the the scripting framework. A manager finds ScriptEngineFactory classes, which create ScriptEngine objects. Developers can add script engines to a JRE with the JAR Service Provider specification. Although this specification is beyond the scope of this article, you can find more information in the JAR File Specification.

Code Example 1 retrieved a scripting engine directly from a script manager. However, that way of accessing a ScriptEngine object works only when you know the engine's name. If you need to retrieve a ScriptEngineobject using more complicated criteria, you may need to get the entire list of supported ScriptEngineFactory objects first. A ScriptEngineFactory can create ScriptEngine objects for a specific scripting language.

Code Example 2 provides a list of discovered factories.

Code Example 2: You can retrieve a list of all engines installed to your Java platform.

  ScriptEngineManager mgr = new ScriptEngineManager();
List<ScriptEngineFactory> factories = mgr.getEngineFactories();

Once you have a script-engine factory, you can retrieve various details about the scripting language that the factory supports:


  • The script-engine name and version
  • The language name and version
  • Aliases used for the script engine
  • A ScriptEngine object for the scripting language

Code Example 3 shows how to retrieve this information.

Code Example 3: A ScriptEngineFactory object provides detailed information about the engine it provides.

  ScriptEngineManager mgr = new ScriptEngineManager();
List<ScriptEngineFactory> factories =
mgr.getEngineFactories();
for (ScriptEngineFactory factory: factories) {
System.out.println("ScriptEngineFactory Info");
String engName = factory.getEngineName();
String engVersion = factory.getEngineVersion();
String langName = factory.getLanguageName();
String langVersion = factory.getLanguageVersion();
System.out.printf("\tScript Engine: %s (%s)\n",
engName, engVersion);
List<String> engNames = factory.getNames();
for(String name: engNames) {
System.out.printf("\tEngine Alias: %s\n", name);
}
System.out.printf("\tLanguage: %s (%s)\n",
langName, langVersion);
}

Code Example 3 produces the following output:

ScriptEngineFactory Info
Script Engine: Mozilla Rhino (1.6 release 2)
Engine Alias: js
Engine Alias: rhino
Engine Alias: JavaScript
Engine Alias: javascript
Engine Alias: ECMAScript
Engine Alias: ecmascript
Language: ECMAScript (1.6)

Notice that the list of script-engine factories contains only one entry for the Mozilla Rhino engine. Currently, Rhino is the only engine included in the core JDK 6 libraries, although it is not dictated by the platform. You can add additional engines by installing a JAR file-based service provider into your JRE, as mentioned earlier. This article's code examples use the Mozilla Rhino engine. Notice that the script-engine factory provides many engine name aliases to help you retrieve an engine for the JavaScript programming language.

Ways to Create a ScriptEngine

Once you have all this information about a factory and the engine it supplies, you can decide at runtime which engine factory to use. If you find the appropriate ScriptEngineFactory, creating the associatedScriptEngine is easy. Ask the factory for the actual engine as in Code Example 4, with the factory's getScriptEngine method. This code iterates through all known factories, searching for one that meets specific criteria for language name and version. In this example, the criteria are hardcoded. The code is searching for a factory that supports ECMAScript version 1.6.

Code Example 4: You can search for script engines that meet your application's requirements.

  List<ScriptEngineFactory> scriptFactories = 
mgr.getEngineFactories();
for (ScriptEngineFactory factory: scriptFactories) {
String langName = factory.getLanguageName();
String langVersion = factory.getLanguageVersion();
if (langName.equals("ECMAScript") &&
langVersion.equals("1.6")) {
engine = factory.getScriptEngine();
break;
}
}

Of course, if you already know that an engine is available, you can ask a ScriptEngineManager object for it directly by name, file extension, or even MIME type. The following line of code will retrieve a JavaScript programming language engine because js is the common file extension for JavaScript programming language files.

  engine = mgr.getEngineByExtension("js");

How to Run a Script

A ScriptEngine object runs script code. An engine's eval method evaluates the script, which is a character sequence obtained from either a String or java.io.Reader object. A Reader object can get its characters from a file too. You can use this ability to read the scripts that customers provide even after you have deployed your application.

Code Example 1 used the eval method to evaluate a String character sequence:

  try {
jsEngine.eval("print('Hello, world!')");
} catch (ScriptException ex) {
ex.printStackTrace();
}

Rhino's implementation of the print method sends its argument data to the console. The Hello, world! message appears in your command-shell console. If you run this in an integrated development environment (IDE) such as NetBeans or Eclipse, the output appears in the IDE's debug or output window.

One of the best reasons to use scripting in your application is to allow users to customize its functionality. The easiest way to allow this customization is read script files that customers provide. An overloaded eval method can use a Reader parameter, which you can use to process scripts from an external file.

Finding resources outside of your application's JAR file can be problematic. However, if you place scripts in a relative directory on the classpath or in a well-defined absolute location that the user defines, your application can reliably find the scripts. If you decide that all user-defined scripts will exist in a scripts subdirectory under your application's JAR file directory, you should ensure that the JAR file's subdirectory is on the classpath. As long as your application's directory is on the classpath, your application should consistently find customer-defined scripts in the scripts subdirectory. You can put the JAR file's relative directory location in the classpath using theClass-path statement in a manifest file that will be stored in the application's JAR file. The relative path for the JAR file's location is denoted by the . character. This article's ScriptCalc demo application uses amanifest.xml file similar to the one in Code Example 5.

Code Example 5: Adding . to the classpath helps your application find scripts that have paths relative to the JAR file.

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.6.5
Created-By: 1.6.0-rc-b89 (Sun Microsystems Inc.)
Main-Class: com.sun.demo.calculator.Calculator
Class-Path: .

Code Example 6 shows how to evaluate a file that the customer has supplied. The file name is /scripts/F1.js, and it is located under the application directory.

Code Example 6: The eval method can read script files.

  ScriptEngineManager engineMgr = new ScriptEngineManager();
ScriptEngine engine = engineMgr.getEngineByName("ECMAScript");
InputStream is =
this.getClass().getResourceAsStream("/scripts/F1.js");
try {
Reader reader = new InputStreamReader(is);
engine.eval(reader);
} catch (ScriptException ex) {
ex.printStackTrace();
}

How to Invoke a Script Procedure

Running entire scripts is useful, but you may want to invoke only specific script procedures. Some script engines implement the Invocable interface. If an engine implements this interface, you can call or invoke specific methods or functions that the engine has already evaluated.

Script engines are not required to support the Invocable interface. However, the Rhino JavaScript technology implementation included in JDK 6 does. If your script contains a function called sayHello, you could invoke it repeatedly by casting your ScriptEngine object to an Invocable object and by calling its invokeFunction method. Alternatively, if your script defines objects, you can call object methods using the invokeMethodmethod. Code Example 7 demonstrates how to use this interface.

Code Example 7: You can use the Invocable interface to call specific methods in a script.

  jsEngine.eval("function sayHello() {" +
" println('Hello, world!');" +
"}");
Invocable invocableEngine = (Invocable) jsEngine;
invocableEngine.invokeFunction("sayHello");

Code Example 7 prints Hello, world! to the console.

Be aware that invokeMethod and invokeFunction methods can throw several exceptions, so you must be prepared to catch ScriptException, NoSuchMethodException, and perhaps evenNullPointerException exceptions. See the documentation on the Invocable interface for details.

How to Access Java Objects From Script

JSR 223 implementations provide programming language bindings that allow access to Java platform classes, methods, and properties. The access mechanism will usually follow the scripting language's conventions for native objects in that particular scripting environment.

How do you get Java objects into the script environment? You can pass objects into script procedures as arguments using the Invocable interface. Alternatively, you can "put" them there: Your Java programming language code can place Java objects into the scripting environment by invoking a script engine's put method. This method places key-value pairs into a javax.script.Bindings object, which is maintained by a script engine. ABindings object is a map of key-value pairs that can be accessed from within an engine.

Imagine you have a list of names for a script to process. Code Example 8 in the Java programming language might produce the list.

Code Example 8: Java programming language code adds names to a list.

  List<String> namesList = new ArrayList<String>();
namesList.add("Jill");
namesList.add("Bob");
namesList.add("Laureen");
namesList.add("Ed");

After creating a ScriptEngine object called jsEngine, you can put the namesList Java object into the scripting environment. The put method requires String and Object arguments that represent a key-value pair. In Code Example 9, the script code can use the namesListKey reference to access the namesList Java object.

Code Example 9: Script code can both access and modify native Java objects.

  jsEngine.put("namesListKey", namesList);
System.out.println("Executing in script environment...");
try {
jsEngine.eval("var x;" +
"var names = namesListKey.toArray();" +
"for(x in names) {" +
" println(names[x]);" +
"}" +
"namesListKey.add(\"Dana\");");
} catch (ScriptException ex) {
ex.printStackTrace();
}
System.out.println("Executing in Java environment...");
for (String name: namesList) {
System.out.println(name);
}

Having placed the namesListKey key-value binding into the script-engine scope, you can use the Java object as a script object. Using the namesListKey variable, the script can access the namesList object. In Code Example 9, the script prints out the list's names and adds the name Dana. By printing the namesList contents after returning from the eval method, the example shows that the script has successfully accessed and modified the list.

The output from Code Example 9 shows the list twice. The script produces the first listing, then adds a name. After evaluating the script, the code prints the list again, showing that the script successfully modified the list as well:

Executing in script environment...
Jill
Bob
Laureen
Ed
Executing in Java environment...
Jill
Bob
Laureen
Ed
Dana

You can pass the same namesList object to the scripting code using the Invocable interface too. Instead of using the key-value pair binding mechanism, scripting code can access and modify procedure arguments that are provided through the Invocable interface. Code Example 10 shows how to use Java objects through the Invocable interface. The code passes the namesList value to the script environment as a parameter of theinvokeFunction method.

Code Example 10: Applications can pass values to script using the Invocable interface.

  Invocable invocableEngine = (Invocable)jsEngine;
try {
jsEngine.eval("function printNames1(namesList) {" +
" var x;" +
" var names = namesList.toArray();" +
" for(x in names) {" +
" println(names[x]);" +
" }" +
"}" +

"function addName(namesList, name) {" +
" namesList.add(name);" +
"}");
invocableEngine.invokeFunction("printNames1", namesList);
invocableEngine.invokeFunction("addName", namesList, "Dana");
} catch (ScriptException ex) {
ex.printStackTrace();
} catch (NoSuchMethodException ex) {
ex.printStackTrace();
}

You can also create new Java objects in the scripting environment. After importing the necessary Java platform packages, your script can use any native Java class. Instead of printing messages to the console, you could create a Swing message dialog box from your script, as in Code Example 11 and its output, shown in Figure 1.

Code Example 11: Scripts can import Java platform packages.

  try {
jsEngine.eval("importPackage(javax.swing);" +
"var optionPane = " +
" JOptionPane.showMessageDialog(null, 'Hello, world!');");
} catch (ScriptException ex) {
ex.printStackTrace();
}

Message dialog

Figure 1. Script code can create native Java platform objects.

How to Access Script Objects

The eval, invokeMethod, and invokeFunction methods always return an Object instance. For most script engines, this object is the last value that your script calculated. So the easiest way to access objects in the scripting environment is to return them from your script procedures or make sure that your script evaluates to the desired object.

The script-engine implementation will map some script types to their equivalents in the Java programming language. For example, the Mozilla Rhino script-engine maps number and string types to the Java programming language Double and String types. You can cast the return value of the eval, invokeMethod, or invokeFunction methods if you know that a mapping exists. You should always consult your script-engine documentation for details of the type mappings. Of course, your script can create and return native Java objects too.

The ScriptCalc Demo

The ScriptCalc demo application implements parts of a postfix calculator. Figure 2 shows the calculator's graphical user interface (GUI).

ScriptCalc image

Figure 2. The ScriptCalc Demo uses an embedded script engine.

The demo calculator provides basic calculator operations: add, subtract, multiply, and divide. Because this calculator's primary purpose is to show how to allow users to provide user-defined scripts that extend the core application, the calculator has four programmable function keys: F1, F2, F3, and F4. Users can extend the basic calculator by adding scripts to implement additional calculator functionality for these keys.

In this example, the customer can add scripts into a scripts subdirectory under the application's JAR file location. The scripts should be named F1.js, F2.js, F3.js, and F4.js. When the user presses any of the programmable function keys, the application invokes the corresponding function script. Each script file should implement a calculate method that uses a java.util.Stack argument. When you press the F1 key on the application GUI, the calculator invokes the calculate method of the /scripts/F1.js script.

The script has access to the calculator stack because the calculator model passes a java.util.Stack object to the F1.js script as an argument. The calculator model invokes the script's calculate method as shown in Code Example 12.

Code Example 12: Invoke the script's calculate method.

  private Stack<Number> numStack;
...
Invocable invocable = invocableEngines[funcNumber];
result = (Double) invocable.invokeFunction("calculate", numStack);

Imagine that you run a mortgage company. Estimating monthly mortgage payments on loans is a common operation when you talk with customers, so you need a calculator that can perform that operation. If you want to associate that operation with the F1 key, you would create a /scripts/F1.js file with a calculate(stack) procedure. Code Example 13 shows what the script code for the F1 key's mortgage calculation might look like.

Code Example 13: Calculate monthly mortgage payments.

function calculate(stack) {
var monthlyPayment = Number.NaN;

var size = stack.size();
if (size >= 3) {
var years = Number(stack.pop());
var annualInterest = Number(stack.pop());
var principal = Number(stack.pop());

var monthlyInterest = annualInterest / 100 / 12;
var numberOfPayments = years * 12;
var x = Math.pow(1+monthlyInterest, numberOfPayments);

monthlyPayment = (principal*x*monthlyInterest)/(x-1);

if (!isNaN(monthlyPayment) &&
(monthlyPayment != Number.POSITIVE_INFINITY) &&
(monthlyPayment != Number.NEGATIVE_INFINITY)) {

monthlyPayment = Math.round(monthlyPayment*100)/100;
stack.push(monthlyPayment);
} else {
stack.push(principal);
stack.push(annualInterest);
stack.push(years);
monthlyPayment = Number.NaN;
}
}
return monthlyPayment;
}

The script's responsibility is to pop as many operands from the stack as necessary, perform the calculation, push the result back on the stack, and return the result at the end of the procedure. If a calculation problem occurs, the script tries to restore the stack and returns a NaN value to indicate an error.

For the mortgage calculation, the script checks the stack to make sure that at least three values are available: the principal amount of the loan, the annual interest rate, and the number of years allowed for payment. If those values are on the stack, the script performs the calculation, pushes the result back on the stack, and returns the result from the procedure.

This script is in the application's scripts subdirectory. To use the script, execute the application and input the required three arguments: principal amount, annual interest rate, and loan payment period in years. For example, input the principal amount of 300000, and press the Enter key. Using the Enter key after each value, input the annual interest amount of 7.5 and the loan period of 30 years. All the operands are now on the stack. Press the F1 key to execute the script and to invoke the calculate method. The calculator should then display the result 2097.64 as shown in Figure 3.

Mortgage calculation

Figure 3. Press the F1 key to invoke the mortgage calculation.

Of course, you don't have to keep or use this particular script. You can change it as you like, or you can add other scripts for the F2, F3, and F4 keys on the calculator. After all, being able to extend core functionality is one of the primary benefits of scripting in the Java platform.

Summary

The JSR 223 specification defines scripting in the Java platform. The Java SE 6 platform implements this specification and currently JDK 6 and JRE 6 provide the Mozilla Rhino script engine for JavaScript technology support. Other script engines are available, and you can add them to your runtime environment as common JAR extensions.

You may include scripting support in your application for a variety of reasons:


  • Sophisticated configuration options.
  • User-defined functionality.
  • Ease of maintenance after application release.
  • Skill sets of users -- end users may be familiar with scripting languages but not the Java programming language.
  • Reuse of code modules in other programming languages.

Using scripting from the Java platform is easy because the API is relatively small. You can quickly add scripting support to your application using only a handful of interfaces and classes in the javax.script package.

Use the included demo application to get started with the scripting API. As a scripting demo, the ScriptCalc application does not implement all common calculator features. However, it does demonstrate how to mix scripting with the Java platform. You can create user-defined scripts that add functionality for programmable function keys in the GUI. The demo provides a script that adds a mortgage calculation to the F1 key.

For More Information


http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/

New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine

By Ed Ort, July 2009

Articles Index

DaVinci HelicopterThis article describes a new feature provided in JDK 7: support for dynamically typed languages in the Java virtual machine (JVM). This feature, which implements JSR 292: Supporting Dynamically Typed Languages on the Java Platform, is the logical follow-on to JSR 223: Scripting for the Java Platform. Support for JSR 223 was provided as part of Java SE 6 and implemented in JDK 6.

With the addition of support for JSR 292 in JDK 7, dynamically typed languages should run faster in the JVM than they do today. A key part of this support is the addition of a new Java bytecode, invokedynamic, for method invocation, and an accompanying linkage mechanism that involves a new construct called a method handle. These features enable implementers of compilers for dynamically typed languages, that is, the people who develop compilers for languages such as JRuby and Jython, to generate bytecode that runs extremely fast in the JVM.

This should increase the variety and quality of dynamically typed languages that run in the JVM. Application developers should see more of their favorite dynamically typed languages available in the Java ecosystem. Also, these features should boost the performance of code generated by dynamically typed language compilers that already run in the JVM. For example, the JRuby compiler generates bytecode that performs well in the JVM, but the JRuby bytecode will run even faster when the JRuby compiler is modified to use the invokedynamic bytecode and method handles.

The JSR 292 Expert Group is also investigating support for interface injection, the ability to modify classes at runtime so that they can implement new interfaces -- this is a feature that is common in dynamically typed languages.

Support for JSR 292 in JDK 7 will enable developers of compilers for dynamically typed languages to generate bytecode that runs extremely fast in the JVM.

Another stimulus for new languages on the JVM is the Da Vinci Machine Project, an OpenJDK community effort. The project's mission is to extend the JVM so that it supports languages other than Java, especially dynamic languages. The project hosts a number of subprojects. One of these is implementing theinvokedynamic bytecode. Other Da Vinci Machine subprojects are implementing MethodHandle support and interface injection. Some other extensions to the JVM developed in Da Vinci Machine subprojects might be incorporated into future versions of the JDK.

Contents

Dynamically Typed Languages and the JVM

Ask a developer what the JVM is and he or she is likely to say that it's a program that executes Java programs translated into machine-independent bytecode. That answer is true but not complete. The JVM does execute Java programs translated into bytecode. In fact, the execution of machine-independent bytecode makes the JVM the cornerstone of the Java platform. The Java Virtual Machine Specification, the bible of the JVM, underscores the JVM's importance as follows:

It is the component of the technology responsible for its hardware- and operating-system independence, the small size of its compiled code, and its ability to protect users from malicious programs.

However, the JVM is not limited to handling translated Java programs. The Java Virtual Machine Specification also states:

The Java virtual machine knows nothing of the Java programming language, only of a particular binary format, the class file format. A class file contains Java virtual machine instructions (or bytecodes) and a symbol table, as well as other ancillary information. For the sake of security, the Java virtual machine imposes strong format and structural constraints on the code in a class file. However, any language with functionality that can be expressed in terms of a valid class file can be hosted by the Java virtual machine. Attracted by a generally available, machine-independent platform, implementers of other languages are turning to the Java virtual machine as a delivery vehicle for their languages.

The JVM has been host to a growing number of languages. Increasingly, JVM implementations of dynamic languages are becoming available.

Over the years, the JVM has been host to a growing number of languages, anywhere from Armed Bear Common Lisp, an implementation of the Common LISP language, to Yoix, a general purpose scripting language. Increasingly, JVM implementations of dynamic languages are becoming available, such asJRuby, an implementation of the Ruby programming language, Jython, an implementation of the Python programming language, and the Groovy scripting language.

For many application developers, the growing list of JVM-hosted dynamic languages is great news. The flexibility that dynamic languages offer, especially scripting languages, makes these languages particularly attractive for application prototyping and experimentation as well as for applications that evolve rapidly. This flexibility stems from dynamic typing. A language that is dynamically typed verifies at runtime that the values in an application conform to expected types. By comparison, a statically typed language such as the Java programming language does most of its type checking at compile time, checking the types of variables, not values. The Java language also allows some dynamic type checking of values, especially receivers of virtual or interface method calls. But even these calls require a static type for the receiver.

Dynamic typing is often more flexible than static typing because it allows programs to generate or configure types based on runtime data. In addition, dynamically typed languages have more permissive type matching rules, and can perform many type conversions automatically. These behaviors tend to help developers create applications more quickly than if they code in a statically typed language. However, programs written in languages that are statically typed often execute more efficiently. In addition, static typing can eliminate many errors at compile time. The downside of static typing is that it could reject programs at compile time that otherwise might execute correctly.

Couple the flexibility inherent in dynamic typing with the execution efficiency of the JVM — an efficiency gained from the contributions of many leading-edge engineers with years of experience — and it's easy to understand why JVM support for dynamically typed languages is attractive to creators of dynamic programming languages as well as to application developers who build applications in these languages.

JSR 223 — A First Step in Dynamic Language Support

The first step in bringing dynamic languages to the JVM was JSR 223: Scripting for the Java Platform, a specification that defined an API for accessing Java code from code written in a dynamic scripting language. JSR 223 also specified a framework for hosting scripting engines in Java applications. A scripting engine is a program that compiles or interprets scripting code and then executes it. This specification and its implementation made it much easier to create applications that include both Java code and scripting code.

JSR 223 was included in Java SE 6 and implemented in JDK 6. In addition, JDK 6 included the Rhino scripting engine, an implementation of the JavaScript scripting language. Sun also initiated a scripting project, whose primary goal is to stimulate the community to build additional scripting engines for use in Java applications. More than 20 scripting engines have already been created in this project, any of which can run in the JVM.

The Problem for Dynamically Typed Languages

Meeting JVM requirements has been a pain point for dynamic language implementers when generating bytecodes for method invocations.

Although support for JSR 223 has stimulated the development of scripting engines for the JVM, developers of these scripting engines have faced a troublesome obstacle. When developers write engines for dynamically typed languages that run in the JVM, they have to satisfy the requirements of the Java bytecode that the JVM executes. Until now, that bytecode has been designed exclusively for statically typed languages. This design has been a pain point for script engine developers when generating bytecodes for method invocations.

Bytecode Requirements for Method Invocation

Recall that a statically typed language does its type checking at compile time. What this means for a method invocation is that the compiler, and the bytecode it generates, needs to know the type of the value returned by the method as well as the types of any receiver or parameters specified in the call.

Consider the following Java code snippet:

   String s = "Hello World";
System.out.println(s);

Notice that the type of parameter to the method is known. It's a String. The println() method doesn't return a value, but if the code example did call a method that does return a value, the type of the return value would need to be specified. The receiver of the call, System.out, also has a statically known type, which happens to be java.io.PrintStream.

Armed with the needed type information, the javac compiler can generate the appropriate bytecode instructions:

   ldc #2
astore_1
getstatic #3
aload_1
invokevirtual #4

If you're not familiar with bytecode, the important thing to understand is that a lot of the bytecode execution in the JVM involves operations on values in an operand stack. The operand stack is the virtual machine equivalent of the hardware registers in a real machine. Most of the bytecode instructs the JVM to push a value in a local value onto the operand stack, pop a value off the stack into a local variable, duplicate a value in the stack, swap values in the stack, or execute operations that produce or consume values.

For example, here's a commented version of the bytecode:

   ldc #2  // Push the String "Hello World" onto the stack
astore_1 // Pop the value "Hello World" from the stack and store it in local variable #1
getstatic #3 // Get the static field java/lang/System.out:Ljava/io/PrintStream from the class
aload_1 // Load the String referenced from local variable #1
invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

Clearly the invokevirtual bytecode instruction is different than the other bytecode instructions in the example. It invokes a method rather than manipulating the operand stack. The comment for the invokevirtualbytecode instruction might look odd too. It identifies the following:


  • The receiver class providing the method: java.io.PrintStream
  • The method name: println
  • The type of the method argument: (Ljava/lang/String;) for String
  • The method's return type: V for void

This information provides a signature for the method invocation. In response to the invokevirtual bytecode instruction, the JVM looks for a method with the supplied signature, in this case,println:(Ljava/lang/String;)V in the java.io.PrintStream class. If the method isn't in that class, the JVM searches up the chain of the class's superclasses.

To learn more about invokevirtual and other "invoke" type bytecode instructions, see JSR 292 — The Next Step in Dynamic Language Support.

Awkward Attempts at Meeting the Requirements

Because dynamically typed languages don't provide type information until runtime, implementers must try various approaches to meet the bytecode requirements for method invocation, none of which is optimal. For example, suppose the following code snippet exists in a hypothetical dynamically typed language:

   function max (x,y) {
if x.lessThan(y) then y else x
}

Notice that no type is specified for the receiver or the arguments — remember that dynamically typed languages don't provide type information until runtime. As a result, the code does not meet the know-in-advance type requirements for method invocation. The code can't be successfully compiled into bytecode on the Java platform.

One common approach to solving this problem is to create language-specific Java types for the return value and method arguments, especially those which act as method call receivers. For example, a dynamically typed language implementation might change the previous code snippet to the following:

   MyObject function max (MyObject x,MyObject y) {
if x.lessThan(y) then y else x
}

The language-specific base type MyObject contains the method isLessThan and any other methods that a dynamic language might want to use, in order to meet the bytecode requirements for the method invocation.

Another technique to solve the problem of receiver typing is called reflected invocation. This approach uses a java.lang.reflect.Method object to invoke the method. Using a Method object to do the method invocation circumvents having to directly invoke the method, and as a result, bypasses the requirement of having to specify the type of the returned value or the types of any parameters.

Implementers of dynamically typed languages have tried various approaches to meet the bytecode requirements for method invocation, none of which are optimal.

A third approach that implementers of dynamic languages use is to create a language-specific interpreter for method invocation to run on top of the JVM.

Creating a language-specific base type meets the requirements of the Java bytecode, but it is limited by the need to statically type each receiver to a prespecified base type. One problem with this technique is that a language implementer must think up a list of all methods in advance to put into the base type. Future methods, such as those defined by an end user, must be simulated less directly with a catch-all method — often called invoke or apply. Also, unless interface injection is an option, JVM system types such as String and Integer cannot serve directly as receivers of language-specific method calls.

The reflected invocation approach has some of its own restrictions. For example, a java.lang.reflect.Method object provides access to a method on a class or interface, just what an implementer of a dynamic language needs, but the object must come from a specific Java type available at runtime. Although dynamic languages can provide type information at runtime, not all of them can provide normal Java types for reflection. This is particularly true for dynamic languages such as JRuby or Rhino, which have interpreters.

Running an interpreter on top of the JVM to handle method invocations is relatively slow, certainly slower than having the JVM directly handle the processing.


JSR 292 — The Next Step in Dynamic Language Support

JSR 292 introduces a new Java bytecode instruction for the JVM, invokedynamic, and a new method linkage mechanism.

JSR 292 aims to solve the problems inherent in trying to fit a square peg — method invocation in a dynamically typed language — into a round hole — the statically-based Java bytecode requirements. It does this by introducing a new Java bytecode instruction for the JVM, invokedynamic, and a new method linkage mechanism.

Bytecode Instructions for Method Invocation

Since its inception, the Java Virtual Machine Specification has specified four bytecodes for method invocation:


  • invokevirtual - Invokes a method on a class. This is the typical type of method invocation.
  • invokeinterface - Invokes a method on an interface.
  • invokestatic - Invokes a static method on a class. This is the only kind of invocation that lacks a receiver argument.
  • invokespecial - Invokes a method without reference to the type of the receiver. Methods called this way can be constructors, superclass methods, or private methods.

Let's examine two of these bytecodes: invokevirtual, because it's the most typical type of method invocation, and invokeinterface, because it's similar in format to the new invokedynamic instruction.

The invokevirtual Instruction

Recall the invokevirtual bytecode instruction that was shown in the earlier bytecode example.

   invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

The invokevirtual part of the instruction is the one-byte operation code. The remainder of the instruction, #4, is the two-byte operand, which provides information about the method call in an abstract way. The operand refers to an entry in a pool of constants. The entry contains a symbolic reference that bundles together information pertinent to the method invocation. The information includes the receiver class that contains the method, the method name, and the method descriptor. The method descriptor specifies the method's return type and the types of its arguments.

As mentioned previously, the receiver in the method invocation is java.io.PrintStream. The method name is println. The method's return type is void — represented by the V. And the method has one Stringargument — represented by (Ljava/lang/String;).

The syntax of the invokevirtual bytecode instruction is as follows:

   invokevirtual <method-specification>

where <method-specification> is the constant pool index as described above.

The invokeinterface Instruction

The invokeinterface bytecode instruction for a Java program might look similar to the following:

   invokeinterface #9,  2; //InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z

The syntax for the invokeinterface bytecode instruction is as follows:

   invokeinterface <method-specification> <n>

where <method-specification> is a two-byte constant pool index specifying an interface name, a method name, and a descriptor, and <n> is a two-byte operand that specifies the number of arguments.

As is the case for invokevirtual, the descriptor specifies the method's argument types as well as the method's return type. In this example, the <method-specification> specifies that the interface isjava.util.List and the method is add. The type descriptor specifies that the method takes arguments of type java.lang.Object, represented by Ljava/lang/Object, and returns a boolean result, represented by the Z code.

The <n> value in the example is 2, indicating that the method takes 2 arguments, including the receiver.

The invokedynamic Instruction

The syntax of the new invokedynamic bytecode instruction is similar to that of the invokeinterface instruction.

   invokedynamic <method-specification> <n>

However, unlike the invokeinterface instruction, the <method-specification> only needs to specify a method name and descriptor. In this case, the two-byte number <n> must be zero. Some JVMs may use these extra bytes internally to link the instruction to runtime structures.

An invokeinterface bytecode instruction might look similar to the following:

   Invokedynamic #10; //NameAndTypelessThan:(Ljava/lang/Object;Ljava/lang/Object;)

Significantly, the invokedynamic bytecode instruction enables an implementer of a dynamic language to translate a method invocation into bytecode without having to specify a target type that contains the method. The method specification in this case is a simplified constant pool reference, which specifies only a method name and type descriptor. The descriptor specifies the return type of the call and the type of method arguments. As withinvokestatic, none of the arguments is singled out as a receiver.

But wait. How does the JVM find the method if the receiver type isn't supplied? After all, the JVM needs to link to and invoke a real method on a real type. The answer to that question is that JSR 292 also includes a new linkage mechanism for dynamically typed languages. When the JVM sees an invokedynamic bytecode, it uses the new linkage mechanism to get to the method it needs.

A New Dynamic Linkage Mechanism: Method Handles

Method handles enable the JVM to invoke the correct method in response to an invokedynamic bytecode instruction.

The new linkage mechanism for dynamically typed languages involves a new structure called method handles. JDK 7 includes a new package, java.dyn, that contains the classes associated with dynamic language support in the Java platform. One of the classes in the package is MethodHandle. A method handle is a simple object of type java.dyn.MethodHandle that contains an anonymous reference to a JVM method. A method handle is callable just like a named reference to a method. What makes it unique, however, is that it is accessed through a pointer structure, as opposed to a linked name.

As with the other invoke instructions, the first time an invokedynamic instruction is executed, it is linked. When this linking happens, a method handle is assigned to the individual invokedynamic instruction as its particular target. Each time that particular instruction is executed, the JVM invokes the target method handle. Interestingly, the target of any given invokedynamic instruction can change over time in response to changes in the dynamic language program.

Another part of this new linkage mechanism is the bootstrap method. A bootstrap method is a method handle that is called once for each invokedynamic instruction, when the instruction is linked. The bootstrap method determines which target method to assign initially to the instruction. Each class that contains at least one invokedynamic instruction must also specify a bootstrap method.

The bootstrap mechanism provides a way for a language runtime to participate in method dispatching at runtime, but the approach also enables the JVM to bypass the language runtime if the method dispatch decision doesn't change. The first time the JVM sees an invokedynamic bytecode with a receiver and argument, it calls a bootstrap method. Calling into a language-supplied method like this is termed an up-call.

The bootstrap method, in turn, creates a call site object and chooses an appropriate target method handle. The JVM then associates the method referenced by the method handle with this invokedynamic bytecode. The next time the JVM executes an invokedynamic bytecode, it immediately invokes the previously chosen method. The idea here is for the JVM to make an up-call into the runtime of the dynamically typed language only for an unlinked dynamic call site, that is, for an invokedynamic instruction that hasn't yet been linked to a target method. However, once the dynamic call site is linked, the JVM directly calls the target method without the need for doing an up-call.

The bootstrap method is also responsible for creating a call site object of type java.dyn.CallSite that is permanently associated with the linked invokedynamic instruction. The call site object provides an API to get and set the target method. The call site object can also be subclassed to contain language-specific logic for linking the instruction. In particular, it can be used by the language runtime to change the target method of the instruction over time.

A method handle is quite simple. All it contains is a type token of class java.dyn.MethodType that describes a specific type. Also, a method handle implicitly has an invoke method associated with it. To call a method handle, you call its invoke method in much the same way as you call object methods, that is, MethodHandle.invoke(...). Because each method handle has its own type, it will accept only an invoke call of that type. If the type of the call doesn't match the type of the method handle, the method handle throws an exception.

Here, for example, is a snippet of bytecode that calls a method handle:

   getfield myMH
ldc #999
invokevirtual #44 //Method java/dyn/MethodHandle:invoke(I)I
istore 5

In this example, the call is to a method handle named myMH with a single int argument. The call also expects an int type to be returned. The method handle has to accept that signature type. Before allowing the call, the JVM will verify (each time) that the method handle includes a type token that matches the call's descriptor — in this case, (I)I.

In response, the method handle directs the JVM to the appropriate target function. As shown in Figure 1, the method handle could point to a function named addOne in class Foo.


Method Handle

Figure 1. Method Handle

The method handle in the previous example provides a direct reference to a Java method — this is the simplest kind of mehod handle. There are also method handles that can adjust the argument list in the course of the call, inserting, converting, or deleting arguments or return values. There is an API on the type java.dyn.MethodHandles for creating all these kinds of method handles and more.

When a bootstrap method is called for an unlinked dynamic call site, it is passed the following information:


  • The java.lang.Class object for the class containing the instruction.
  • The method name represented as a String.
  • The resolved descriptor for the instruction, represented as a java.dyn.MethodType token.

The bootstrap method must then return a java.dyn.CallSite object that reifies the call site. The term reify means turning an abstract concept into something real. So in reifying the call site, the CallSite object makes the call site real to the Java platform. The CallSite object includes getTarget and setTargetmethods to get and set the call site's target method, that is, a method handle that represents the linkage state of theinvokedynamic instruction.

The bootstrap method may also store the call site object in any language-specific runtime structure, such as a table of known call sites.

What's significant here is that the CallSite object lets the language runtime change the target method of the reified call site. In essence, the bootstrap method acts as a messenger that relays a call for help from theinvokedynamic instruction to the language runtime. The answer to the call for help is provided by the CallSite and its setTarget() method. When the linkage is complete, the messenger disappears, and the call site is now capable of directly calling the target method.

Here is a source code example that includes a method handle and a bootstrap method.

   import java.dyn.*;

public class Hello {
public static void main(String... av) {
if (av.length == 0) av = new String[] { "world" };
greeter(av[0] + " (from a statically linked call site)");
for (String whom : av) {
greeter.<void>invoke(whom); // strongly typed direct call
// previous line generates invokevirtual MethodHandle.invoke(String)void
Object x = whom;
InvokeDynamic.hail(x); // weakly typed invokedynamic
// previous line generates invokedynamic MethodHandle.invoke(Object)Object
}
}

static void greeter(String x) { System.out.println("Hello, "+x); }
// intentionally pun between the method and its reified handle:
static MethodHandle greeter
= MethodHandles.lookup().findStatic(Hello.class, "greeter",
MethodType.make(void.class, String.class));

// Set up a class-local bootstrap method.
static { Linkage.registerBootstrapMethod("bootstrapDynamic"); }
private static CallSite bootstrapDynamic(Class caller, String name, MethodType type) {
assert(type.parameterCount() == 1 && (Object)name == "hail"); // in lieu of MOP
System.out.println("set target to adapt "+greeter);
MethodHandle target = MethodHandles.convertArguments(greeter, type);
CallSite site = new CallSite(caller, name, type);
site.setTarget(target);
return site;
}
}

In this example, a Java class named Hello registers a bootstrap method, bootstrapDynamic, as follows:

   // Set up a class-local bootstrap method.
static { Linkage.registerBootstrapMethod("bootstrapDynamic"); }

The bootstrap method creates a CallSite and uses its setTarget() method to set the target for the call site to the method handle, greeter. The call to convertArguments creates an adapter method handle that wraps the original greeter, so that the call site target's type will match the descriptor of the invokedynamic instruction.

    static MethodHandle greeter
= MethodHandles.lookup().findStatic(Hello.class, "greeter",
MethodType.make(void.class, String.class));


private static CallSite bootstrapDynamic(Class caller, String name, MethodType type) {
assert(type.parameterCount() == 1 && (Object)name == "hail"); // in lieu of MOP
System.out.println("set target to adapt "+greeter);
MethodHandle target = MethodHandles.convertArguments(greeter, type);
CallSite site = new CallSite(caller, name, type);
site.setTarget(target);
return site;
}

In summary, method handles provide the linkage mechanism that enables the JVM to invoke the correct method in response to an invokedynamic bytecode instruction. When the JVM sees an invokedynamic bytecode, it uses method handles to get to the method it needs. Note that method handles provide a better way to meet the bytecode requirements for method invocation than the reflected invocation approach. Recall that the reflected invocation approach uses java.lang.reflect.Method objects to invoke the method. That approach requires a simulation layer that imposes extra complexity and execution overhead. By comparison, method handles provide a way to name and interconnect methods without regard to method type or placement, and with full type safety and native execution speed.

Modifying Classes at Runtime Through Interface Injection

Interface injection is the ability to modify classes at runtime so that they can implement new interfaces. It can enable a dynamically typed language in the JVM to easily integrate with other languages.

Interface injection is the ability to modify classes at runtime so that they can implement new interfaces. Adding new methods is a common feature in dynamically typed languages, especially in scripting languages. Interface injection can provide a structured way to accomplish this in the JVM. However, it has not been part of the JVM standard. The feature is being investigated for inclusion in JSR 292.

With interface injection supported in the JVM, a language runtime could add new capabilities for its own use in a modular way. For example, suppose a class or set of classes in a language running in the JVM needs a type of serialization that is currently not implemented in the language. The language runtime could define that serialization as an injectable interface. It could also define an injector method. That method would know about the classes to which the language wants to assign the new serialization capability. The injection is done either initially as a configuration step, or lazily when the JVM first attempts to invoke an injectable method on a previously untouched class.

Interface injection has a variety of potential applications. One of them is enabling a dynamically typed language in the JVM to easily integrate with other languages in the JVM. The approach here is to inject the base or master interface of the language. For example, Jython has the base interface org.python.cor.PyObject. Once injected, the base interface can be used as the conduit for communication between the injecting language and libraries in other languages.


Summary

Over the years, the JVM has been host to a growing number of languages, including implementations of dynamically typed languages such as Ruby and Python. Support for dynamically typed languages in the JVM is very attractive to application developers who build applications in these languages. That's because dynamic typing gives developers a lot of flexibility and the JVM delivers a lot of execution efficiency.

However, implementers of compilers for dynamically typed languages have found it difficult to meet the JVM bytecode requirements for method invocation. JSR 292 addresses that problem by providing a new bytecode,invokedynamic, and a new linkage mechanism based on method handles. Also being investigated for inclusion in JSR 292 is interface injection, the ability to modify classes at runtime so that they can implement new interfaces.


For More Information


http://java.sun.com/developer/technicalArticles/DynTypeLang/