1

How can I use the janino compiler to compile a simple java source from string to bytecode in byte array?

I have so far been trying to make sense of the janino documentation here (under SimpleCompiler) and here on how to go about compiling one single java source into one single class in bytecode format but I don't think I am doing it right.

So far my naive approach looks like this:

    private void testJanino() {
        String cn = "Arne";
        SimpleCompiler sc = new SimpleCompiler();
        try {
            sc.cook("public class Arne{ public float doWork(){return 42.0f;}}");
            InputStream is = sc.getClassLoader().getResourceAsStream(cn);
            if (null != is) {
                int len = is.available();
                byte[] ar = new byte[len];
                System.out.println("SZ:" + len);
                int r = is.read(ar);
                System.out.println("READ:" + r);
            } else {
                System.out.println("NO IS");
            }
        } catch (CompileException e) {
            e.printStackTrace();

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

Output is NO IS suggesting that I am trying to use it incorrectly.

So what should I be doing instead?

EDIT: I have been going at this non-stop and I just cant seem to get what I want. Here is an attempt to use the janino UnitCompiler class:

  private String mClassName = "Arnulf";
  private String mCode = "public class " + mClassName + "{ public float doWork(){return 42.0f;}}";
  private void testJanino2() {
        try {
            InputStream is = new ByteArrayInputStream(mCode.getBytes(StandardCharsets.UTF_8));
            Scanner s = new Scanner(mClassName, is);
            Parser p = new Parser(s);
            Java.CompilationUnit compilationUnit = p.parseCompilationUnit();
            IClassLoader iClassLoader = new LOLClassLoader(null);
            UnitCompiler uc = new UnitCompiler(compilationUnit, iClassLoader);
            uc.compileUnit(false, false, false);
        } catch (CompileException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Where LOLClassLoader is a simple "log everything, do nothing" kind of class that extends IClassLoader.

This ends up in a nullpointer like this:

java.lang.NullPointerException
    at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:429)
    at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:393)
    at org.codehaus.janino.UnitCompiler.access$400(UnitCompiler.java:185)
    at org.codehaus.janino.UnitCompiler$2.visitPackageMemberClassDeclaration(UnitCompiler.java:347)
    at org.codehaus.janino.Java$PackageMemberClassDeclaration.accept(Java.java:1139)
    at org.codehaus.janino.UnitCompiler.compile(UnitCompiler.java:354)
    at org.codehaus.janino.UnitCompiler.compileUnit(UnitCompiler.java:322)
    at com.mypackage.backend.MyServlet.testJanino2(MyServlet.java:60)
    at com.mypackage.backend.MyServlet.doPost(MyServlet.java:208)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:127)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:63)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:125)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectRequest(DevAppServerModulesFilter.java:366)
    at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectModuleRequest(DevAppServerModulesFilter.java:349)
    at com.google.appengine.tools.development.DevAppServerModulesFilter.doFilter(DevAppServerModulesFilter.java:116)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:98)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:491)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

Any help or tips are welcomed at this point.

Thanks!

Mr. Developerdude
  • 9,118
  • 10
  • 57
  • 95

1 Answers1

1

So what should I be doing instead?

This seems to work:

private void testJanino() throws Exception {
    SimpleCompiler sc = new SimpleCompiler();
    sc.cook("public class Arne{ public float doWork(){return 42.0f;}}");
    Class<?> arneClass = sc.getClassLoader().loadClass("Arne");
    Object arne = arneClass.newInstance();
    Method doWork = arneClass.getDeclaredMethod("doWork");
    Object result = doWork.invoke(arne, new Object[0]);
    System.out.println(result);
}

If you really want to dynamically compile a class, then be able to get its bytecode in a stream, check out How do you dynamically compile and load external java classes?

Community
  • 1
  • 1
gknicker
  • 5,509
  • 2
  • 25
  • 41
  • Thanks! But I don't want to run the code, I just want the bytecode in a byte array if at all possible. – Mr. Developerdude Jan 24 '15 at 01:31
  • It appears that cannot be done without having a `.class` file on disk. See [this answer](http://stackoverflow.com/a/17322761/1594449) for details. – gknicker Jan 24 '15 at 01:41
  • Hm. So as a next best thing, can I make Janino create an actual .class file for me? – Mr. Developerdude Jan 24 '15 at 01:48
  • See my edit - looks like you can do that without Janino... http://stackoverflow.com/questions/21544446/how-do-you-dynamically-compile-and-load-external-java-classes – gknicker Jan 24 '15 at 01:52
  • Actually I avoided that route because my environment has blacklisted it (GAE). But there is hope, someone on that thread said Janino could be told to create the class files. – Mr. Developerdude Jan 24 '15 at 02:06