|
1 /* |
|
2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package com.sun.tools.javac.main; |
|
27 |
|
28 import java.io.File; |
|
29 import java.io.IOException; |
|
30 import java.io.PrintWriter; |
|
31 import java.net.URL; |
|
32 import java.security.DigestInputStream; |
|
33 import java.security.MessageDigest; |
|
34 import java.util.Arrays; |
|
35 import java.util.Collection; |
|
36 import java.util.Iterator; |
|
37 import java.util.LinkedHashSet; |
|
38 import java.util.Set; |
|
39 |
|
40 import javax.annotation.processing.Processor; |
|
41 import javax.tools.JavaFileManager; |
|
42 import javax.tools.JavaFileObject; |
|
43 |
|
44 import com.sun.source.util.JavacTask; |
|
45 import com.sun.source.util.Plugin; |
|
46 import com.sun.tools.doclint.DocLint; |
|
47 import com.sun.tools.javac.api.BasicJavacTask; |
|
48 import com.sun.tools.javac.code.Source; |
|
49 import com.sun.tools.javac.file.CacheFSInfo; |
|
50 import com.sun.tools.javac.file.JavacFileManager; |
|
51 import com.sun.tools.javac.jvm.Profile; |
|
52 import com.sun.tools.javac.jvm.Target; |
|
53 import com.sun.tools.javac.processing.AnnotationProcessingError; |
|
54 import com.sun.tools.javac.processing.JavacProcessingEnvironment; |
|
55 import com.sun.tools.javac.util.*; |
|
56 import com.sun.tools.javac.util.Log.PrefixKind; |
|
57 import com.sun.tools.javac.util.Log.WriterKind; |
|
58 import com.sun.tools.javac.util.ServiceLoader; |
|
59 import static com.sun.tools.javac.main.Option.*; |
|
60 |
|
61 /** This class provides a command line interface to the javac compiler. |
|
62 * |
|
63 * <p><b>This is NOT part of any supported API. |
|
64 * If you write code that depends on this, you do so at your own risk. |
|
65 * This code and its internal interfaces are subject to change or |
|
66 * deletion without notice.</b> |
|
67 */ |
|
68 public class Main { |
|
69 |
|
70 /** The name of the compiler, for use in diagnostics. |
|
71 */ |
|
72 String ownName; |
|
73 |
|
74 /** The writer to use for diagnostic output. |
|
75 */ |
|
76 PrintWriter out; |
|
77 |
|
78 /** The log to use for diagnostic output. |
|
79 */ |
|
80 public Log log; |
|
81 |
|
82 /** |
|
83 * If true, certain errors will cause an exception, such as command line |
|
84 * arg errors, or exceptions in user provided code. |
|
85 */ |
|
86 boolean apiMode; |
|
87 |
|
88 |
|
89 /** Result codes. |
|
90 */ |
|
91 public enum Result { |
|
92 OK(0), // Compilation completed with no errors. |
|
93 ERROR(1), // Completed but reported errors. |
|
94 CMDERR(2), // Bad command-line arguments |
|
95 SYSERR(3), // System error or resource exhaustion. |
|
96 ABNORMAL(4); // Compiler terminated abnormally |
|
97 |
|
98 Result(int exitCode) { |
|
99 this.exitCode = exitCode; |
|
100 } |
|
101 |
|
102 public boolean isOK() { |
|
103 return (exitCode == 0); |
|
104 } |
|
105 |
|
106 public final int exitCode; |
|
107 } |
|
108 |
|
109 private Option[] recognizedOptions = |
|
110 Option.getJavaCompilerOptions().toArray(new Option[0]); |
|
111 |
|
112 private OptionHelper optionHelper = new OptionHelper() { |
|
113 @Override |
|
114 public String get(Option option) { |
|
115 return options.get(option); |
|
116 } |
|
117 |
|
118 @Override |
|
119 public void put(String name, String value) { |
|
120 options.put(name, value); |
|
121 } |
|
122 |
|
123 @Override |
|
124 public void remove(String name) { |
|
125 options.remove(name); |
|
126 } |
|
127 |
|
128 @Override |
|
129 public Log getLog() { |
|
130 return log; |
|
131 } |
|
132 |
|
133 @Override |
|
134 public String getOwnName() { |
|
135 return ownName; |
|
136 } |
|
137 |
|
138 @Override |
|
139 public void error(String key, Object... args) { |
|
140 Main.this.error(key, args); |
|
141 } |
|
142 |
|
143 @Override |
|
144 public void addFile(File f) { |
|
145 filenames.add(f); |
|
146 } |
|
147 |
|
148 @Override |
|
149 public void addClassName(String s) { |
|
150 classnames.append(s); |
|
151 } |
|
152 |
|
153 }; |
|
154 |
|
155 /** |
|
156 * Construct a compiler instance. |
|
157 */ |
|
158 public Main(String name) { |
|
159 this(name, new PrintWriter(System.err, true)); |
|
160 } |
|
161 |
|
162 /** |
|
163 * Construct a compiler instance. |
|
164 */ |
|
165 public Main(String name, PrintWriter out) { |
|
166 this.ownName = name; |
|
167 this.out = out; |
|
168 } |
|
169 |
|
170 /** A table of all options that's passed to the JavaCompiler constructor. */ |
|
171 private Options options = null; |
|
172 |
|
173 /** The list of source files to process |
|
174 */ |
|
175 public Set<File> filenames = null; // XXX sb protected |
|
176 |
|
177 /** List of class files names passed on the command line |
|
178 */ |
|
179 public ListBuffer<String> classnames = null; // XXX sb protected |
|
180 |
|
181 /** Report a usage error. |
|
182 */ |
|
183 void error(String key, Object... args) { |
|
184 if (apiMode) { |
|
185 String msg = log.localize(PrefixKind.JAVAC, key, args); |
|
186 throw new PropagatedException(new IllegalStateException(msg)); |
|
187 } |
|
188 warning(key, args); |
|
189 log.printLines(PrefixKind.JAVAC, "msg.usage", ownName); |
|
190 } |
|
191 |
|
192 /** Report a warning. |
|
193 */ |
|
194 void warning(String key, Object... args) { |
|
195 log.printRawLines(ownName + ": " + log.localize(PrefixKind.JAVAC, key, args)); |
|
196 } |
|
197 |
|
198 public Option getOption(String flag) { |
|
199 for (Option option : recognizedOptions) { |
|
200 if (option.matches(flag)) |
|
201 return option; |
|
202 } |
|
203 return null; |
|
204 } |
|
205 |
|
206 public void setOptions(Options options) { |
|
207 if (options == null) |
|
208 throw new NullPointerException(); |
|
209 this.options = options; |
|
210 } |
|
211 |
|
212 public void setAPIMode(boolean apiMode) { |
|
213 this.apiMode = apiMode; |
|
214 } |
|
215 |
|
216 /** Process command line arguments: store all command line options |
|
217 * in `options' table and return all source filenames. |
|
218 * @param flags The array of command line arguments. |
|
219 */ |
|
220 public Collection<File> processArgs(String[] flags) { // XXX sb protected |
|
221 return processArgs(flags, null); |
|
222 } |
|
223 |
|
224 public Collection<File> processArgs(String[] flags, String[] classNames) { // XXX sb protected |
|
225 int ac = 0; |
|
226 while (ac < flags.length) { |
|
227 String flag = flags[ac]; |
|
228 ac++; |
|
229 |
|
230 Option option = null; |
|
231 |
|
232 if (flag.length() > 0) { |
|
233 // quick hack to speed up file processing: |
|
234 // if the option does not begin with '-', there is no need to check |
|
235 // most of the compiler options. |
|
236 int firstOptionToCheck = flag.charAt(0) == '-' ? 0 : recognizedOptions.length-1; |
|
237 for (int j=firstOptionToCheck; j<recognizedOptions.length; j++) { |
|
238 if (recognizedOptions[j].matches(flag)) { |
|
239 option = recognizedOptions[j]; |
|
240 break; |
|
241 } |
|
242 } |
|
243 } |
|
244 |
|
245 if (option == null) { |
|
246 error("err.invalid.flag", flag); |
|
247 return null; |
|
248 } |
|
249 |
|
250 if (option.hasArg()) { |
|
251 if (ac == flags.length) { |
|
252 error("err.req.arg", flag); |
|
253 return null; |
|
254 } |
|
255 String operand = flags[ac]; |
|
256 ac++; |
|
257 if (option.process(optionHelper, flag, operand)) |
|
258 return null; |
|
259 } else { |
|
260 if (option.process(optionHelper, flag)) |
|
261 return null; |
|
262 } |
|
263 } |
|
264 |
|
265 if (options.get(PROFILE) != null && options.get(BOOTCLASSPATH) != null) { |
|
266 error("err.profile.bootclasspath.conflict"); |
|
267 return null; |
|
268 } |
|
269 |
|
270 if (this.classnames != null && classNames != null) { |
|
271 this.classnames.addAll(Arrays.asList(classNames)); |
|
272 } |
|
273 |
|
274 if (!checkDirectory(D)) |
|
275 return null; |
|
276 if (!checkDirectory(S)) |
|
277 return null; |
|
278 |
|
279 String sourceString = options.get(SOURCE); |
|
280 Source source = (sourceString != null) |
|
281 ? Source.lookup(sourceString) |
|
282 : Source.DEFAULT; |
|
283 String targetString = options.get(TARGET); |
|
284 Target target = (targetString != null) |
|
285 ? Target.lookup(targetString) |
|
286 : Target.DEFAULT; |
|
287 // We don't check source/target consistency for CLDC, as J2ME |
|
288 // profiles are not aligned with J2SE targets; moreover, a |
|
289 // single CLDC target may have many profiles. In addition, |
|
290 // this is needed for the continued functioning of the JSR14 |
|
291 // prototype. |
|
292 if (Character.isDigit(target.name.charAt(0))) { |
|
293 if (target.compareTo(source.requiredTarget()) < 0) { |
|
294 if (targetString != null) { |
|
295 if (sourceString == null) { |
|
296 warning("warn.target.default.source.conflict", |
|
297 targetString, |
|
298 source.requiredTarget().name); |
|
299 } else { |
|
300 warning("warn.source.target.conflict", |
|
301 sourceString, |
|
302 source.requiredTarget().name); |
|
303 } |
|
304 return null; |
|
305 } else { |
|
306 target = source.requiredTarget(); |
|
307 options.put("-target", target.name); |
|
308 } |
|
309 } else { |
|
310 if (targetString == null && !source.allowGenerics()) { |
|
311 target = Target.JDK1_4; |
|
312 options.put("-target", target.name); |
|
313 } |
|
314 } |
|
315 } |
|
316 |
|
317 String profileString = options.get(PROFILE); |
|
318 if (profileString != null) { |
|
319 Profile profile = Profile.lookup(profileString); |
|
320 if (!profile.isValid(target)) { |
|
321 warning("warn.profile.target.conflict", profileString, target.name); |
|
322 return null; |
|
323 } |
|
324 } |
|
325 |
|
326 // handle this here so it works even if no other options given |
|
327 String showClass = options.get("showClass"); |
|
328 if (showClass != null) { |
|
329 if (showClass.equals("showClass")) // no value given for option |
|
330 showClass = "com.sun.tools.javac.Main"; |
|
331 showClass(showClass); |
|
332 } |
|
333 |
|
334 options.notifyListeners(); |
|
335 |
|
336 return filenames; |
|
337 } |
|
338 // where |
|
339 private boolean checkDirectory(Option option) { |
|
340 String value = options.get(option); |
|
341 if (value == null) |
|
342 return true; |
|
343 File file = new File(value); |
|
344 if (!file.exists()) { |
|
345 error("err.dir.not.found", value); |
|
346 return false; |
|
347 } |
|
348 if (!file.isDirectory()) { |
|
349 error("err.file.not.directory", value); |
|
350 return false; |
|
351 } |
|
352 return true; |
|
353 } |
|
354 |
|
355 /** Programmatic interface for main function. |
|
356 * @param args The command line parameters. |
|
357 */ |
|
358 public Result compile(String[] args) { |
|
359 Context context = new Context(); |
|
360 JavacFileManager.preRegister(context); // can't create it until Log has been set up |
|
361 Result result = compile(args, context); |
|
362 if (fileManager instanceof JavacFileManager) { |
|
363 // A fresh context was created above, so jfm must be a JavacFileManager |
|
364 ((JavacFileManager)fileManager).close(); |
|
365 } |
|
366 return result; |
|
367 } |
|
368 |
|
369 public Result compile(String[] args, Context context) { |
|
370 return compile(args, context, List.<JavaFileObject>nil(), null); |
|
371 } |
|
372 |
|
373 /** Programmatic interface for main function. |
|
374 * @param args The command line parameters. |
|
375 */ |
|
376 public Result compile(String[] args, |
|
377 Context context, |
|
378 List<JavaFileObject> fileObjects, |
|
379 Iterable<? extends Processor> processors) |
|
380 { |
|
381 return compile(args, null, context, fileObjects, processors); |
|
382 } |
|
383 |
|
384 public Result compile(String[] args, |
|
385 String[] classNames, |
|
386 Context context, |
|
387 List<JavaFileObject> fileObjects, |
|
388 Iterable<? extends Processor> processors) |
|
389 { |
|
390 context.put(Log.outKey, out); |
|
391 log = Log.instance(context); |
|
392 |
|
393 if (options == null) |
|
394 options = Options.instance(context); // creates a new one |
|
395 |
|
396 filenames = new LinkedHashSet<File>(); |
|
397 classnames = new ListBuffer<String>(); |
|
398 JavaCompiler comp = null; |
|
399 /* |
|
400 * TODO: Logic below about what is an acceptable command line |
|
401 * should be updated to take annotation processing semantics |
|
402 * into account. |
|
403 */ |
|
404 try { |
|
405 if (args.length == 0 |
|
406 && (classNames == null || classNames.length == 0) |
|
407 && fileObjects.isEmpty()) { |
|
408 Option.HELP.process(optionHelper, "-help"); |
|
409 return Result.CMDERR; |
|
410 } |
|
411 |
|
412 Collection<File> files; |
|
413 try { |
|
414 files = processArgs(CommandLine.parse(args), classNames); |
|
415 if (files == null) { |
|
416 // null signals an error in options, abort |
|
417 return Result.CMDERR; |
|
418 } else if (files.isEmpty() && fileObjects.isEmpty() && classnames.isEmpty()) { |
|
419 // it is allowed to compile nothing if just asking for help or version info |
|
420 if (options.isSet(HELP) |
|
421 || options.isSet(X) |
|
422 || options.isSet(VERSION) |
|
423 || options.isSet(FULLVERSION)) |
|
424 return Result.OK; |
|
425 if (JavaCompiler.explicitAnnotationProcessingRequested(options)) { |
|
426 error("err.no.source.files.classes"); |
|
427 } else { |
|
428 error("err.no.source.files"); |
|
429 } |
|
430 return Result.CMDERR; |
|
431 } |
|
432 } catch (java.io.FileNotFoundException e) { |
|
433 warning("err.file.not.found", e.getMessage()); |
|
434 return Result.SYSERR; |
|
435 } |
|
436 |
|
437 boolean forceStdOut = options.isSet("stdout"); |
|
438 if (forceStdOut) { |
|
439 log.flush(); |
|
440 log.setWriters(new PrintWriter(System.out, true)); |
|
441 } |
|
442 |
|
443 // allow System property in following line as a Mustang legacy |
|
444 boolean batchMode = (options.isUnset("nonBatchMode") |
|
445 && System.getProperty("nonBatchMode") == null); |
|
446 if (batchMode) |
|
447 CacheFSInfo.preRegister(context); |
|
448 |
|
449 // FIXME: this code will not be invoked if using JavacTask.parse/analyze/generate |
|
450 // invoke any available plugins |
|
451 String plugins = options.get(PLUGIN); |
|
452 if (plugins != null) { |
|
453 JavacProcessingEnvironment pEnv = JavacProcessingEnvironment.instance(context); |
|
454 ClassLoader cl = pEnv.getProcessorClassLoader(); |
|
455 ServiceLoader<Plugin> sl = ServiceLoader.load(Plugin.class, cl); |
|
456 Set<List<String>> pluginsToCall = new LinkedHashSet<List<String>>(); |
|
457 for (String plugin: plugins.split("\\x00")) { |
|
458 pluginsToCall.add(List.from(plugin.split("\\s+"))); |
|
459 } |
|
460 JavacTask task = null; |
|
461 Iterator<Plugin> iter = sl.iterator(); |
|
462 while (iter.hasNext()) { |
|
463 Plugin plugin = iter.next(); |
|
464 for (List<String> p: pluginsToCall) { |
|
465 if (plugin.getName().equals(p.head)) { |
|
466 pluginsToCall.remove(p); |
|
467 try { |
|
468 if (task == null) |
|
469 task = JavacTask.instance(pEnv); |
|
470 plugin.init(task, p.tail.toArray(new String[p.tail.size()])); |
|
471 } catch (Throwable ex) { |
|
472 if (apiMode) |
|
473 throw new RuntimeException(ex); |
|
474 pluginMessage(ex); |
|
475 return Result.SYSERR; |
|
476 } |
|
477 } |
|
478 } |
|
479 } |
|
480 for (List<String> p: pluginsToCall) { |
|
481 log.printLines(PrefixKind.JAVAC, "msg.plugin.not.found", p.head); |
|
482 } |
|
483 } |
|
484 |
|
485 comp = JavaCompiler.instance(context); |
|
486 |
|
487 // FIXME: this code will not be invoked if using JavacTask.parse/analyze/generate |
|
488 String xdoclint = options.get(XDOCLINT); |
|
489 String xdoclintCustom = options.get(XDOCLINT_CUSTOM); |
|
490 if (xdoclint != null || xdoclintCustom != null) { |
|
491 Set<String> doclintOpts = new LinkedHashSet<String>(); |
|
492 if (xdoclint != null) |
|
493 doclintOpts.add(DocLint.XMSGS_OPTION); |
|
494 if (xdoclintCustom != null) { |
|
495 for (String s: xdoclintCustom.split("\\s+")) { |
|
496 if (s.isEmpty()) |
|
497 continue; |
|
498 doclintOpts.add(s.replace(XDOCLINT_CUSTOM.text, DocLint.XMSGS_CUSTOM_PREFIX)); |
|
499 } |
|
500 } |
|
501 if (!(doclintOpts.size() == 1 |
|
502 && doclintOpts.iterator().next().equals(DocLint.XMSGS_CUSTOM_PREFIX + "none"))) { |
|
503 JavacTask t = BasicJavacTask.instance(context); |
|
504 // standard doclet normally generates H1, H2 |
|
505 doclintOpts.add(DocLint.XIMPLICIT_HEADERS + "2"); |
|
506 new DocLint().init(t, doclintOpts.toArray(new String[doclintOpts.size()])); |
|
507 comp.keepComments = true; |
|
508 } |
|
509 } |
|
510 |
|
511 fileManager = context.get(JavaFileManager.class); |
|
512 |
|
513 if (!files.isEmpty()) { |
|
514 // add filenames to fileObjects |
|
515 comp = JavaCompiler.instance(context); |
|
516 List<JavaFileObject> otherFiles = List.nil(); |
|
517 JavacFileManager dfm = (JavacFileManager)fileManager; |
|
518 for (JavaFileObject fo : dfm.getJavaFileObjectsFromFiles(files)) |
|
519 otherFiles = otherFiles.prepend(fo); |
|
520 for (JavaFileObject fo : otherFiles) |
|
521 fileObjects = fileObjects.prepend(fo); |
|
522 } |
|
523 comp.compile(fileObjects, |
|
524 classnames.toList(), |
|
525 processors); |
|
526 |
|
527 if (log.expectDiagKeys != null) { |
|
528 if (log.expectDiagKeys.isEmpty()) { |
|
529 log.printRawLines("all expected diagnostics found"); |
|
530 return Result.OK; |
|
531 } else { |
|
532 log.printRawLines("expected diagnostic keys not found: " + log.expectDiagKeys); |
|
533 return Result.ERROR; |
|
534 } |
|
535 } |
|
536 |
|
537 if (comp.errorCount() != 0) |
|
538 return Result.ERROR; |
|
539 } catch (IOException ex) { |
|
540 ioMessage(ex); |
|
541 return Result.SYSERR; |
|
542 } catch (OutOfMemoryError ex) { |
|
543 resourceMessage(ex); |
|
544 return Result.SYSERR; |
|
545 } catch (StackOverflowError ex) { |
|
546 resourceMessage(ex); |
|
547 return Result.SYSERR; |
|
548 } catch (FatalError ex) { |
|
549 feMessage(ex); |
|
550 return Result.SYSERR; |
|
551 } catch (AnnotationProcessingError ex) { |
|
552 if (apiMode) |
|
553 throw new RuntimeException(ex.getCause()); |
|
554 apMessage(ex); |
|
555 return Result.SYSERR; |
|
556 } catch (ClientCodeException ex) { |
|
557 // as specified by javax.tools.JavaCompiler#getTask |
|
558 // and javax.tools.JavaCompiler.CompilationTask#call |
|
559 throw new RuntimeException(ex.getCause()); |
|
560 } catch (PropagatedException ex) { |
|
561 throw ex.getCause(); |
|
562 } catch (Throwable ex) { |
|
563 // Nasty. If we've already reported an error, compensate |
|
564 // for buggy compiler error recovery by swallowing thrown |
|
565 // exceptions. |
|
566 if (comp == null || comp.errorCount() == 0 || |
|
567 options == null || options.isSet("dev")) |
|
568 bugMessage(ex); |
|
569 return Result.ABNORMAL; |
|
570 } finally { |
|
571 if (comp != null) { |
|
572 try { |
|
573 comp.close(); |
|
574 } catch (ClientCodeException ex) { |
|
575 throw new RuntimeException(ex.getCause()); |
|
576 } |
|
577 } |
|
578 filenames = null; |
|
579 options = null; |
|
580 } |
|
581 return Result.OK; |
|
582 } |
|
583 |
|
584 /** Print a message reporting an internal error. |
|
585 */ |
|
586 void bugMessage(Throwable ex) { |
|
587 log.printLines(PrefixKind.JAVAC, "msg.bug", JavaCompiler.version()); |
|
588 ex.printStackTrace(log.getWriter(WriterKind.NOTICE)); |
|
589 } |
|
590 |
|
591 /** Print a message reporting a fatal error. |
|
592 */ |
|
593 void feMessage(Throwable ex) { |
|
594 log.printRawLines(ex.getMessage()); |
|
595 if (ex.getCause() != null && options.isSet("dev")) { |
|
596 ex.getCause().printStackTrace(log.getWriter(WriterKind.NOTICE)); |
|
597 } |
|
598 } |
|
599 |
|
600 /** Print a message reporting an input/output error. |
|
601 */ |
|
602 void ioMessage(Throwable ex) { |
|
603 log.printLines(PrefixKind.JAVAC, "msg.io"); |
|
604 ex.printStackTrace(log.getWriter(WriterKind.NOTICE)); |
|
605 } |
|
606 |
|
607 /** Print a message reporting an out-of-resources error. |
|
608 */ |
|
609 void resourceMessage(Throwable ex) { |
|
610 log.printLines(PrefixKind.JAVAC, "msg.resource"); |
|
611 ex.printStackTrace(log.getWriter(WriterKind.NOTICE)); |
|
612 } |
|
613 |
|
614 /** Print a message reporting an uncaught exception from an |
|
615 * annotation processor. |
|
616 */ |
|
617 void apMessage(AnnotationProcessingError ex) { |
|
618 log.printLines(PrefixKind.JAVAC, "msg.proc.annotation.uncaught.exception"); |
|
619 ex.getCause().printStackTrace(log.getWriter(WriterKind.NOTICE)); |
|
620 } |
|
621 |
|
622 /** Print a message reporting an uncaught exception from an |
|
623 * annotation processor. |
|
624 */ |
|
625 void pluginMessage(Throwable ex) { |
|
626 log.printLines(PrefixKind.JAVAC, "msg.plugin.uncaught.exception"); |
|
627 ex.printStackTrace(log.getWriter(WriterKind.NOTICE)); |
|
628 } |
|
629 |
|
630 /** Display the location and checksum of a class. */ |
|
631 void showClass(String className) { |
|
632 PrintWriter pw = log.getWriter(WriterKind.NOTICE); |
|
633 pw.println("javac: show class: " + className); |
|
634 URL url = getClass().getResource('/' + className.replace('.', '/') + ".class"); |
|
635 if (url == null) |
|
636 pw.println(" class not found"); |
|
637 else { |
|
638 pw.println(" " + url); |
|
639 try { |
|
640 final String algorithm = "MD5"; |
|
641 byte[] digest; |
|
642 MessageDigest md = MessageDigest.getInstance(algorithm); |
|
643 DigestInputStream in = new DigestInputStream(url.openStream(), md); |
|
644 try { |
|
645 byte[] buf = new byte[8192]; |
|
646 int n; |
|
647 do { n = in.read(buf); } while (n > 0); |
|
648 digest = md.digest(); |
|
649 } finally { |
|
650 in.close(); |
|
651 } |
|
652 StringBuilder sb = new StringBuilder(); |
|
653 for (byte b: digest) |
|
654 sb.append(String.format("%02x", b)); |
|
655 pw.println(" " + algorithm + " checksum: " + sb); |
|
656 } catch (Exception e) { |
|
657 pw.println(" cannot compute digest: " + e); |
|
658 } |
|
659 } |
|
660 } |
|
661 |
|
662 private JavaFileManager fileManager; |
|
663 |
|
664 /* ************************************************************************ |
|
665 * Internationalization |
|
666 *************************************************************************/ |
|
667 |
|
668 // /** Find a localized string in the resource bundle. |
|
669 // * @param key The key for the localized string. |
|
670 // */ |
|
671 // public static String getLocalizedString(String key, Object... args) { // FIXME sb private |
|
672 // try { |
|
673 // if (messages == null) |
|
674 // messages = new JavacMessages(javacBundleName); |
|
675 // return messages.getLocalizedString("javac." + key, args); |
|
676 // } |
|
677 // catch (MissingResourceException e) { |
|
678 // throw new Error("Fatal Error: Resource for javac is missing", e); |
|
679 // } |
|
680 // } |
|
681 // |
|
682 // public static void useRawMessages(boolean enable) { |
|
683 // if (enable) { |
|
684 // messages = new JavacMessages(javacBundleName) { |
|
685 // @Override |
|
686 // public String getLocalizedString(String key, Object... args) { |
|
687 // return key; |
|
688 // } |
|
689 // }; |
|
690 // } else { |
|
691 // messages = new JavacMessages(javacBundleName); |
|
692 // } |
|
693 // } |
|
694 |
|
695 public static final String javacBundleName = |
|
696 "com.sun.tools.javac.resources.javac"; |
|
697 // |
|
698 // private static JavacMessages messages; |
|
699 } |