Java SE 6 new feature: Compiler API

Source: Internet
Author: User
Tags iterable

New API features

JDK 6 provides an API for calling the compiler at runtime. We will assume that this API is applied to JSP technology later. In traditional JSP technology, the following six steps are usually required for servers to process JSP:

  1. Analyze JSP code;
  2. Generate Java code;
  3. Write Java code into memory;
  4. Start another process and run the compiler to compile Java code;
  5. Write class files into the memory;
  6. The server reads and runs class files;

However, if you use runtime compilation, You can simplify steps 4 and 5 at the same time, saving the overhead of new processes and writing Memory output overhead, and improving system efficiency. In fact, Sun also provides a programming interface for calling the compiler in JDK 5. However, the difference is that the programming interface of the old version is not part of the standard API, but provided as sun's proprietary implementation. The new version brings the advantages of standardization.

The second new feature of the new API is the ability to compile abstract files, theoretically any form of Object-as long as the object implements a specific interface. With this feature, step 3 in the preceding example can be omitted. The compilation of the entire JSP is completed in one process, and additional input and output operations are eliminated.

The third new feature is to collect diagnostic information during compilation. As a supplement to the first two new features, it allows developers to easily output necessary compilation errors or warning information, thus saving a lot of redirection troubles.

Compile java files during runtime

In JDK 6, the class library passesjavax.toolsThe package provides the API for calling the compiler when the program is running. From the Tool Name of this package, we can see that the functions provided by this development kit are not limited to compilers. Tools also include javah, jar, and pack200. They are all command line tools provided by JDK. This development kit hopes to call these tools at runtime by implementing a unified interface. In JDK 6, the compiler has been given special attention. For the compiler, JDK has designed two interfaces:JavaCompilerAndJavaCompiler.CompilationTask.

The following example shows how to call the compiler at runtime.

  • Specify the name of the compiled file (this file must be available in classpath ):String fullQuanlifiedFileName = "compile" + java.io.File.separator +"Target.java";
  • Obtain the compiler object:JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

By callingToolProviderOfgetSystemJavaCompilerMethod: JDK provides the ability to map the compiler of the current platform to an object in the memory. In this way, you can manipulate the compiler at runtime.JavaCompilerIs an interface that inheritsjavax.tools.ToolInterface. Therefore, a third-party compiler can be called through a unified interface as long as it complies with the specifications. At the same time, the Tools Development Kit wants to provide a unified runtime call interface for all tools. Believe in the future,ToolProviderClass will provide more toolsgetSystemXXXToolMethod. The tools development kit provides a framework for coexistence of different tools and implementations.

  • Compile the file:int result = compiler.run(null, null, null, fileToCompile);

After obtaining the compiler object, you can callTool.runMethod to compile the source file.RunThe first three parameters of the method can be used to redirect standard input, standard output, and standard error output, respectively,nullThe default value is used. Listing 1 provides a complete example:

Listing 1. compile files during program running

01 package compile;
02 import java. util. date;
03 public class target {
04 public void dosomething (){
05 date = new date (10, 3, 3 );
// This constructor is marked as deprecated.
// Output error information.
06 system. Out. println ("doing ...");
07}
08}

09 package compile;
10 Import javax. Tools .*;
11 import java. Io. fileoutputstream;
12 public class compiler {
13 public static void main (string [] ARGs) throws exception {
14 string fullquanlifiedfilename = "compile" + Java. Io. file. Separator +
"Target. Java ";
15 javacompiler compiler = toolprovider. getsystemjavacompiler ();

16 fileoutputstream err = new fileoutputstream ("err.txt ");

17 int compilationresult = compiler. Run (null, null, err, fullquanlifiedfilename );

18 if (compilationresult = 0 ){
19 system. Out. println ("done ");
20} else {
21 system. Out. println ("fail ");
22}
23}
24}

Run <jdk60_installation_dir>/bin/javac compiler. Java first, and then run <jdk60_installation_dir>/jdk1.6.0/bin/Java compile. compiler. Output on screenDoneAnd an err.txt file is generated in the current directory. The file content is as follows:

Note: compile/Target.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.

Observe carefullyrunMethod, you can find that the last parameter isString...argumentsIs a variable-length string array. Its actual function is to accept the parameters passed to javac. Suppose you want to compile the target. Java file and display the detailed information during the compilation process. Command Behavior:javac Target.java -verbose. You can change 17 sentences:

int compilationResult = compiler.run(null, null, err, “-verbose”,fullQuanlifiedFileName);

Compile non-text files

Another powerful feature of the JDK 6 compiler API is that the form of source files that can be compiled is not limited to text files.JavaCompilerClass relies on the file management service to compile multiple forms of source files. For example, files directly constructed by strings in the memory or files retrieved from the database. This service is composedJavaFileManagerClass. The compilation process consists of the following steps:

  1. Parse javac parameters;
  2. Find the source file or jar package in Source Path and/or classpath;
  3. Process input and output files;

In this process,JavaFileManagerClass can be used to create an output file, read and cache the output file. Because it can read and cache input files, it is possible to read various forms of input files. The command line tools provided by JDK have similar processing mechanisms. In future versions, it is also possible for other tools to process various forms of source files. To this end, the new JDK definesjavax.tools.FileObjectAndjavax.tools.JavaFileObjectInterface. Any class, as long as this interface is implemented, can beJavaFileManagerRecognition.

If you want to useJavaFileManager, You must constructCompilationTask. JDK 6 providesJavaCompiler.CompilationTaskClass to encapsulate a compilation operation. This class can be passed through:

JavaCompiler.getTask (
Writer out,
JavaFileManager fileManager,
DiagnosticListener<? super JavaFileObject> diagnosticListener,
Iterable<String> options,
Iterable<String> classes,
Iterable<? extends JavaFileObject> compilationUnits
)

Method. For more information about the meaning of each parameter, see the JDK documentation. Pass different parameters to get differentCompilationTask. By constructing this class, a compilation process can be divided into multiple steps. Further,CompilationTaskProvidedsetProcessors(Iterable<? extends Processor>processors)Method, you can develop a processor for processing annotation. Figure 1 showsCompilationTaskCompilation process:

Figure 1. Compile with compilationtask

In the following exampleCompilationTaskCompile a set of Java source files in multiple steps.

Listing 2. Construct compilationtask for compilation

01 package math;

02 public class Calculator {
03 public int multiply(int multiplicand, int multiplier) {
04 return multiplicand * multiplier;
05 }
06 }

07 package compile;
08 import javax.tools.*;
09 import java.io.FileOutputStream;
10 import java.util.Arrays;
11 public class Compiler {
12 public static void main(String[] args) throws Exception{
13 String fullQuanlifiedFileName = "math" + java.io.File.separator +"Calculator.java";
14 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
15 StandardJavaFileManager fileManager =
compiler.getStandardFileManager(null, null, null);

16 Iterable<? extends JavaFileObject> files =
fileManager.getJavaFileObjectsFromStrings(
Arrays.asList(fullQuanlifiedFileName));
17 JavaCompiler.CompilationTask task = compiler.getTask(
null, fileManager, null, null, null, files);

18 Boolean result = task.call();
19 if( result == true ) {
20 System.out.println("Succeeded");
21 }
22 }
23 }

The above is the first step, by constructingCompilationTaskCompiled a Java file. Lines 14-17 implement the main logic. First, get a compiler object. Because only common files need to be compiled, a standard file manager is obtained through the compiler object in line 1. Line 16: Construct the file to be compiled intoIterableObject. Finally, the file manager andIterableObjectJavaCompilerOfgetTaskMethod, obtainedJavaCompiler.CompilationTaskObject.

Step 2: developers want to generateCalculatorInstead of writing it manually. Using the compiler API, You can compile a string in the memory into a class file.

Listing 3. Customizing the javafileobject object

01 package math;
02 import java.net.URI;
03 public class StringObject extends SimpleJavaFileObject{
04 private String contents = null;
05 public StringObject(String className, String contents) throws Exception{
06 super(new URI(className), Kind.SOURCE);
07 this.contents = contents;
08 }

09 public CharSequence getCharContent(boolean ignoreEncodingErrors)
throws IOException {
10 return contents;
11 }
12 }

SimpleJavaFileObjectYesJavaFileObjectIt provides the default implementation. InheritanceSimpleJavaObjectAfter that, you only need to implementgetCharContentMethod. See rows 9-11 in listing 3. Next, constructCalculatorTest classCalculatorTestAnd place the string representing the classStringObjectToJavaCompilerOfgetTaskMethod. Listing 4 shows these steps.

Listing 4. compile non-text source files

01 package math;
02 import javax.tools.*;
03 import java.io.FileOutputStream;
04 import java.util.Arrays;
05 public class AdvancedCompiler {
06 public static void main(String[] args) throws Exception{

07 // Steps used to compile Calculator
08 // Steps used to compile StringObject

09 // construct CalculatorTest in memory
10 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
11 StandardJavaFileManager fileManager =
compiler.getStandardFileManager(null, null, null);
12 JavaFileObject file = constructTestor();
13 Iterable<? extends JavaFileObject> files = Arrays.asList(file);
14 JavaCompiler.CompilationTask task = compiler.getTask (
null, fileManager, null, null, null, files);

15 Boolean result = task.call();
16 if( result == true ) {
17 System.out.println("Succeeded");
18 }
19 }

20 private static SimpleJavaFileObject constructTestor() {
21 StringBuilder contents = new StringBuilder(
"package math;" +
"class CalculatorTest {/n" +
" public void testMultiply() {/n" +
" Calculator c = new Calculator();/n" +
" System.out.println(c.multiply(2, 4));/n" +
" }/n" +
" public static void main(String[] args) {/n" +
" CalculatorTest ct = new CalculatorTest();/n" +
" ct.testMultiply();/n" +
" }/n" +
"}/n");
22 StringObject so = null;
23 try {
24 so = new StringObject("math.CalculatorTest", contents.toString());
25 } catch(Exception exception) {
26 exception.printStackTrace();
27 }
28 return so;
29 }
30 }

The implementation logic is similar to that in Listing 2. The difference is that in 20-30 rows, the program constructs CalculatorTestAndStringObjectThe constructor converts the strings in the memoryJavaFileObjectObject.

Collect compiler diagnostic information

The third new feature is to collect diagnostic information during compilation. Diagnostic information, usually refers to errors, warnings, or detailed output during compilation. JDK 6 passesListenerTo obtain the information. If you want to registerDiagnosticListener, Must be usedCompilationTaskBecause the toolrunMethod cannot be registeredListener. The procedure is simple. First, constructListenerAnd then pass itJavaFileManagerConstructor. Listing 5 makes changes to listing 2, showing how to registerDiagnosticListener.

Listing 5. Register a diagnosticlistener to collect compilation Information

01 package math;

02 public class Calculator {
03 public int multiply(int multiplicand, int multiplier) {
04 return multiplicand * multiplier
// deliberately omit semicolon, ADiagnosticListener
// will take effect
05 }
06 }

07 package compile;
08 import javax.tools.*;
09 import java.io.FileOutputStream;
10 import java.util.Arrays;
11 public class CompilerWithListener {
12 public static void main(String[] args) throws Exception{
13 String fullQuanlifiedFileName = "math" +
java.io.File.separator +"Calculator.java";
14 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
15 StandardJavaFileManager fileManager =
compiler.getStandardFileManager(null, null, null);

16 Iterable<? extends JavaFileObject> files =
fileManager.getJavaFileObjectsFromStrings(
Arrays.asList(fullQuanlifiedFileName));
17 DiagnosticCollector<JavaFileObject> collector =
new DiagnosticCollector<JavaFileObject>();
18 JavaCompiler.CompilationTask task =
compiler.getTask(null, fileManager, collector, null, null, files);

19 Boolean result = task.call();
20 List<Diagnostic<? extends JavaFileObject>> diagnostics =
collector.getDiagnostics();
21 for(Diagnostic<? extends JavaFileObject> d : diagnostics){
22 System.out.println("Line Number->" + d.getLineNumber());
23 System.out.println("Message->"+
d.getMessage(Locale.ENGLISH));
24 System.out.println("Source" + d.getCode());
25 System.out.println("/n");
26 }

27 if( result == true ) {
28 System.out.println("Succeeded");
29 }
30 }
31 }

In row 17,DiagnosticCollectorObject provided by JDK, which implementsDiagnosticListenerInterface. Line 18 registers itCompilationTask. A compilation process may contain multiple diagnostic information. Each diagnostic information is abstracted asDiagnostic. 20-26 rows. All diagnostic information is output one by one. Compile and run compiler to get the following output:

Listing 6. Compilation information collected by diagnosticcollector

Line Number->5
Message->math/Calculator.java:5: ';' expected
Source->compiler.err.expected

In fact, it can also be customized by the user. Listing 7 provides a customizedListener.

Listing 7. Custom diagnosticlistener

01 class ADiagnosticListener implements DiagnosticListener<JavaFileObject>{
02 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
03 System.out.println("Line Number->" + diagnostic.getLineNumber());
04 System.out.println("Message->"+ diagnostic.getMessage(Locale.ENGLISH));
05 System.out.println("Source" + diagnostic.getCode());
06 System.out.println("/n");
07 }
08 }

Summary

The new features of the JDK 6 compiler allow developers to control the compilation process more freely, which gives Tool developers more flexibility. By calling APIs to complete compilation operations, developers can conveniently and efficiently turn compilation into a service when the software system is running. Compilation of more extensive source code provides powerful support for integrating more data sources and functions. We believe that with the continuous improvement of JDK, more tools will have API support, and we will wait and see.

References

  • ReadJava SE 6 new feature seriesA complete list of articles to learn about other important enhancements of Java SE 6.

  • Java SE 6 Document: Specification document of Java SE 6, which can be found in the official description of most new features.
  • Refer to the Java compiler API.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.