Extending Java classes from JavaScript

Published August 23, 2015
Advertisement
Hi! So this entry will be dealing with the Nashorn JavaScript engine found in Java 8+, specifically, how to extend a Java class from JavaScript and use the resulting JavaScript object in the Java side.

Extending Java classes from JavaScript



First this what I want to do:

  • Extend a Java class from JavaScript implementing a specific method.
  • Fetch the resulting object from Java and call that method.

So lets start by initializing the script engine:
String[] options = new String[] { "--language=es6" }; NashornScriptEngineFactory factory = new NashornScriptEngineFactory();NashornScriptEngine engine = (NashornScriptEngine) factory.getScriptEngine(options);
That will get us a Nashorn JS engine instance supporting some ECMAScript 6 features (the ones I want specifically are 'let' and 'const'). I spent hours Googling for a way to pass the "--language=es6" argument to the engine initialization since I was creating it with Java's "standard" script engine API instead of using the Nashorn factory object directly.

Now we need to load the script file, for that I'll use my ResourceManager and TxtFileLoader classes:// Create a manager at top level folder at 'res'.ResourceManager rm = new ResourceManager( "res" );// Now register the text file loader at sub folder 'script'.rm.registerResource( StringBuilder.class, new TxtFileLoader(), "script" );// Now load the script named 'testEntitySystem.js'.String scriptSource = rm.get( StringBuilder.class, "testEntitySystem.js" ).toString();
The long term goal is allowing me to have some EntitySystems implemented in JavaScript, so what we'll do on the JS side is to extend an EntitySystem and give it some implementation of 'processEntities(entities)' method, here is the script file:function main(){ // We need this one for initializing the EntitySystem. const Aspect = Java.type("com.artemis.Aspect") // Now fetch the type. const EntitySystem = Java.type("com.artemis.EntitySystem") // Prepare for extension. const JSEntitySystem = Java.extend(EntitySystem) // Now return an instance that implements the abstract 'processEntities' method. return new JSEntitySystem(Aspect.EMPTY_ASPECT) { processEntities: function(entities) print("Extended from JavaScript!") }}// Calling the function so it will return the EntitySystem instance to Java after execution. main()
Now all we need to do is to eval the script (or compile then execute) with the Nashorn engine instance and call the method:Object jsSystem = null;try{ jsSystem = engine.eval( scriptSource );}catch ( ScriptException e ){ e.printStackTrace();}// Lets see what kind of class it is...System.out.println(jsSystem.getClass());// Is it really a subclass of EntitySystem?System.out.println(jsSystem instanceof EntitySystem);// Now lets try to run the JS implementation!((EntitySystem)jsSystem).process();
And this outputs:[quote]
class com.artemis.EntitySystem$$NashornJavaAdapter
true
Extended from JavaScript![/quote]

We see that it really is an instance of EntitySystem, it executes the JS implementation just fine, and it seems the Nashorn engine is creating an adhoc adapter class for extension purposes, cool!

The fun thing here is that I can do "gameWorld.addObserver(jsSystem)" just fine and it will get iterated over like any other EntitySystem in the engine, so I can have systems both implemented in Java and in JavaScript working side to side.

Given how easy is the integration I'm pretty sure I'll be using this a lot in the future for scripting all sort of things. Thats all, cya later!
5 likes 3 comments

Comments

TheChubu

I'd love to put some space in between paragraphs and the code blocks but the editor eats the new lines away (and also did eat 80% of the entry the first time I previewed it). So just be glad this one wasn't in a PDF like the last one :P

August 23, 2015 09:37 PM
CulDeVu

Check out my solution that I do on my journal: http://www.gamedev.net/blog/1084/entry-2261493-fluid-dynamics-advection/

I just put a "." between every paragraph that I want separated. It works pretty well and is also nearly unnoticeable :D

August 25, 2015 01:47 AM
TheChubu

Ohhh you're the master of tricking the editor!

August 25, 2015 01:53 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement