0

I'm trying to run a java class without saving to a file and i use javax.tools.JavaCompiler for this.

here i found a answer on so question about java memory compile.

but when i run this code i got two different outputs .java version in both ide and cmd is 1.8.0_31 this is in netbeans IDE version-8.0.2

enter image description here

this is the line 50

Class.forName("HelloWorld").getDeclaredMethod("main", new Class[]{String[].class})

this is cmd output

enter image description here

line 33 is

CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits);

i want to know the reason for getting two different output .

this is the code i used .this is almost same as above answer's code .but i removed multiple catch blocks in to one.

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.Arrays;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject.Kind;

public class CompileSourceInMemory {

    public static void main(String args[]) throws IOException {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

        StringWriter writer = new StringWriter();
        PrintWriter out = new PrintWriter(writer);
        out.println("public class HelloWorld {");
        out.println("  public static void main(String args[]) {");
        out.println("    System.out.println(\"This is in another java file\");");
        out.println("  }");
        out.println("}");
        out.close();
        JavaFileObject file = new JavaSourceFromString("HelloWorld", writer.toString());

        Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file);
        CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits);

        boolean success = task.call();
        for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
            System.out.println(diagnostic.getCode());
            System.out.println(diagnostic.getKind());
            System.out.println(diagnostic.getPosition());
            System.out.println(diagnostic.getStartPosition());
            System.out.println(diagnostic.getEndPosition());
            System.out.println(diagnostic.getSource());
            System.out.println(diagnostic.getMessage(null));

        }
        System.out.println("Success: " + success);

        if (success) {
            try {
                Class.forName("HelloWorld").getDeclaredMethod("main", new Class[]{String[].class})
                        .invoke(null, new Object[]{null});
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

class JavaSourceFromString extends SimpleJavaFileObject {

    final String code;

    JavaSourceFromString(String name, String code) {
        super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
        this.code = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return code;
    }
}

thanks.

Community
  • 1
  • 1
Madhawa Priyashantha
  • 9,208
  • 7
  • 28
  • 58

2 Answers2

1

I couldn't reproduce your first error:

$ ~/jdk1.8.0_25/bin/java CompileSourceInMemory
Success: true
This is in another java file

Try finding out which java was called from terminal or command line in your case. The second problem is related to where NetBeans/compiler outputs compiled class. It is root of project, so class path needs adjustment:

if (success) {
  try {
    URL[] classpathExt = {new File("/home/[your name]/NetBeansProjects/JavaApplication2/").toURI().toURL()};
    URLClassLoader loader = new URLClassLoader(classpathExt, null);
    Class.forName("HelloWorld", true, loader).getDeclaredMethod("main", new Class[]{String[].class})
        .invoke(null, new Object[]{null});
  } catch (Exception e) {
    e.printStackTrace();
  }
}

Interesting that ~/NetBeansProjects/JavaApplication2/ won't work, full path must be specified. For Windows you will use C:\\User\\and so on\\

Filip Bulovic
  • 1,530
  • 12
  • 10
  • thanks for your responce .i created a folder in my desktop and created that class inside it and run using cmd .i didn't run netbeans class from cmd – Madhawa Priyashantha Jul 09 '15 at 14:04
  • You are welcome. The first part of the answer is original code as it is, no NetBeans involved. I remember that at some companies Desktop folder is actually remote share, helps them do backup. Are you doing that at work? – Filip Bulovic Jul 09 '15 at 14:12
  • no remort share that is my personal one.so does this code work for you in cmd and netbeans both ?? – Madhawa Priyashantha Jul 09 '15 at 14:18
  • Code as it is compiles and works from terminal/command line, for NetBeans adjustment in path is required. Do not know then why that doesn't work from command line on your OS. – Filip Bulovic Jul 09 '15 at 14:22
1

The cmd problem at line 33 is probably because tools.jar is not present in your command line classpath (and thus compiler is null). The compiler returned by ToolProvider.getSystemJavaCompiler() comes from this jar, so if tools.jar isn't on your classpath it will return null. This is then being dereferenced at line 33 to cause the NPE.

Perhaps the compiler that you run from the command line was installed with only the JRE present, and not the JDK? I imagine that NetBeans IDE is automatically including JDK libraries for you.

However its classloader seems not to be capable of loading your java source, as Filip Bulovic mentioned: you can create a new URLClassLoader adding to it the directory where the compiler returned by ToolProvider.getSystemJavaCompiler() put your compiled code. Or you can use the class loader provided by ToolProvider.getSystemToolClassLoader() to load the HelloWorld class.

Breandán Dalton
  • 1,481
  • 14
  • 20
  • thanks for the reply "Perhaps the system compiler was installed with only the JRE present, and not the JDK?" i don't get that part can you clarify – Madhawa Priyashantha Sep 24 '15 at 13:36
  • The compiler that is returned by 'ToolProvider.getSystemJavaCompiler()' is from tools.jar. This only gets installed if you install the JDK. If the compiler you run from the command line was installed as part of a JRE install, then you won't have a tools.jar, and the 'JavaCompiler' returned by 'ToolProvider.getSystemJavaCompiler()' will be null. I think that's what's happening when you run the compiler from the command line. You're picking up a JRE-only compiler. – Breandán Dalton Sep 29 '15 at 11:51
  • I rewrote the answer slightly to remove the reference to system compiler in the line you mentioned, to make it clearer exactly which compiler I'm referring to. – Breandán Dalton Sep 29 '15 at 11:54