Reputation: 11
I writed a code that generates two class which I write them to buffer and compile them with JavaCompiler. My classes are like this in .java files;
public class A{
public A() { }
public String toString(){ return "A";}
}
and
public class B extends ArrayList<A> {
public B() {
super();
}
public void addItem(A a)
{
this.add(a);
}
public void print() {
this.print();
}
}
something like this.
However, the name of the classes are randomly generated and when I create the file it gives an error like this;
symbol: class A
location: class B
./src/A.java:4: error: cannot find symbol
(4th line is the "...extends ArrayList..." and there is a ^ symbol under A)
My code generator compiles like this;
First I fill the buffer with my template for A type classes then compile like this:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
compiler.run(null, null, null, f.getPath());
after that I create another buffer and fill it with my template for B type classes then compile like this;
System.out.println(f.getParentFile().getPath());
compiler.run(null, null, null, f.getPath());
f is;
f = new File(("./src/" + name + ".java"));
How can I solve this problem?
Upvotes: 1
Views: 394
Reputation: 493
this should be help
public void CompileClasses(ArrayList<String> classesNames){
//File helloWorldJava = new File("classes\\"+className+".java");
try {
List<String> optionList = new ArrayList<String>();
optionList.add("-classpath");
optionList.add(System.getProperty("java.class.path") + ";dist/InlineCompiler.jar");
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
Iterable<? extends JavaFileObject> compilationUnit=null;
ArrayList<File> files = new ArrayList<>();
for (String className:classesNames) {
files.add(new File(className+".java"));
}
compilationUnit = fileManager.getJavaFileObjectsFromFiles(files);
JavaCompiler.CompilationTask task = compiler.getTask(
null,
fileManager,
diagnostics,
optionList,
null,
compilationUnit);
if (task.call()) {
URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("./").toURI().toURL()});
} else {
for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
System.out.format("Error on line %d in %s%n %s",
diagnostic.getLineNumber(),
diagnostic.getSource().toUri(),
diagnostic.toString());
}
}
fileManager.close();
} catch (IOException exp) {
exp.printStackTrace();
}
}
Upvotes: 0
Reputation: 22973
As mentioned in the comment the compiler need to know about class A
when class B
is compiled. In the example below we add the output directory for the compiled classes /tmp/bin/
to the classpath for the compiler in optionList
.
You could either prevent to create the source files on the filesystem, if you don't need them as such
public class CompileDependent {
public static void main(String[] args) {
String sourceClassA = "public class A {"
+ " public String toString() {"
+ " return \"A\";"
+ " }"
+ "}";
String sourceClassB = "import java.util.ArrayList;"
+ "class B extends ArrayList<A> {"
+ " public void addItem(A a) {"
+ " this.add(a);"
+ " }"
+ "}";
List<JavaFileObject> compilationUnits = new ArrayList<>();
compilationUnits.add(new StringJavaFileObject("A.java", sourceClassA));
compilationUnits.add(new StringJavaFileObject("B.java", sourceClassB));
List<String> optionList = new ArrayList<>();
// classpath from current JVM + binary output directory
optionList.add("-classpath");
optionList.add(System.getProperty("java.class.path") + ":/tmp/bin");
// class output directory
optionList.add("-d");
optionList.add("/tmp/bin");
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = compiler.getStandardFileManager(
null,
Locale.UK,
Charset.forName("UTF-8")
);
boolean compiled = compiler.getTask(
null,
fileManager,
null,
optionList,
null,
compilationUnits).call();
System.out.println("compiled = " + compiled);
}
private static class StringJavaFileObject extends SimpleJavaFileObject {
final String code;
StringJavaFileObject(String name, String code) {
super(URI.create("string:///" + name), Kind.SOURCE);
this.code = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return code;
}
}
}
or you create the Java source files on the file system. Similar code as above with a small change for the compilationUnits
. It's assumed the files have been already stored on the given location.
List<File> sourceFiles = new ArrayList<>();
sourceFiles.add(new File("/tmp/A.java"));
sourceFiles.add(new File("/tmp/B.java"));
Upvotes: 1