Laura
Laura

Reputation: 279

Changing the behaviour of a Java app dynamically using Groovy

I am investigating methods of dynamically modifying the behaviour of a Java application (specifically, I'm trying to make a Minecraft mod that allows users to modify the behaviour of the objects they find by writing code without the need to restart the game) and I stumbled upon Groovy. My question is: is it possible to integrate Java and Groovy in such way they "share" objects? (I'm thinking about having a specific set of classes that are actually Groovy code so you can change the code during runtime, similarly to what you can do in any Smalltalk implementation)

Upvotes: 3

Views: 1678

Answers (4)

Jerry101
Jerry101

Reputation: 13367

What a cool idea!

1. Groovy: Java and Groovy can share objects and call back and forth. Groovy classes that implement Java interfaces are easily called from Java. (There are other ways, like calling groovyObject.invokeMethod("methodName", args) from Java.) Of JVM languages, Groovy has the tightest integration with Java. It's also easy for Java programmers to learn since it shares so much with Java.

The book Groovy in Action has a chapter on "Integrating Groovy" that explains and compares the approaches (in more detail than the reference docs do): GroovyShell, GroovyScriptEngine, GroovyClassLoader, Spring integration, and JSR-223 ScriptEngineManager. GroovyClassLoader is the most capable choice.

However, while it's easy to compile and load Groovy code at runtime, I'm puzzled about how to change behavior of existing object instances (short of the notes below on hot swapping). (It might depend on whether the class overrides a Java interface or subclasses a Java class.) Consider:

class G implements Runnable {
  void run() { println 'Groovy' }
}

g = new G()
g.run()

This prints Groovy. Now redefine the class:

class G implements Runnable {
  void run() { println 'Groovy!' }
}

g1 = new G()
g.run()
g1.run()

This prints

Groovy
Groovy!

Now use the meta-class to change methods at runtime:

G.metaClass.run = { println 'Groovy!!!' }

g2 = new G()
g.run()
g1.run()
g2.run()

This prints

Groovy
Groovy!
Groovy!

If we omitted implements Runnable from those class definitions, then the last step would instead print

Groovy
Groovy!
Groovy!!!

But with our class that does implement Runnable, now do:

G.metaClass.run = { println 'Very Groovy!!!' }

g3 = new G()
g.run()
g1.run()
g2.run()
g3.run()

this prints:

 Groovy
 Groovy!
 Very Groovy!!!
 Very Groovy!!!

A workaround would implement the methods in closures held in class variables.

2. Hot Swapping: If the main point is to redefine method bodies at run time for classes with existing instances, then you can simply run within an IDE's debugger and use hot swapping.

E.g. for IntelliJ, here are the instructions to configure hot swapping of Java and Groovy code.

3. Expanded Hot Swapping: If you also want to be able to add/remove methods and instance variables at run time, then see this JetBrains article on extended hot swapping via DCEVM (Dynamic Code Evolution VM).

See Hot Swap code code at https://github.com/HotswapProjects

Also see this SO Q&A on hot swapping techniques.

Upvotes: 3

Fincio
Fincio

Reputation: 198

Yes, You can achieve that. For example, You have something written in java that uses some objects from let's say spring context. So now what u can do is :

  • execute groovy script before that java code is executed,
  • use delegate design pattern to wrap it, overwrite some methods
  • finaly put it back into context.

So basicly in moment where Your java code is executed, he'll get a wrapped object with some changes made in runtime.

If that's what are You trying to do, let me know i could write You some example code.

Upvotes: 1

Anderson Vieira
Anderson Vieira

Reputation: 9049

Take a look at Integrating Groovy in a Java Application. It shows examples of how you can run a Groovy script from inside a Java application and share data between them using groovy.lang.Binding.

Upvotes: 4

Quicksilver002
Quicksilver002

Reputation: 735

I'm not sure that's something you can accomplish with Groovy without compiling it. You could do it, but the "scripting" aspect of Groovy won't help you. I'd look into having the player write javascript and using Java's ScriptEngine. See here: http://docs.oracle.com/javase/7/docs/technotes/guides/scripting/programmer_guide/

Upvotes: 1

Related Questions