p_gaard Juniormester
25. februar 2008 - 13:35 Der er 15 kommentarer og
1 løsning

kompilering og kørsel af klasse (i memory)

Hej,

Jeg har et godt stykke tid kørt med en løsning hvor mit program skriver en java-klasse ned i en fil, kompilerer denne hvorefter den indlæser/kører vha. classloader. Det må kunne gøres smartere.

Jeg har fundet nedenstående kode som overordnet set skulle kompilere streng i memory og køre en metode, lige hvad jeg skal bruge. Jeg kan ikke få den til at virke. Problemet er en nullpointerexception på linje 90.
mht. linjen "getResult()" er der også noget galt. Evt skal denne fjernes eller der mangler noget.


Er der nogen som kender til problemet?





----------------------------------

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.tools.*;

import javax.tools.JavaFileObject.Kind;
import javax.tools.JavaCompiler.CompilationTask;

public class OnTheFlyInRAM {

static JavaFileObject generateJavaSourceCode() {

final String source =
"package just.generated;\n" +
"public class Hello {\n" +
"public static void main(String... args) {\n" +
"System.out.println(new Object() {\n" +
"public String toString() {\n" +
"return \"just hello!\";\n" +
"}\n" +
"});\n" +
"}\n" +
"}";

return new SimpleJavaFileObject(toURI("Hello.java"), JavaFileObject.Kind.SOURCE) {

@Override
public CharSequence getCharContent(boolean
ignoreEncodingErrors)
throws IOException, IllegalStateException,
UnsupportedOperationException {
return source;
}

};
}


static class RAMJavaFileObject extends SimpleJavaFileObject {

RAMJavaFileObject(String name, Kind kind) {
super(toURI(name), kind);
}

ByteArrayOutputStream baos;

@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors)
throws IOException, IllegalStateException,
UnsupportedOperationException {
throw new UnsupportedOperationException();
}

@Override
public InputStream openInputStream() throws IOException,
IllegalStateException, UnsupportedOperationException {
return new ByteArrayInputStream(baos.toByteArray());
}

@Override
public OutputStream openOutputStream() throws IOException,
IllegalStateException, UnsupportedOperationException {
return baos = new ByteArrayOutputStream();
}

}

getResult()
public static void main(String[] args) throws Exception {

JavaCompiler compiler =
ToolProvider.getSystemJavaCompiler();

final Map<String, JavaFileObject> output =
new HashMap<String, JavaFileObject>();

DiagnosticCollector<JavaFileObject> diagnostics =
new DiagnosticCollector<JavaFileObject>();

JavaFileManager jfm = new
ForwardingJavaFileManager<StandardJavaFileManager> (
compiler.getStandardFileManager(diagnostics,null,null)) {

@Override
public JavaFileObject getJavaFileForOutput(Location location,
String name,
Kind kind,
FileObject sibling) throws IOException {
JavaFileObject jfo = new RAMJavaFileObject(name, kind);
output.put(name, jfo);
return jfo;
}

};

CompilationTask task = compiler.getTask(
null, jfm, diagnostics, null, null,
Arrays.asList(generateJavaSourceCode()));

if (! task.call()) {
for(Diagnostic dm : diagnostics.getDiagnostics())
System.err.println(dm);
throw new RuntimeException("Compilation failed");
}

System.out.println("generated classes: "+ output.keySet());

ClassLoader cl = new ClassLoader() {

@Override
protected Class<?> findClass(String name) throws
ClassNotFoundException {
JavaFileObject jfo = output.get(name);
if (jfo != null) {
byte[] bytes = ((RAMJavaFileObject)
jfo).baos.toByteArray();
return defineClass(name, bytes, 0, bytes.length);
}
return super.findClass(name);
}

};

Class<?> c = Class.forName("just.generated.Hello", false, cl);
c.getMethod("main", String[].class)
.invoke(null, new Object[] {args});

}

private static URI toURI(String name) {
try {
return new URI(name);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}

}
arne_v Ekspert
25. februar 2008 - 15:31 #1
Det er en ny feature i Java 1.6.

Jeg har ogsaa nogle eksempler i http://www.eksperten.dk/artikler/941 paa
fil->fil og mem->fil.

Men det er en lidt tricky feature.

Vil du have mem->fil eller mem->mem ?
p_gaard Juniormester
25. februar 2008 - 17:42 #2
Hej Arne,

Da jeg primært står med en tekststreng bestående af f.eks:

(1) public class a {bla.bla.bla..new class b() ...}

og ikke er interesseret i nogle mellemresultater i filer eller nogle class-fil. i den anden ende må det vel være mem>mem.

Tekststrengen (klassen) skal kompileres i mem og dens metode afvikles i mem.

Jeg er yderst interesseret i hvis du har noget kode som kan løse problemet.

(mit næste problem bliver vel så at få klassen a til at se klassen b i kompilerings- og afviklingsøjeblikket)
arne_v Ekspert
28. februar 2008 - 05:36 #3
Det her eksempel virker hos mig:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;

public class JC16 {
    public static void main(String[] args) throws Exception {
        testFileFile();
        testMemoryFile();
        testFileMemory();
        testMemoryMemory();
    }
    public static void testFileFile() throws Exception {
        PrintWriter pw = new PrintWriter(new FileWriter("Temp2.java"));
        pw.println("public class Temp2 {");
        pw.println("    public void test() {");
        pw.println("        System.out.println(\"Temp2 OK\");");
        pw.println("    }");
        pw.println("}");
        pw.close();
        compileFileFile("Temp2.java", System.err);
        Class<?> c = Class.forName("Temp2");
        Object o = c.newInstance();
        c.getMethod("test", new Class[] { }).invoke(o, new Object[] { });
    }
    public static void compileFileFile(String fnm, PrintStream err) {
        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diacol = new DiagnosticCollector<JavaFileObject>();
        StandardJavaFileManager sjfm = javac.getStandardFileManager(diacol, null, null);
        CompilationTask compile = javac.getTask(null, sjfm, diacol, Arrays.asList(new String[] { }), null,
                                                sjfm.getJavaFileObjects(new String[] { fnm }));
        boolean status = compile.call();
        if(err != null) {
            err.println("Compile status: " + status);
            for(Diagnostic<? extends JavaFileObject> dia : diacol.getDiagnostics()) {
                err.println(dia);
            }
        }
    }
    public static void testMemoryFile() throws Exception {
        String src = "public class Temp3 { public void test() { System.out.println(\"Temp3 OK\"); } }";
        compileMemoryFile(src, "Temp3", System.err);
        Class<?> c = Class.forName("Temp3");
        Object o = c.newInstance();
        c.getMethod("test", new Class[] { }).invoke(o, new Object[] { });
    }
    public static void compileMemoryFile(String src, String name, PrintStream err) {
        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diacol = new DiagnosticCollector<JavaFileObject>();
        StandardJavaFileManager sjfm = javac.getStandardFileManager(diacol, null, null);
        CompilationTask compile = javac.getTask(null, sjfm, diacol, Arrays.asList(new String[] { }), null,
                                                Arrays.asList(new JavaFileObject[] { new MemorySource(name, src) }));
        boolean status = compile.call();
        if(err != null) {
            err.println("Compile status: " + status);
            for(Diagnostic<? extends JavaFileObject> dia : diacol.getDiagnostics()) {
                err.println(dia);
            }
        }
    }
    public static void testFileMemory() throws Exception {
        PrintWriter pw = new PrintWriter(new FileWriter("Temp4.java"));
        pw.println("public class Temp4 {");
        pw.println("    public void test() {");
        pw.println("        System.out.println(\"Temp4 OK\");");
        pw.println("    }");
        pw.println("}");
        pw.close();
        SpecialClassLoader xcl = new SpecialClassLoader();
        compileFileMemory("Temp4.java", xcl, System.err);
        Class<?> c = Class.forName("Temp4", true, xcl);
        Object o = c.newInstance();
        c.getMethod("test", new Class[] { }).invoke(o, new Object[] { });
    }
    public static void compileFileMemory(String fnm, SpecialClassLoader xcl, PrintStream err) {
        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diacol = new DiagnosticCollector<JavaFileObject>();
        StandardJavaFileManager sjfm = javac.getStandardFileManager(diacol, null, null);
        SpecialJavaFileManager xfm = new SpecialJavaFileManager(sjfm, xcl);
        CompilationTask compile = javac.getTask(null, xfm, diacol, Arrays.asList(new String[] { }), null,
                                                sjfm.getJavaFileObjects(new String[] { fnm }));
        boolean status = compile.call();
        if(err != null) {
            err.println("Compile status: " + status);
            for(Diagnostic<? extends JavaFileObject> dia : diacol.getDiagnostics()) {
                err.println(dia);
            }
        }
    }
    public static void testMemoryMemory() throws Exception {
        String src = "public class Temp5 { public void test() { System.out.println(\"Temp5 OK\"); } }";
        SpecialClassLoader xcl = new SpecialClassLoader();
        compileMemoryMemory(src, "Temp5", xcl, System.err);
        Class<?> c = Class.forName("Temp5", true, xcl);
        Object o = c.newInstance();
        c.getMethod("test", new Class[] { }).invoke(o, new Object[] { });
    }
    public static void compileMemoryMemory(String src, String name, SpecialClassLoader xcl, PrintStream err) {
        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diacol = new DiagnosticCollector<JavaFileObject>();
        StandardJavaFileManager sjfm = javac.getStandardFileManager(diacol, null, null);
        SpecialJavaFileManager xfm = new SpecialJavaFileManager(sjfm, xcl);
        CompilationTask compile = javac.getTask(null, xfm, diacol, Arrays.asList(new String[] { }), null,
                                                Arrays.asList(new JavaFileObject[] { new MemorySource(name, src) }));
        boolean status = compile.call();
        if(err != null) {
            err.println("Compile status: " + status);
            for(Diagnostic<? extends JavaFileObject> dia : diacol.getDiagnostics()) {
                err.println(dia);
            }
        }
    }
}

class MemorySource extends SimpleJavaFileObject {
    private String src;
    public MemorySource(String name, String src) {
        super(URI.create("string:///" + name + ".java"), Kind.SOURCE);
        this.src = src;
    }
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return src;
    }
    public OutputStream openOutputStream() {
        throw new IllegalStateException();
    }
    public InputStream openInputStream() {
        return new ByteArrayInputStream(src.getBytes());
    }
}

class MemoryByteCode extends SimpleJavaFileObject {
    private ByteArrayOutputStream baos;
    public MemoryByteCode(String name) {
        super(URI.create("byte:///" + name + ".class"), Kind.CLASS);
    }
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        throw new IllegalStateException();
    }
    public OutputStream openOutputStream() {
        baos = new ByteArrayOutputStream();
        return baos;
    }
    public InputStream openInputStream() {
        throw new IllegalStateException();
    }
    public byte[] getBytes() {
        return baos.toByteArray();
    }
}

class SpecialJavaFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
    private SpecialClassLoader xcl;
    public SpecialJavaFileManager(StandardJavaFileManager sjfm, SpecialClassLoader xcl) {
        super(sjfm);
        this.xcl = xcl;
    }
    public JavaFileObject getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
        MemoryByteCode mbc = new MemoryByteCode(name);
        xcl.addClass(name, mbc);
        return mbc;
    }
}

class SpecialClassLoader extends ClassLoader {
    private Map<String,MemoryByteCode> m;
    public SpecialClassLoader() {
        m = new HashMap<String, MemoryByteCode>();
    }
    protected Class<?> findClass(String name) {
        MemoryByteCode mbc = m.get(name);
        return defineClass(name, mbc.getBytes(), 0, mbc.getBytes().length);
    }
    public void addClass(String name, MemoryByteCode mbc) {
        m.put(name, mbc);
    }
}
arne_v Ekspert
28. februar 2008 - 05:36 #4
Du skal kigge på testMemoryMemory !
p_gaard Juniormester
03. marts 2008 - 14:50 #5
testMemoryMemory kører fint hos mig. Jeg har dog ikke fået den kompilerede klasse i memory til at åbne objekter af klasser beliggende på disk. Det ville være fint hvis man kunne pege på et sted hvor der ligger en række klasser.
arne_v Ekspert
03. marts 2008 - 15:47 #6
Proev med:

Arrays.asList(new String[] { "-classpath", "/dir/foobar.jar" })

som 4. argument til getTask.
p_gaard Juniormester
04. marts 2008 - 20:28 #7
Tak for det, jeg vil pr&#248;ve...
arne_v Ekspert
31. marts 2008 - 04:45 #8
OK ?
p_gaard Juniormester
16. april 2008 - 11:28 #9
Jeg vil gerne lige lade denne tråd stå åben...
p_gaard Juniormester
13. august 2008 - 00:47 #10
Tilbage til denne!. Jeg har i aften fået undersøgt -classpath som 4. qargument til getTask:

Arrays.asList(new String[] { "-classpath", "C:/arb/Java2/pkkcms_231/Hyperlink.class"})

får flg. fejl 

Compile status: false
null
string:///Temp5.java:16: cannot find symbol
symbol  : class Hyperlink
location: class Temp5
string:///Temp5.java:16: cannot find symbol
symbol  : class Hyperlink
location: class Temp5

Hvem kan gennemskue dette?
arne_v Ekspert
13. august 2008 - 02:48 #11
Den er også forkert.

Arrays.asList(new String[] { "-classpath", "C:/arb/Java2/pkkcms_231"})

eller

Arrays.asList(new String[] { "-classpath", "C:/arb/Java2"})

afhængig af om pkkcms_231 er en package.
p_gaard Juniormester
16. oktober 2008 - 23:45 #12
Det kører fint nu, men kun under eclipse. Når jeg kører det under tomcat i mappen pkkcms_lib .../web-inf/pkkcms_lib så får jeg fejlen:

java.lang.NoClassDefFoundError: javax/tools/DiagnosticListener

Denne fejl har jeg forsøgt at tackle ved at på forskellige måder referere til javax og tools, men uden held.

Ved du hvad jeg kan gøre?
arne_v Ekspert
17. oktober 2008 - 00:15 #13
Kører Tomcat med Java 1.6 som Java version ?
p_gaard Juniormester
17. oktober 2008 - 12:39 #14
Jeg har nu sat tomcat til java version jdk1.6.0_010 og fejlen vedr. DiagnosticListener er væk.

Til gengæld får jeg nu:

NullPointerException
      at SpecialClassLoader.findClass(JC16.java:195)
      at java.lang.classLoader.loadClass(ClassLoader.java:307)
      ...
      ...
p_gaard Juniormester
17. oktober 2008 - 12:44 #15
Jeg har nu sat tomcat til java version jdk1.6.0_010 og fejlen vedr. DiagnosticListener er væk. Alt fungerer ok når jeg kører fra eclipse.



Til gengæld får jeg nu output i tomcat (det ser ud til at kompileringen er udført med success):

compile-status:true
NullPointerException
      at SpecialClassLoader.findClass(JC16.java:195)
      at java.lang.classLoader.loadClass(ClassLoader.java:307)
      ...
      ...
p_gaard Juniormester
21. oktober 2008 - 10:28 #16
Forresten er spørgsmålet besvaret. Det går fint med at oprette klasser i memory, kompilere og kalde en metode. Sidstnævnte må være et apache/tomcat-java problem.
Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links

Opret Preview

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester





Premium
Her er de danske ERP-huse der vækster mest: Visma E-conomic vinder tæt forfulgt af fire Microsoft-partnere
Årets it-komet 2019: Computerworlds it-komet 2019 er på trapperne, og vi indleder jagten på Danmarks dygtigste it-virksomhed i kontinuerlig vækst med et kig på en række af underkategorierne. Her tager vi et kig på landets mest vækstende ERP-huse.
Computerworld
Streaming: Sådan ser fremtiden ud for DRTV
Det nye DRTV bliver efter nytår det eneste sted, hvor man kan se ungdomskanalerne DR Ultra og DR3. De to kanaler lukker nemlig som flowkanaler 2. januar 2020. Kulturkanalen DR K lukkes derudover helt.
CIO
I 2002 besluttede Rockwools globale CIO, Jan Amtoft, at han ville være en rigtig god chef. Her er hvad han lærte på vejen.
I 2002 besluttede Rockwools globale CIO, Jan Amtoft, at han ville være en rigtig god chef. Ikke bare god. Men rigtigt god. Her er hans historie om hvad han lærte på vejen.
Job & Karriere
Nyt job i et konsulenthus? Her er 10 fede stillinger, der er ledige netop nu
Drømmer du om en karriere konsulentbranchen? Så har vi fundet 10 stillinger, der netop nu er ledige i virksomheder som Netcompany, Commentor og KMD.
White paper
Vil du styrke økonomi, overblik og ydeevne gennem konsolidering på virtualiseret platform?
Med en platform baseret på Hyperconverged Infrastructure gør din virksomhed datacenteret langt mere fleksibelt og kan vælge præcis de servere, der passer bedst. Samtidig får I mulighed for at etablere fuld deduplikering på tværs af datacentre og geografi – og kan samtidig skære en betydelig del af licensomkostningerne til en traditionel virtualiseringsplatform. Netop dét tager vi fat i, i dette whitepaper.