DiagnosticCollector
In the previous program, we saw that we have a customized class called MyDiagnosticListener. Its sole purpose it to collect and print all the diagnostic messages to the console. This class can be completely eliminated since Mustang already has a class called DiagnosticCollection<SourceObject> that does the same thing. It has a method called getDiagnostics() which returns a list , through which we can iterate and can output the diagnostic messages to the console.
The following code achieves the same using DiagosticCollector class.
AdvancedCompilationTest2.java:
package test;
import java.io.*;
import java.util.*;
import javax.tools.*;
import javax.tools.JavaCompiler.*;
public class AdvancedCompilationTest2 {
public static void main(String[] args) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // Line 1.
DiagnosticCollector<JavaFileObject> diagnosticsCollector =
new DiagnosticCollector<JavaFileObject>();
StandardJavaFileManager fileManager =
compiler.getStandardFileManager(diagnosticsCollector, null, null); // Line 3.
String fileToCompile = "test" + File.separator + "ManyErrors.java"; // Line 4
Iterable<? extends JavaFileObject> fileObjects = fileManager.getJavaFileObjectsFromStrings(Arrays.asList(fileToCompile)); // Line 5
CompilationTask task = compiler.getTask(null, fileManager, diagnosticsCollector, null, null, fileObjects); // Line 6
Boolean result = task.call(); // Line 7
List<Diagnostic<? extends JavaFileObject>> diagnostics = diagnosticsCollector.getDiagnostics();
for(Diagnostic<? extends JavaFileObject> d : diagnostics){
// Print all the information here.
}
if(result == true){
System.out.println("Compilation has succeeded");
}else{
System.out.println("Compilation fails.");
}
}
}
Compilation of Java Source from a String object
Having discussed about the various ways of compiling java file sources, it’s now time to look at how to compile a java source that is encapsulated in a string object. As previously mentioned, it is not mandatory that the contents of a java source must reside in hard-disk, it can even reside in memory. By saying that compiling a java source from a string object, we are implicitly saying that the java source is residing in memory, more specifically, the contents are residing in RAM.
For this to happen, we have to encapsulate a class the represents the java source from a string. We can extend this class from the SimpleJavaFileObject (a convenient class that overrides all the methods in the JavaFileObject with some default implementation). The only method to override is the getCharContent() that will be called internally by the Java compiler to get the java source contents.
JavaObjectFromString.java:
package test;
import java.net.URI;
class JavaObjectFromString extends SimpleJavaFileObject{
private String contents = null;
public JavaObjectFromString(String className, String contents) throws Exception{
super(new URI(className), Kind.SOURCE);
this.contents = contents;
}
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return contents;
}
}
Since the SimpleJavaFileObject has a protected two argument constructor that accepts an URI (the URI representation of the file object) and a Kind object (a special type that tells what kind is this object, the Kind may be a Kind.SOURCE, Kind.CLASS, Kind.HTML, Kind.OTHER, in our case, it is Kind.SOURCE, since we are inferring a Java source object), we have defined a two argument constructor in JavaObjectFromString class and delegates the control back the base class. The getCharContent() method has to be overridden (since this is the method that will be called by the JavaCompiler to get the actual java source contents) to return the string (remember, String implements CharSequence) that represents the entire java source (which was previously saved in the constructor).
The code that uses this JavaObjectFromString object looks like this.
AdvancedCompilationTest3.java:
package test;
import java.io.*;
import java.util.*;
import javax.tools.*;
import javax.tools.JavaCompiler.*;
public class AdvancedCompilationTest3 {
public static void main(String[] args) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnosticsCollector =
new DiagnosticCollector<JavaFileObject>();
StandardJavaFileManager fileManager =
compiler.getStandardFileManager(diagnosticsCollector, null, null);
JavaFileObject javaObjectFromString = getJavaFileContentsAsString();
Iterable<? extends JavaFileObject> fileObjects = Arrays.asList(javaObjectFromString);
CompilationTask task = compiler.getTask(null, fileManager, diagnosticsCollector, null, null, fileObjects);
Boolean result = task.call();
List<Diagnostic<? extends JavaFileObject>> diagnostics = diagnosticsCollector.getDiagnostics();
for(Diagnostic<? extends JavaFileObject> d : diagnostics){
// Print all the information here.
}
if(result == true){
System.out.println("Compilation has succeeded");
}else{
System.out.println("Compilation fails.");
}
}
static SimpleJavaFileObject getJavaFileContentsAsString(){
StringBuilder javaFileContents = new StringBuilder("" +
"class TestClass{" +
" public void testMethod(){" +
" System.out.println(" + "\"test\"" + ");" +
"}" +
"}");
JavaObjectFromString javaFileObject = null;
try{
javaFileObject = new JavaObjectFromString("TestClass", javaFileContents.toString());
}catch(Exception exception){
exception.printStackTrace();
}
return javaFileObject;
}
}
Conclusion
Before the release of Mustang, the compiler API related interfaces and classes were maintained in some non-standard packages (i.e inside com.sun.javac.tools.javac). But with Java 6.0, the designers of java have given great heights to compilation API by generalizing them in the javax.tools package. As already mentioned, this API is not for everyone. Web and Application servers can depend on this API exhaustively to provide compilation activities of the dynamically created Java source files. Although it is heard that more and more bugs related to Compiler API are there, they are expected to be fixed soon in the future builds.
|