This discussion is archived
3 Replies Latest reply: Apr 25, 2013 12:44 PM by jschellSomeoneStoleMyAlias RSS

Dynamic compilation in memory

Gen.Java Newbie
Currently Being Moderated
Hello,

I have used javax.tools.ToolProvider to compile a simple class that comes from a CharSequence object in memory, and it works just fine.

Now, I need to reference another class that comes also from a CharSequence object in memory. Which method in the ForwardingJavaFileManager I should override to make this class available to the main class.

Thank you

The class I need to reference is in class (.class) format not the java source format (.java).

Edited by: Gen.Java on Apr 23, 2013 2:05 AM
  • 1. Re: Dynamic compilation in memory
    jschellSomeoneStoleMyAlias Expert
    Currently Being Moderated
    You question isn't clear.

    Presumably you have source that you compiled to create a class. That compilation is occurring in your application.

    That step however has nothing to do with what you need to do to create that source in the first place. So it might be better to explain what it is that you want to do with ForwardingJavaFileManager, without reference to compilation, since that is, best as I can see, your real question.
  • 2. Re: Dynamic compilation in memory
    Gen.Java Newbie
    Currently Being Moderated
    CharSequence src = "public class DynaClass {public String toString (){return"hello";}}";
    Using javax.tools API, this compiles just fine. However,the following does not, complaining that it cannot find the class "another". The bytecode for the class "another" is in memory (not the file system). I just need to make it available to the main class "DynaClass".
    CharSequence src = "public class DynaClass {public String toString (){return new another().get();}}";
    The following is my code:

    import java.util.*;
    import javax.tools.*;
    import java.io.*;
    
    public class DynaCompTest
    {
    
    public static void main(String[] args) throws Exception
    {
    JavaCompiler         compiler;
    ClassFileManager     fileManager;
    List<JavaFileObject> jfiles;
    CharSequence         src;
    String               fullName;
    
    fullName = "DynaClass";
    src      = "public class DynaClass {public String toString (){return"hello";}}";
    
    compiler    = ToolProvider.getSystemJavaCompiler ();
    fileManager = new ClassFileManager ( compiler.getStandardFileManager(null, null, null) );
    
    jfiles      = new ArrayList<JavaFileObject>();
    jfiles.add  ( new CharSequenceJavaFileObject(fullName,src) );
    
    compiler.getTask ( null, fileManager, null, null, null, jfiles).call ();
    }
    
    }
    
    ///////////////////////////////////
    
    import java.net.*;
    import javax.tools.*;
    
    public class CharSequenceJavaFileObject extends SimpleJavaFileObject
    {
    
    private CharSequence content;
    
    public       CharSequenceJavaFileObject (
    String       className,
    CharSequence content                    )
    {
    super      ( URI.create("string:///" + className.replace('.', '/')+ Kind.SOURCE.extension), Kind.SOURCE);
    this.content = content;
    }
    
    // ....................
    
    @Override
    public CharSequence getCharContent       (
    boolean             ignoreEncodingErrors )
    {
    return content;
    }
    
    }
    
    ///////////////////////////////////
    
    import java.security.*;
    import java.io.*;
    import java.net.*;
    import java.util.*;
    import javax.tools.*;
    import javax.tools.JavaFileObject.*;
    
    public class ClassFileManager extends ForwardingJavaFileManager<JavaFileManager>
    {
    
    private final Map<String,JavaClassObject> fileObjects;
    
    // ....................
    
    public                  ClassFileManager (
    StandardJavaFileManager standardManager  )
    {
    super       ( standardManager );
    fileObjects = new HashMap<String,JavaClassObject>();
    }
    
    // ....................
    
    @Override
    public ClassLoader getClassLoader (
    Location           location       )
    {
    return new ClassLoader() {
               @Override
               protected Class<?> findClass(String name) throws ClassNotFoundException {
                    JavaClassObject jco;
                    jco      = fileObjects.get(name);
                    byte[] b = jco.getByteCode();
                    return super.defineClass(name, b, 0, b.length);
               }
           };
    }
    
    // ....................
    
    @Override
    public JavaFileObject getJavaFileForOutput (
    Location              location,
    String                className,
    Kind                  kind,
    FileObject            sibling              ) throws IOException
    {
    JavaClassObject jco;
    
    jco             = new JavaClassObject(className, kind);
    fileObjects.put ( className,jco );
    
    return jco;
    }
    
    }
    
    ///////////////////////////////////
    
    import java.net.*;
    import java.io.*;
    import javax.tools.*;
    
    public class JavaClassObject extends SimpleJavaFileObject
    {
    
    protected final ByteArrayOutputStream bos = new ByteArrayOutputStream();
    
    public JavaClassObject (
    String className,
    Kind   kind            )
    {
    super ( URI.create("string:///" + className.replace('.', '/')+ kind.extension), kind );
    }
    
    // ....................
    
    public byte[] getByteCode ()
    {
    return bos.toByteArray();
    }
    
    // ....................
    
    @Override
    public OutputStream openOutputStream () throws IOException
    {
    return bos;
    }
    
    }
  • 3. Re: Dynamic compilation in memory
    jschellSomeoneStoleMyAlias Expert
    Currently Being Moderated
    I just need to make it available to the main class "DynaClass".
    And thus you have a class path problem. No different than if you were doing it on the command line.

    At best the solution is going to be complex because you need to intercept the class path look up of the compiler. You might look to the API to see if you can pass in your own custom classloader which would need to resolve normal stuff and also find your other class.

    At worst you would need to create a class/jar and add it to the class path directory of the dynamic compiler. I know this exists somewhere in the API (but I am not going to dig it up.)

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points