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!

1 Answer 1

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?

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks! But I don't want to run the code, I just want the bytecode in a byte array if at all possible.
It appears that cannot be done without having a .class file on disk. See this answer for details.
Hm. So as a next best thing, can I make Janino create an actual .class file for me?
See my edit - looks like you can do that without Janino... stackoverflow.com/questions/21544446/…
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.