Klein Thibaut
Klein Thibaut

Reputation: 11

Java Dynamic implementation of abstract method

I'm trying to do the following in Java:

I have a collection of strings (anywhere between 1 and 10 000), each string contains a different method body (they are written in Java code) for the same abstract method of a class. For example:

string1= "int a=1;" 
string2="System.out.println(\"HelloWorld\");"
...

each of the string could be an implementation of the following abstract method:

abstract class FOO{
    public abstract void doSomething();
}

For each string I'd like to generate an instance of FOO to use.

I'm not quite sure what is the best way to go: I've searched the web and came up with these suggestions:

Is there any other suggestions, as these look a bit complicated (at least to myself)...

Thanks for your help

Edit:

I might be going the wrong way about my problem. Here is what I'm ultimately trying to achieve :

I have an interface representing a node in a tree

public  interface Node{
    public <T> void process(T input);

/* ... other methods not related to my problem ...*/ }

When you provide an instance of T to the node it does something to it (some might need access to other methods of Node), and passes it on to the child nodes.

The problem is (the spec for the program) : the program reads and builds the nodes from text files, including that method body (the bodies are in java). It then builds the tree and returns it.

I'm under the impression that to do this, I must somehow generate an implementation of Node for each of the methods provided in the text file. I might be wrong though, and there might be a better way...

Upvotes: 1

Views: 890

Answers (1)

Peter Lawrey
Peter Lawrey

Reputation: 533660

Perhaps what you want is BeanShell

BeanShell is a small, free, embeddable Java source interpreter with object scripting language features, written in Java. BeanShell dynamically executes standard Java syntax and extends it with common scripting conveniences such as loose types, commands, and method closures like those in Perl and JavaScript.

You can use BeanShell interactively for Java experimentation and debugging as well as to extend your applications in new ways. Scripting Java lends itself to a wide variety of applications including rapid prototyping, user scripting extension, rules engines, configuration, testing, dynamic deployment, embedded systems, and even Java education.

BeanShell is small and embeddable, so you can call BeanShell from your Java applications to execute Java code dynamically at run-time or to provide extensibility in your applications. Alternatively, you can use standalone BeanShell scripts to manipulate Java applications; working with Java objects and APIs dynamically. Since BeanShell is written in Java and runs in the same VM as your application, you can freely pass references to "live" objects into scripts and return them as results.

In short, BeanShell is dynamically interpreted Java, plus a scripting language and flexible environment all rolled into one clean package.

Summary of features

  • Dynamic execution of the full Java syntax, Java code fragments, as well as loosely typed Java and additional scripting conveniences.
  • Transparent access to all Java objects and APIs.
  • Runs in four modes: Command Line, Console, Applet, Remote Session Server.
  • Can work in security constrained environments without a classloader or bytecode generation for most features.
  • The interpreter is small ~150K jar file.
  • Pure Java.
  • It's Free!!

An alternative is to use a library I wrote which wraps the Compiler API so that it compiles in memory and loads into the current ClassLoader (by default)

http://sourceforge.net/projects/essence/files/Essence%20Java%20Config.%20Files/Essence%20JCF%201.02/

http://vanillajava.blogspot.co.uk/2010/11/more-uses-for-dynamic-code-in-java.html

// this writes the file to disk only when debugging is enabled.
CachedCompiler cc = CompilerUtils.DEBUGGING ?
        new CachedCompiler(new File(parent, "src/test/java"), new File(parent, "target/compiled")) :
        CompilerUtils.CACHED_COMPILER;

String text = "generated test " + new Date();
Class fooBarTeeClass = cc.loadFromJava("eg.FooBarTee", "package eg;\n" +
    '\n' +
    "import eg.components.BarImpl;\n" +
    "import eg.components.TeeImpl;\n" +
    "import eg.components.Foo;\n" +
    '\n' +
    "public class FooBarTee{\n" +
    "    public final String name;\n" +
    "    public final TeeImpl tee;\n" +
    "    public final BarImpl bar;\n" +
    "    public final BarImpl copy;\n" +
    "    public final Foo foo;\n" +
    '\n' +
    "    public FooBarTee(String name) {\n" +
    "        // when viewing this file, ensure it is synchronised with the copy on disk.\n" +
    "        System.out.println(\"" + text + "\");\n" +
    "        this.name = name;\n" +
    '\n' +
    "        tee = new TeeImpl(\"test\");\n" +
    '\n' +
    "        bar = new BarImpl(tee, 55);\n" +
    '\n' +
    "        copy = new BarImpl(tee, 555);\n" +
    '\n' +
    "        // you should see the current date here after synchronisation.\n" +
    "        foo = new Foo(bar, copy, \"" + text + "\", 5);\n" +
    "    }\n" +
    '\n' +
    "    public void start() {\n" +
    "    }\n" +
    '\n' +
    "    public void stop() {\n" +
    "    }\n" +
    '\n' +
    "    public void close() {\n" +
    "        stop();\n" +
    '\n' +
    "    }\n" +
    "}\n");

// add a debug break point here and step into this method.
FooBarTee fooBarTee = new FooBarTee("test foo bar tee");
Foo foo = fooBarTee.foo;
assertNotNull(foo);
assertEquals(text, foo.s);

Upvotes: 3

Related Questions