views:

277

answers:

4

I want to revisit an old question of mine about in-memory "compilation" of classes. Since about 1/2 a year have passed since I asked (and was somewhat answered), I'd like to re-raise the issue and see if something new would come up (so no, I don't consider this a duplicate).

The old question can be found here: http://stackoverflow.com/questions/616532/on-the-fly-in-memory-java-code-compilation-for-java-5-and-java-6 - I suggest reading it (and the answers) before answering this question.

I'm quite content with beanshell doing the heavy work of evaluating string of a java class to an actual Class object. However, beanshell has been standing on version 2.0b4 for ages now and its limitations (no constructor, not even default; no generics, no for-each, no enums...) are annoying.

Reminder - this is to be used as a debugging interface, so performance considerations are negligible. However, I can't have server restarts, can't send class files to the location and JSPs are a very bad choice for me (I won't go into reasons here). Also, the end product must be a Class (or an Object of that class) so I could pass it around.

Some limitations: I can't have a JDK, so no javax.tools.JavaCompiler. I can't have JSPs since I don't have tomcat or other "real" web container. Java 5 syntax support would be great, especially generics, enums and parameterization. Support for default constructors would be very nice.

Any ideas?

Edit 1: I just found out that there is a round-about way of having constructors in beanshell - however you have to declare them "public void XXX(){...}" instead of the usual way "public XXX(){...}".

A: 

Can't you just copy over to tools.jar and get the javax.tools.JavaCompiler and add it to the classpath? Or is it a licensing issue.

This code, and tools.jar on the classpath, seems to work:

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;


public class Main
{
    public static void main(final String[] argv)
        throws IOException
    {
        final File[]                             files;
        final JavaCompiler                       compiler;
        final StandardJavaFileManager            fileManager;
        final Iterable<? extends JavaFileObject> compilationUnits;

        files = new File[]
        {
            new File(argv[0]),
        };        
        compiler         = ToolProvider.getSystemJavaCompiler();
        fileManager      = compiler.getStandardFileManager(null, null, null);
        compilationUnits = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(files));

        compiler.getTask(null, fileManager, null, null, null, compilationUnits).call();
        fileManager.close();
    }
}
TofuBeer
No. Licensing issue. Also, the client can change the JRE my server is running with, so it's a compatibility issue as well.
Ran Biron
+2  A: 

If you can't bundle the SUN JDK tools.jar due to licensing reasons, perhaps you could include the Eclipse JDT Core compiler instead, see

http://help.eclipse.org/galileo/index.jsp?topic=/org.eclipse.jdt.doc.isv/guide/jdt_api_compile.htm

This is e.g. what the Jetty web server's JSP implementation does.

Stefan L
since I do use jetty, I might consider this. good call.
Ran Biron
Well, I did. It would require me to either: 1. depend directly on JDT, which is a problem for me (organization level) or 2. depend on jetty internals which are not guaranteed not to change. Thanks anyway
Ran Biron
A: 

I remember reading about the Bytecode Engineering Library (BCEL) a long time ago, back when Java 1.4 was all the rage. See http://jakarta.apache.org/bcel/index.html. I never used it, so I only mention it because it seems close to what you are asking about (and it works, or at least worked, with older VMs) and I didn't see anybody mention it yet.

Gabe Johnson
Would look into it. Doesn't sound like a valid solution though - too much overhead.
Ran Biron
A: 

Is there a specific reason why it has to be a Java string that produces the class/object? My spontaneous reaction is that JRuby is what you're looking for - it seems to be a very solid platform, and Ruby has a strong tradition of meta-programming.

gustafc
Has to be a Java string since thats what all of the developers here know. I want to write a "plugin" that will connect to a running server and help debug it (produce log message, query internal structures, etc). Forcing everyone to learn ruby would make this obsolete before it starts (no one would learn - no one would use it).
Ran Biron
How sad - it would fit you like a glove. There's a reason why Java usually isn't used for scripting, as you've noticed. I assume Groovy and JavaScript (both more Java-ish than Ruby) are out of the question, too?
gustafc
@gustafc: yes, for the same reasons.
Ran Biron