In many Java applications, you need to call the Java compiler in the program to compile and run the program. However, in earlier versions (Java se5 and earlier versions. com. sun. tools. the javac package is used to call the Java compiler. jar is not a standard Java library. You must set the jar path when using it. In Java se6, we provide a standard package for operating the Java compiler. This is the javax. Tools Package. With this package, we do not need to add the JAR file path to classpath.
1. Use the javacompiler interface to compile the Java source program
There are many ways to compile a Java source program using Java APIs. Now let's look at the simplest way to compile it using javacompiler.
You can use the static method getsystemjavacompiler of the toolprovider class to obtain an instance of the javacompiler interface.
Javacompiler compiler = toolprovider. getsystemjavacompiler (); |
The most important method in javacompiler is run. This method can be used to compile the Java source program. This method has three fixed parameters and one variable parameter (the variable parameter is a new parameter type provided starting from Jave se5, with type... Argu ). The first three parameters are used to provide parameters for the Java compiler, obtain the output information of the Java compiler, and receive the error information of the compiler. The variable parameters can be passed into one or more java source program files. If run is compiled successfully, 0 is returned.
Int run (inputstream in, outputstream out, outputstream err, string... arguments) |
If the first three parameters are null, the run method replaces the standard input and output, namely system. In, system. Out, And system. Err. If we want to compile a test. Java file and use standard input and output, run is used as follows:
Int Results = tool. Run (null, "test. Java "); |
The complete code for using javacompiler is as follows:
Import java. Io .*; Import javax. Tools .*; Public class test_compilerapi { Public static void main (string ARGs []) throws ioexception { Javacompiler compiler = toolprovider. getsystemjavacompiler (); Int Results = compiler. Run (null, "test. Java "); System. Out. println (Results = 0 )? "Compiled successfully": "Compilation failed "); // Run test in the program Runtime run = runtime. getruntime (); PROCESS p = run.exe C ("Java test "); Bufferedinputstream in = new bufferedinputstream (P. getinputstream ()); Bufferedreader BR = new bufferedreader (New inputstreamreader (in )); String S; While (S = Br. Readline ())! = NULL) System. Out. println (s ); } } Public class test { Public static void main (string [] ARGs) throws exception { System. Out. println ("javacompiler test successful! "); } } |
Output result of successful compilation:
Compiled successfully Javacompiler test successful |
Output result of compilation failure:
Test. Java: 9: The symbol cannot be found. Symbol: Method printlnln (Java. Lang. String) Location: Java. Io. printstream System. Out. printlnln ("javacompiler test successful! "); ^ 1 error Compilation failed |
Ii. Use standardjavafilemanager to compile Java source code
In the first part, we will discuss the easiest way to call the Java compiler. This method works well, but it cannot obtain the information we need more effectively, such as standard input and output information. The best method in Java se6 is to use the standardjavafilemanager class. This class can control input and output well, and obtain diagnostic information through diagnosticlistener, while the diagnosticcollector class is the implementation of listener.
Two steps are required to use standardjavafilemanager. First, create a diagnosticcollector instance and obtain a standardfilemanager object through the getstandardfilemanager () method of javacompiler. Finally, compile the source program using the call method in compilationtask.
The most complex method for calling Java compilation using this method is gettask. Let's discuss the gettask method. This method has the following six parameters.
Gettask (writer out, javafilemanager filemanager, Diagnosticlistener <? Super javafileobject> diagnosticlistener, Iterable <string> options, Iterable <string> classes, Iterable <? Extends javafileobject> compilationunits) |
Most of these parameters can be null. Their meanings.
- · Out: Output Error stream. The default value is system. Err.
- · Filemanager: standard file management.
- · Diagnosticlistener: the default behavior of the compiler.
- · Options: Compiler Options
- · Classes: the class to be compiled.
The last parameter compilationunits cannot be null, because this object saves the Java file you want to compile.
After using gettask, you must use the getjavafileobjectsfromfiles or getjavafileobjectsfromstrings method of standardjavafilemanager to obtain the compilationunits object. You can call these two methods as follows :.
Iterable <? Extends javafileobject> getjavafileobjectsfromfiles ( Iterable <? Extends File> files) Iterable <? Extends javafileobject> getjavafileobjectsfromstrings ( Iterable <string> names) String [] filenames = ...; Iterable <? Extends javafileobject> compilationunits = Filemanager. getjavafileobjectsfromfiles (arrays. aslist (filenames )); Javacompiler. compilationtask task = compiler. gettask (null, filemanager, Diagnostics, options, null, compilationunits ); |
Close filemanager. Close ();
The following is a complete demo program.
Import java. Io .*; Import java. util .*; Import javax. Tools .*; Public class test_compilerapi { Private Static void compilejava () throws exception { Javacompiler compiler = toolprovider. getsystemjavacompiler (); // Create a diagnosticcollector object Diagnosticcollector <javafileobject> diagnostics = new diagnosticcollector <javafileobject> (); Standardjavafilemanager filemanager = compiler. getstandardfilemanager (diagnostics, null, null ); // Create an object for saving the compiled file name // Each file is saved in a class inherited from javafileobject Iterable <? Extends javafileobject> compilationunits = filemanager . Getjavafileobjectsfromstrings (arrays aslist ("test3.java ")); Javacompiler. compilationtask task = compiler. gettask (null, filemanager, Diagnostics, null, null, compilationunits ); // Compile the source program Boolean success = task. Call (); Filemanager. Close (); System. Out. println (SUCCESS )? "Compiled successfully": "Compilation failed "); } Public static void main (string ARGs []) throws exception { Compilejava (); } } |
If you want to get a specific compilation error, you can scan diagnostics. The Code is as follows:
For (diagnostic: diagnostics. getdiagnostics ()) System. Out. printf ( "Code: % S % N" + "Kind: % S % N" + "Position: % S % N" + "Start position: % S % N" + "End position: % S % N" + "Source: % S % N" + "Message: % S % N ", Diagnostic. getcode (), diagnostic. getkind (), Diagnostic. getposition (), diagnostic. getstartposition (), Diagnostic. getendposition (), diagnostic. getsource (), Diagnostic. getmessage (null )); |
The compiled test. Java code is as follows:
Public class test { Public static void main (string [] ARGs) throws exception { AA; // incorrect statement System. Out. println ("javacompiler test successful! "); } } |
Write an AA in this Code and the compilation error is:
Code: Compiler. Err. Not. stmt Kind: Error Position: 89 Start position: 89 End position: 89 Source: test. Java Message: Test. Java: 5: Not a statement Success: false |
The. Class file is generated in the current directory by compiling with javacompiler, and the default directory can be changed by using the compilation option. The compilation option is a string-type iterable set of elements. For example, we can use the following code to generate a. Class file under the root directory of drive D.
Iterable <string> Options = arrays. aslist ("-d", "d ://"); Javacompiler. compilationtask task = compiler. gettask (null, filemanager, Diagnostics, options, null, compilationunits ); |
In the preceding example, the options parameter is null. To pass the compiler parameter, you need to pass the options parameter.
Sometimes we compile a Java source program file, which requires several other java files, and these java files are in another directory, therefore, you need to specify the directory of these files for the compiler.
Iterable <string> Options = arrays. aslist ("-sourcepath", "d: // SRC "); |
The preceding Code specifies the directory of the source files on which the compiled java files depend.
Iii. Compile from memory
Javacompiler can not only compile the java files on the hard disk, but also compile the Java code in the memory and then run them using reflection. We can write a javasourcefromstring class, through which we can enter the Java source code. Once this object is created, you can input any Java code to it and then compile and run it without writing a. Class file to the hard disk.
Import java. Lang. Reflect .*; Import java. Io .*; Import javax. Tools .*; Import javax. Tools. javacompiler. compilationtask; Import java. util .*; Import java.net .*; Public class test_compilerapi { Private Static void compilerjava () throws exception { Javacompiler compiler = toolprovider. getsystemjavacompiler (); Diagnosticcollector <javafileobject> diagnostics = new diagnosticcollector <javafileobject> (); // Define a stringwriter class for writing Java programs Stringwriter writer = new stringwriter (); Printwriter out = new printwriter (writer ); // Start writing Java programs Out. println ("public class helloworld {"); Out. println ("public static void main (string ARGs []) {"); Out. println ("system. Out. println (/" Hello, world /");"); Out. println ("}"); Out. println ("}"); Out. Close (); // Get a name for this code: helloworld, so that you can use reflection to call it later. Javafileobject file = new javasourcefromstring ("helloworld", writer. tostring ()); Iterable <? Extends javafileobject> compilationunits = arrays. aslist (File ); Javacompiler. compilationtask task = compiler. gettask (null, null, Diagnostics, null, null, compilationunits ); Boolean success = task. Call (); System. Out. println ("success:" + success ); // If successful, run the Java program through reflection If (SUCCESS) { System. Out. println ("----- output -----"); Class. forname ("helloworld"). getdeclaredmethod ("Main", new class [] {String []. Class}). Invoke (null, new object [] {Null }); System. Out. println ("----- output -----"); } } Public static void main (string ARGs []) throws exception { Compilerjava (); } } // Javasourcefromstring class used to pass the source program Class extends ourcefromstring 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; } } |