src/share/classes/com/sun/tools/javap/JavapTask.java

Tue, 08 Sep 2009 11:43:57 -0700

author
jjg
date
Tue, 08 Sep 2009 11:43:57 -0700
changeset 402
261c54b2312e
parent 350
526de25e0b28
child 404
14735c7932d7
permissions
-rw-r--r--

6879371: javap does not close internal default file manager
Reviewed-by: darcy

jjg@46 1 /*
xdono@54 2 * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
jjg@46 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jjg@46 4 *
jjg@46 5 * This code is free software; you can redistribute it and/or modify it
jjg@46 6 * under the terms of the GNU General Public License version 2 only, as
jjg@46 7 * published by the Free Software Foundation. Sun designates this
jjg@46 8 * particular file as subject to the "Classpath" exception as provided
jjg@46 9 * by Sun in the LICENSE file that accompanied this code.
jjg@46 10 *
jjg@46 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jjg@46 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jjg@46 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jjg@46 14 * version 2 for more details (a copy is included in the LICENSE file that
jjg@46 15 * accompanied this code).
jjg@46 16 *
jjg@46 17 * You should have received a copy of the GNU General Public License version
jjg@46 18 * 2 along with this work; if not, write to the Free Software Foundation,
jjg@90 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jjg@46 20 *
jjg@46 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
jjg@46 22 * CA 95054 USA or visit www.sun.com if you need additional information or
jjg@46 23 * have any questions.
jjg@46 24 */
jjg@46 25
jjg@46 26 package com.sun.tools.javap;
jjg@46 27
jjg@46 28 import java.io.EOFException;
jjg@46 29 import java.io.FileNotFoundException;
jjg@88 30 import java.io.FilterInputStream;
jjg@88 31 import java.io.InputStream;
jjg@46 32 import java.io.IOException;
jjg@46 33 import java.io.OutputStream;
jjg@46 34 import java.io.PrintWriter;
jjg@350 35 import java.io.Reader;
jjg@46 36 import java.io.StringWriter;
jjg@46 37 import java.io.Writer;
jjg@350 38 import java.net.URI;
jjg@88 39 import java.security.DigestInputStream;
jjg@88 40 import java.security.MessageDigest;
jjg@300 41 import java.security.NoSuchAlgorithmException;
jjg@46 42 import java.text.MessageFormat;
jjg@46 43 import java.util.ArrayList;
jjg@46 44 import java.util.Arrays;
jjg@283 45 import java.util.EnumSet;
jjg@46 46 import java.util.HashMap;
jjg@46 47 import java.util.Iterator;
jjg@46 48 import java.util.List;
jjg@46 49 import java.util.Locale;
jjg@46 50 import java.util.Map;
jjg@46 51 import java.util.MissingResourceException;
jjg@46 52 import java.util.ResourceBundle;
jjg@46 53
jjg@350 54 import javax.lang.model.element.Modifier;
jjg@350 55 import javax.lang.model.element.NestingKind;
jjg@46 56 import javax.tools.Diagnostic;
jjg@46 57 import javax.tools.DiagnosticListener;
jjg@46 58 import javax.tools.JavaFileManager;
jjg@46 59 import javax.tools.JavaFileObject;
jjg@46 60 import javax.tools.StandardJavaFileManager;
jjg@46 61 import javax.tools.StandardLocation;
jjg@46 62
jjg@46 63 import com.sun.tools.classfile.*;
jjg@350 64 import java.net.URISyntaxException;
jjg@350 65 import java.net.URL;
jjg@350 66 import java.net.URLConnection;
jjg@46 67
jjg@46 68 /**
jjg@46 69 * "Main" class for javap, normally accessed from the command line
jjg@46 70 * via Main, or from JSR199 via DisassemblerTool.
jjg@46 71 *
jjg@46 72 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
jjg@46 73 * you write code that depends on this, you do so at your own risk.
jjg@46 74 * This code and its internal interfaces are subject to change or
jjg@46 75 * deletion without notice.</b>
jjg@46 76 */
jjg@283 77 public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
jjg@46 78 public class BadArgs extends Exception {
jjg@46 79 static final long serialVersionUID = 8765093759964640721L;
jjg@46 80 BadArgs(String key, Object... args) {
jjg@46 81 super(JavapTask.this.getMessage(key, args));
jjg@46 82 this.key = key;
jjg@46 83 this.args = args;
jjg@46 84 }
jjg@46 85
jjg@46 86 BadArgs showUsage(boolean b) {
jjg@46 87 showUsage = b;
jjg@46 88 return this;
jjg@46 89 }
jjg@46 90
jjg@46 91 final String key;
jjg@46 92 final Object[] args;
jjg@46 93 boolean showUsage;
jjg@46 94 }
jjg@46 95
jjg@46 96 static abstract class Option {
jjg@46 97 Option(boolean hasArg, String... aliases) {
jjg@46 98 this.hasArg = hasArg;
jjg@46 99 this.aliases = aliases;
jjg@46 100 }
jjg@46 101
jjg@46 102 boolean matches(String opt) {
jjg@46 103 for (String a: aliases) {
jjg@46 104 if (a.equals(opt))
jjg@46 105 return true;
jjg@46 106 }
jjg@46 107 return false;
jjg@46 108 }
jjg@46 109
jjg@46 110 boolean ignoreRest() {
jjg@46 111 return false;
jjg@46 112 }
jjg@46 113
jjg@46 114 abstract void process(JavapTask task, String opt, String arg) throws BadArgs;
jjg@46 115
jjg@46 116 final boolean hasArg;
jjg@46 117 final String[] aliases;
jjg@46 118 }
jjg@46 119
jjg@46 120 static Option[] recognizedOptions = {
jjg@46 121
jjg@46 122 new Option(false, "-help", "--help", "-?") {
jjg@46 123 void process(JavapTask task, String opt, String arg) {
jjg@46 124 task.options.help = true;
jjg@46 125 }
jjg@46 126 },
jjg@46 127
jjg@46 128 new Option(false, "-version") {
jjg@46 129 void process(JavapTask task, String opt, String arg) {
jjg@46 130 task.options.version = true;
jjg@46 131 }
jjg@46 132 },
jjg@46 133
jjg@46 134 new Option(false, "-fullversion") {
jjg@46 135 void process(JavapTask task, String opt, String arg) {
jjg@46 136 task.options.fullVersion = true;
jjg@46 137 }
jjg@46 138 },
jjg@46 139
jjg@46 140 new Option(false, "-v", "-verbose", "-all") {
jjg@46 141 void process(JavapTask task, String opt, String arg) {
jjg@46 142 task.options.verbose = true;
jjg@46 143 task.options.showFlags = true;
jjg@46 144 task.options.showAllAttrs = true;
jjg@46 145 }
jjg@46 146 },
jjg@46 147
jjg@46 148 new Option(false, "-l") {
jjg@46 149 void process(JavapTask task, String opt, String arg) {
jjg@46 150 task.options.showLineAndLocalVariableTables = true;
jjg@46 151 }
jjg@46 152 },
jjg@46 153
jjg@46 154 new Option(false, "-public") {
jjg@46 155 void process(JavapTask task, String opt, String arg) {
jjg@68 156 task.options.accessOptions.add(opt);
jjg@46 157 task.options.showAccess = AccessFlags.ACC_PUBLIC;
jjg@46 158 }
jjg@46 159 },
jjg@46 160
jjg@46 161 new Option(false, "-protected") {
jjg@46 162 void process(JavapTask task, String opt, String arg) {
jjg@68 163 task.options.accessOptions.add(opt);
jjg@46 164 task.options.showAccess = AccessFlags.ACC_PROTECTED;
jjg@46 165 }
jjg@46 166 },
jjg@46 167
jjg@46 168 new Option(false, "-package") {
jjg@46 169 void process(JavapTask task, String opt, String arg) {
jjg@68 170 task.options.accessOptions.add(opt);
jjg@46 171 task.options.showAccess = 0;
jjg@46 172 }
jjg@46 173 },
jjg@46 174
jjg@46 175 new Option(false, "-p", "-private") {
jjg@46 176 void process(JavapTask task, String opt, String arg) {
jjg@68 177 if (!task.options.accessOptions.contains("-p") &&
jjg@68 178 !task.options.accessOptions.contains("-private")) {
jjg@68 179 task.options.accessOptions.add(opt);
jjg@68 180 }
jjg@46 181 task.options.showAccess = AccessFlags.ACC_PRIVATE;
jjg@46 182 }
jjg@46 183 },
jjg@46 184
jjg@46 185 new Option(false, "-c") {
jjg@46 186 void process(JavapTask task, String opt, String arg) {
jjg@46 187 task.options.showDisassembled = true;
jjg@46 188 }
jjg@46 189 },
jjg@46 190
jjg@46 191 new Option(false, "-s") {
jjg@46 192 void process(JavapTask task, String opt, String arg) {
jjg@46 193 task.options.showInternalSignatures = true;
jjg@46 194 }
jjg@46 195 },
jjg@46 196
jjg@46 197 // new Option(false, "-all") {
jjg@46 198 // void process(JavapTask task, String opt, String arg) {
jjg@46 199 // task.options.showAllAttrs = true;
jjg@46 200 // }
jjg@46 201 // },
jjg@46 202
jjg@46 203 new Option(false, "-h") {
jjg@46 204 void process(JavapTask task, String opt, String arg) throws BadArgs {
jjg@46 205 throw task.new BadArgs("err.h.not.supported");
jjg@46 206 }
jjg@46 207 },
jjg@46 208
jjg@46 209 new Option(false, "-verify", "-verify-verbose") {
jjg@46 210 void process(JavapTask task, String opt, String arg) throws BadArgs {
jjg@46 211 throw task.new BadArgs("err.verify.not.supported");
jjg@46 212 }
jjg@46 213 },
jjg@46 214
jjg@88 215 new Option(false, "-sysinfo") {
jjg@88 216 void process(JavapTask task, String opt, String arg) {
jjg@88 217 task.options.sysInfo = true;
jjg@88 218 }
jjg@88 219 },
jjg@88 220
jjg@46 221 new Option(false, "-Xold") {
jjg@46 222 void process(JavapTask task, String opt, String arg) throws BadArgs {
jjg@291 223 task.log.println(task.getMessage("warn.Xold.not.supported"));
jjg@46 224 }
jjg@46 225 },
jjg@46 226
jjg@46 227 new Option(false, "-Xnew") {
jjg@46 228 void process(JavapTask task, String opt, String arg) throws BadArgs {
jjg@46 229 // ignore: this _is_ the new version
jjg@46 230 }
jjg@46 231 },
jjg@46 232
jjg@46 233 new Option(false, "-XDcompat") {
jjg@46 234 void process(JavapTask task, String opt, String arg) {
jjg@46 235 task.options.compat = true;
jjg@46 236 }
jjg@46 237 },
jjg@46 238
jjg@46 239 new Option(false, "-XDjsr277") {
jjg@46 240 void process(JavapTask task, String opt, String arg) {
jjg@46 241 task.options.jsr277 = true;
jjg@46 242 }
jjg@46 243 },
jjg@46 244
jjg@283 245 new Option(false, "-XDdetails") {
jjg@283 246 void process(JavapTask task, String opt, String arg) {
jjg@283 247 task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
jjg@283 248 }
jjg@283 249
jjg@283 250 },
jjg@283 251
jjg@283 252 new Option(false, "-XDdetails:") {
jjg@283 253 @Override
jjg@283 254 boolean matches(String opt) {
jjg@283 255 int sep = opt.indexOf(":");
jjg@283 256 return sep != -1 && super.matches(opt.substring(0, sep + 1));
jjg@283 257 }
jjg@283 258
jjg@283 259 void process(JavapTask task, String opt, String arg) throws BadArgs {
jjg@283 260 int sep = opt.indexOf(":");
jjg@283 261 for (String v: opt.substring(sep + 1).split("[,: ]+")) {
jjg@283 262 if (!handleArg(task, v))
jjg@283 263 throw task.new BadArgs("err.invalid.arg.for.option", v);
jjg@283 264 }
jjg@283 265 }
jjg@283 266
jjg@283 267 boolean handleArg(JavapTask task, String arg) {
jjg@283 268 if (arg.length() == 0)
jjg@283 269 return true;
jjg@283 270
jjg@283 271 if (arg.equals("all")) {
jjg@283 272 task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
jjg@283 273 return true;
jjg@283 274 }
jjg@283 275
jjg@283 276 boolean on = true;
jjg@283 277 if (arg.startsWith("-")) {
jjg@283 278 on = false;
jjg@283 279 arg = arg.substring(1);
jjg@283 280 }
jjg@283 281
jjg@283 282 for (InstructionDetailWriter.Kind k: InstructionDetailWriter.Kind.values()) {
jjg@283 283 if (arg.equalsIgnoreCase(k.option)) {
jjg@283 284 if (on)
jjg@283 285 task.options.details.add(k);
jjg@283 286 else
jjg@283 287 task.options.details.remove(k);
jjg@283 288 return true;
jjg@283 289 }
jjg@283 290 }
jjg@283 291 return false;
jjg@283 292 }
jjg@283 293 },
jjg@283 294
jjg@87 295 new Option(false, "-constants") {
jjg@87 296 void process(JavapTask task, String opt, String arg) {
jjg@87 297 task.options.showConstants = true;
jjg@87 298 }
jjg@346 299 },
jjg@346 300
jjg@346 301 new Option(false, "-XDinner") {
jjg@346 302 void process(JavapTask task, String opt, String arg) {
jjg@346 303 task.options.showInnerClasses = true;
jjg@346 304 }
jjg@348 305 },
jjg@348 306
jjg@348 307 new Option(false, "-XDindent:") {
jjg@348 308 @Override
jjg@348 309 boolean matches(String opt) {
jjg@348 310 int sep = opt.indexOf(":");
jjg@348 311 return sep != -1 && super.matches(opt.substring(0, sep + 1));
jjg@348 312 }
jjg@348 313
jjg@348 314 void process(JavapTask task, String opt, String arg) throws BadArgs {
jjg@348 315 int sep = opt.indexOf(":");
jjg@348 316 try {
jjg@348 317 task.options.indentWidth = Integer.valueOf(opt.substring(sep + 1));
jjg@348 318 } catch (NumberFormatException e) {
jjg@348 319 }
jjg@348 320 }
jjg@348 321 },
jjg@348 322
jjg@348 323 new Option(false, "-XDtab:") {
jjg@348 324 @Override
jjg@348 325 boolean matches(String opt) {
jjg@348 326 int sep = opt.indexOf(":");
jjg@348 327 return sep != -1 && super.matches(opt.substring(0, sep + 1));
jjg@348 328 }
jjg@348 329
jjg@348 330 void process(JavapTask task, String opt, String arg) throws BadArgs {
jjg@348 331 int sep = opt.indexOf(":");
jjg@348 332 try {
jjg@348 333 task.options.tabColumn = Integer.valueOf(opt.substring(sep + 1));
jjg@348 334 } catch (NumberFormatException e) {
jjg@348 335 }
jjg@348 336 }
jjg@46 337 }
jjg@46 338
jjg@46 339 };
jjg@46 340
jjg@300 341 public JavapTask() {
jjg@46 342 context = new Context();
jjg@283 343 context.put(Messages.class, this);
jjg@46 344 options = Options.instance(context);
jjg@300 345 attributeFactory = new Attribute.Factory();
jjg@46 346 }
jjg@46 347
jjg@300 348 public JavapTask(Writer out,
jjg@300 349 JavaFileManager fileManager,
jjg@300 350 DiagnosticListener<? super JavaFileObject> diagnosticListener) {
jjg@300 351 this();
jjg@300 352 this.log = getPrintWriterForWriter(out);
jjg@300 353 this.fileManager = fileManager;
jjg@300 354 this.diagnosticListener = diagnosticListener;
jjg@300 355 }
jjg@300 356
jjg@300 357 public JavapTask(Writer out,
jjg@46 358 JavaFileManager fileManager,
jjg@46 359 DiagnosticListener<? super JavaFileObject> diagnosticListener,
jjg@46 360 Iterable<String> options,
jjg@46 361 Iterable<String> classes) {
jjg@300 362 this(out, fileManager, diagnosticListener);
jjg@46 363
jjg@340 364 this.classes = new ArrayList<String>();
jjg@340 365 for (String classname: classes) {
jjg@340 366 classname.getClass(); // null-check
jjg@340 367 this.classes.add(classname);
jjg@340 368 }
jjg@340 369
jjg@46 370 try {
jjg@46 371 handleOptions(options, false);
jjg@46 372 } catch (BadArgs e) {
jjg@46 373 throw new IllegalArgumentException(e.getMessage());
jjg@46 374 }
jjg@46 375 }
jjg@46 376
jjg@46 377 public void setLocale(Locale locale) {
jjg@46 378 if (locale == null)
jjg@46 379 locale = Locale.getDefault();
jjg@46 380 task_locale = locale;
jjg@46 381 }
jjg@46 382
jjg@46 383 public void setLog(PrintWriter log) {
jjg@46 384 this.log = log;
jjg@46 385 }
jjg@46 386
jjg@46 387 public void setLog(OutputStream s) {
jjg@46 388 setLog(getPrintWriterForStream(s));
jjg@46 389 }
jjg@46 390
jjg@46 391 private static PrintWriter getPrintWriterForStream(OutputStream s) {
jjg@46 392 return new PrintWriter(s, true);
jjg@46 393 }
jjg@46 394
jjg@46 395 private static PrintWriter getPrintWriterForWriter(Writer w) {
jjg@46 396 if (w == null)
jjg@46 397 return getPrintWriterForStream(null);
jjg@46 398 else if (w instanceof PrintWriter)
jjg@46 399 return (PrintWriter) w;
jjg@46 400 else
jjg@46 401 return new PrintWriter(w, true);
jjg@46 402 }
jjg@46 403
jjg@46 404 public void setDiagnosticListener(DiagnosticListener<? super JavaFileObject> dl) {
jjg@46 405 diagnosticListener = dl;
jjg@46 406 }
jjg@46 407
jjg@46 408 public void setDiagnosticListener(OutputStream s) {
jjg@46 409 setDiagnosticListener(getDiagnosticListenerForStream(s));
jjg@46 410 }
jjg@46 411
jjg@46 412 private DiagnosticListener<JavaFileObject> getDiagnosticListenerForStream(OutputStream s) {
jjg@46 413 return getDiagnosticListenerForWriter(getPrintWriterForStream(s));
jjg@46 414 }
jjg@46 415
jjg@46 416 private DiagnosticListener<JavaFileObject> getDiagnosticListenerForWriter(Writer w) {
jjg@46 417 final PrintWriter pw = getPrintWriterForWriter(w);
jjg@46 418 return new DiagnosticListener<JavaFileObject> () {
jjg@46 419 public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
jjg@340 420 switch (diagnostic.getKind()) {
jjg@340 421 case ERROR:
jjg@66 422 pw.print(getMessage("err.prefix"));
jjg@340 423 break;
jjg@340 424 case WARNING:
jjg@340 425 pw.print(getMessage("warn.prefix"));
jjg@340 426 break;
jjg@340 427 case NOTE:
jjg@340 428 pw.print(getMessage("note.prefix"));
jjg@340 429 break;
jjg@46 430 }
jjg@340 431 pw.print(" ");
jjg@46 432 pw.println(diagnostic.getMessage(null));
jjg@46 433 }
jjg@46 434 };
jjg@46 435 }
jjg@46 436
jjg@64 437 /** Result codes.
jjg@64 438 */
jjg@64 439 static final int
jjg@64 440 EXIT_OK = 0, // Compilation completed with no errors.
jjg@64 441 EXIT_ERROR = 1, // Completed but reported errors.
jjg@64 442 EXIT_CMDERR = 2, // Bad command-line arguments
jjg@64 443 EXIT_SYSERR = 3, // System error or resource exhaustion.
jjg@64 444 EXIT_ABNORMAL = 4; // Compiler terminated abnormally
jjg@64 445
jjg@46 446 int run(String[] args) {
jjg@46 447 try {
jjg@46 448 handleOptions(args);
jjg@64 449
jjg@64 450 // the following gives consistent behavior with javac
jjg@64 451 if (classes == null || classes.size() == 0) {
jjg@64 452 if (options.help || options.version || options.fullVersion)
jjg@64 453 return EXIT_OK;
jjg@64 454 else
jjg@64 455 return EXIT_CMDERR;
jjg@64 456 }
jjg@64 457
jjg@402 458 try {
jjg@402 459 boolean ok = run();
jjg@402 460 return ok ? EXIT_OK : EXIT_ERROR;
jjg@402 461 } finally {
jjg@402 462 if (defaultFileManager != null) {
jjg@402 463 try {
jjg@402 464 defaultFileManager.close();
jjg@402 465 defaultFileManager = null;
jjg@402 466 } catch (IOException e) {
jjg@402 467 throw new InternalError(e);
jjg@402 468 }
jjg@402 469 }
jjg@402 470 }
jjg@46 471 } catch (BadArgs e) {
jjg@340 472 reportError(e.key, e.args);
jjg@66 473 if (e.showUsage) {
jjg@66 474 log.println(getMessage("main.usage.summary", progname));
jjg@66 475 }
jjg@64 476 return EXIT_CMDERR;
jjg@46 477 } catch (InternalError e) {
jjg@46 478 Object[] e_args;
jjg@46 479 if (e.getCause() == null)
jjg@46 480 e_args = e.args;
jjg@46 481 else {
jjg@46 482 e_args = new Object[e.args.length + 1];
jjg@46 483 e_args[0] = e.getCause();
jjg@46 484 System.arraycopy(e.args, 0, e_args, 1, e.args.length);
jjg@46 485 }
jjg@340 486 reportError("err.internal.error", e_args);
jjg@64 487 return EXIT_ABNORMAL;
jjg@46 488 } finally {
jjg@46 489 log.flush();
jjg@46 490 }
jjg@46 491 }
jjg@46 492
jjg@46 493 public void handleOptions(String[] args) throws BadArgs {
jjg@46 494 handleOptions(Arrays.asList(args), true);
jjg@46 495 }
jjg@46 496
jjg@46 497 private void handleOptions(Iterable<String> args, boolean allowClasses) throws BadArgs {
jjg@46 498 if (log == null) {
jjg@46 499 log = getPrintWriterForStream(System.out);
jjg@46 500 if (diagnosticListener == null)
jjg@46 501 diagnosticListener = getDiagnosticListenerForStream(System.err);
jjg@46 502 } else {
jjg@46 503 if (diagnosticListener == null)
jjg@46 504 diagnosticListener = getDiagnosticListenerForWriter(log);
jjg@46 505 }
jjg@46 506
jjg@46 507
jjg@46 508 if (fileManager == null)
jjg@46 509 fileManager = getDefaultFileManager(diagnosticListener, log);
jjg@46 510
jjg@46 511 Iterator<String> iter = args.iterator();
jjg@64 512 boolean noArgs = !iter.hasNext();
jjg@46 513
jjg@46 514 while (iter.hasNext()) {
jjg@46 515 String arg = iter.next();
jjg@46 516 if (arg.startsWith("-"))
jjg@46 517 handleOption(arg, iter);
jjg@46 518 else if (allowClasses) {
jjg@46 519 if (classes == null)
jjg@46 520 classes = new ArrayList<String>();
jjg@46 521 classes.add(arg);
jjg@46 522 while (iter.hasNext())
jjg@46 523 classes.add(iter.next());
jjg@46 524 } else
jjg@46 525 throw new BadArgs("err.unknown.option", arg).showUsage(true);
jjg@46 526 }
jjg@46 527
jjg@68 528 if (!options.compat && options.accessOptions.size() > 1) {
jjg@68 529 StringBuilder sb = new StringBuilder();
jjg@68 530 for (String opt: options.accessOptions) {
jjg@68 531 if (sb.length() > 0)
jjg@68 532 sb.append(" ");
jjg@68 533 sb.append(opt);
jjg@68 534 }
jjg@68 535 throw new BadArgs("err.incompatible.options", sb);
jjg@68 536 }
jjg@68 537
jjg@46 538 if ((classes == null || classes.size() == 0) &&
jjg@64 539 !(noArgs || options.help || options.version || options.fullVersion)) {
jjg@46 540 throw new BadArgs("err.no.classes.specified");
jjg@46 541 }
jjg@64 542
jjg@64 543 if (noArgs || options.help)
jjg@64 544 showHelp();
jjg@64 545
jjg@64 546 if (options.version || options.fullVersion)
jjg@64 547 showVersion(options.fullVersion);
jjg@46 548 }
jjg@46 549
jjg@46 550 private void handleOption(String name, Iterator<String> rest) throws BadArgs {
jjg@46 551 for (Option o: recognizedOptions) {
jjg@46 552 if (o.matches(name)) {
jjg@46 553 if (o.hasArg) {
jjg@46 554 if (rest.hasNext())
jjg@46 555 o.process(this, name, rest.next());
jjg@46 556 else
jjg@46 557 throw new BadArgs("err.missing.arg", name).showUsage(true);
jjg@46 558 } else
jjg@46 559 o.process(this, name, null);
jjg@46 560
jjg@46 561 if (o.ignoreRest()) {
jjg@46 562 while (rest.hasNext())
jjg@46 563 rest.next();
jjg@46 564 }
jjg@46 565 return;
jjg@46 566 }
jjg@46 567 }
jjg@46 568
jjg@46 569 if (fileManager.handleOption(name, rest))
jjg@46 570 return;
jjg@46 571
jjg@46 572 throw new BadArgs("err.unknown.option", name).showUsage(true);
jjg@46 573 }
jjg@46 574
jjg@46 575 public Boolean call() {
jjg@46 576 return run();
jjg@46 577 }
jjg@46 578
jjg@46 579 public boolean run() {
jjg@46 580 if (classes == null || classes.size() == 0)
jjg@64 581 return false;
jjg@46 582
jjg@46 583 context.put(PrintWriter.class, log);
jjg@46 584 ClassWriter classWriter = ClassWriter.instance(context);
jjg@283 585 SourceWriter sourceWriter = SourceWriter.instance(context);
jjg@283 586 sourceWriter.setFileManager(fileManager);
jjg@46 587
jjg@346 588 attributeFactory.setCompat(options.compat);
jjg@346 589 attributeFactory.setJSR277(options.jsr277);
jjg@346 590
jjg@46 591 boolean ok = true;
jjg@46 592
jjg@46 593 for (String className: classes) {
jjg@46 594 JavaFileObject fo;
jjg@46 595 try {
jjg@346 596 writeClass(classWriter, className);
jjg@46 597 } catch (ConstantPoolException e) {
jjg@340 598 reportError("err.bad.constant.pool", className, e.getLocalizedMessage());
jjg@46 599 ok = false;
jjg@46 600 } catch (EOFException e) {
jjg@340 601 reportError("err.end.of.file", className);
jjg@46 602 ok = false;
jjg@46 603 } catch (FileNotFoundException e) {
jjg@340 604 reportError("err.file.not.found", e.getLocalizedMessage());
jjg@46 605 ok = false;
jjg@46 606 } catch (IOException e) {
jjg@46 607 //e.printStackTrace();
jjg@46 608 Object msg = e.getLocalizedMessage();
jjg@46 609 if (msg == null)
jjg@46 610 msg = e;
jjg@340 611 reportError("err.ioerror", className, msg);
jjg@46 612 ok = false;
jjg@46 613 } catch (Throwable t) {
jjg@46 614 StringWriter sw = new StringWriter();
jjg@46 615 PrintWriter pw = new PrintWriter(sw);
jjg@46 616 t.printStackTrace(pw);
jjg@46 617 pw.close();
jjg@340 618 reportError("err.crash", t.toString(), sw.toString());
jjg@52 619 ok = false;
jjg@46 620 }
jjg@46 621 }
jjg@46 622
jjg@46 623 return ok;
jjg@46 624 }
jjg@46 625
jjg@346 626 protected boolean writeClass(ClassWriter classWriter, String className)
jjg@346 627 throws IOException, ConstantPoolException {
jjg@350 628 JavaFileObject fo = open(className);
jjg@350 629 if (fo == null) {
jjg@350 630 reportError("err.class.not.found", className);
jjg@350 631 return false;
jjg@346 632 }
jjg@346 633
jjg@346 634 ClassFileInfo cfInfo = read(fo);
jjg@346 635 if (!className.endsWith(".class")) {
jjg@346 636 String cfName = cfInfo.cf.getName();
jjg@346 637 if (!cfName.replaceAll("[/$]", ".").equals(className.replaceAll("[/$]", ".")))
jjg@346 638 reportWarning("warn.unexpected.class", className, cfName.replace('/', '.'));
jjg@346 639 }
jjg@346 640 write(cfInfo);
jjg@346 641
jjg@346 642 if (options.showInnerClasses) {
jjg@346 643 ClassFile cf = cfInfo.cf;
jjg@346 644 Attribute a = cf.getAttribute(Attribute.InnerClasses);
jjg@346 645 if (a instanceof InnerClasses_attribute) {
jjg@346 646 InnerClasses_attribute inners = (InnerClasses_attribute) a;
jjg@346 647 try {
jjg@346 648 boolean ok = true;
jjg@346 649 for (int i = 0; i < inners.classes.length; i++) {
jjg@346 650 int outerIndex = inners.classes[i].outer_class_info_index;
jjg@346 651 ConstantPool.CONSTANT_Class_info outerClassInfo = cf.constant_pool.getClassInfo(outerIndex);
jjg@346 652 String outerClassName = outerClassInfo.getName();
jjg@346 653 if (outerClassName.equals(cf.getName())) {
jjg@346 654 int innerIndex = inners.classes[i].inner_class_info_index;
jjg@346 655 ConstantPool.CONSTANT_Class_info innerClassInfo = cf.constant_pool.getClassInfo(innerIndex);
jjg@346 656 String innerClassName = innerClassInfo.getName();
jjg@346 657 classWriter.println("// inner class " + innerClassName.replaceAll("[/$]", "."));
jjg@346 658 classWriter.println();
jjg@346 659 ok = ok & writeClass(classWriter, innerClassName);
jjg@346 660 }
jjg@346 661 }
jjg@346 662 return ok;
jjg@346 663 } catch (ConstantPoolException e) {
jjg@346 664 reportError("err.bad.innerclasses.attribute", className);
jjg@346 665 return false;
jjg@346 666 }
jjg@346 667 } else if (a != null) {
jjg@346 668 reportError("err.bad.innerclasses.attribute", className);
jjg@346 669 return false;
jjg@346 670 }
jjg@346 671 }
jjg@346 672
jjg@346 673 return true;
jjg@346 674 }
jjg@346 675
jjg@350 676 protected JavaFileObject open(String className) throws IOException {
jjg@350 677 // for compatibility, first see if it is a class name
jjg@350 678 JavaFileObject fo = getClassFileObject(className);
jjg@350 679 if (fo != null)
jjg@350 680 return fo;
jjg@350 681
jjg@350 682 // see if it is an inner class, by replacing dots to $, starting from the right
jjg@350 683 String cn = className;
jjg@350 684 int lastDot;
jjg@350 685 while ((lastDot = cn.lastIndexOf(".")) != -1) {
jjg@350 686 cn = cn.substring(0, lastDot) + "$" + cn.substring(lastDot + 1);
jjg@350 687 fo = getClassFileObject(cn);
jjg@350 688 if (fo != null)
jjg@350 689 return fo;
jjg@350 690 }
jjg@350 691
jjg@350 692 if (!className.endsWith(".class"))
jjg@350 693 return null;
jjg@350 694
jjg@350 695 if (fileManager instanceof StandardJavaFileManager) {
jjg@350 696 StandardJavaFileManager sfm = (StandardJavaFileManager) fileManager;
jjg@350 697 fo = sfm.getJavaFileObjects(className).iterator().next();
jjg@350 698 if (fo != null && fo.getLastModified() != 0) {
jjg@350 699 return fo;
jjg@350 700 }
jjg@350 701 }
jjg@350 702
jjg@350 703 // see if it is a URL, and if so, wrap it in just enough of a JavaFileObject
jjg@350 704 // to suit javap's needs
jjg@350 705 if (className.matches("^[A-Za-z]+:.*")) {
jjg@350 706 try {
jjg@350 707 final URI uri = new URI(className);
jjg@350 708 final URL url = uri.toURL();
jjg@350 709 final URLConnection conn = url.openConnection();
jjg@350 710 return new JavaFileObject() {
jjg@350 711 public Kind getKind() {
jjg@350 712 return JavaFileObject.Kind.CLASS;
jjg@350 713 }
jjg@350 714
jjg@350 715 public boolean isNameCompatible(String simpleName, Kind kind) {
jjg@350 716 throw new UnsupportedOperationException();
jjg@350 717 }
jjg@350 718
jjg@350 719 public NestingKind getNestingKind() {
jjg@350 720 throw new UnsupportedOperationException();
jjg@350 721 }
jjg@350 722
jjg@350 723 public Modifier getAccessLevel() {
jjg@350 724 throw new UnsupportedOperationException();
jjg@350 725 }
jjg@350 726
jjg@350 727 public URI toUri() {
jjg@350 728 return uri;
jjg@350 729 }
jjg@350 730
jjg@350 731 public String getName() {
jjg@350 732 return url.toString();
jjg@350 733 }
jjg@350 734
jjg@350 735 public InputStream openInputStream() throws IOException {
jjg@350 736 return conn.getInputStream();
jjg@350 737 }
jjg@350 738
jjg@350 739 public OutputStream openOutputStream() throws IOException {
jjg@350 740 throw new UnsupportedOperationException();
jjg@350 741 }
jjg@350 742
jjg@350 743 public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
jjg@350 744 throw new UnsupportedOperationException();
jjg@350 745 }
jjg@350 746
jjg@350 747 public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
jjg@350 748 throw new UnsupportedOperationException();
jjg@350 749 }
jjg@350 750
jjg@350 751 public Writer openWriter() throws IOException {
jjg@350 752 throw new UnsupportedOperationException();
jjg@350 753 }
jjg@350 754
jjg@350 755 public long getLastModified() {
jjg@350 756 return conn.getLastModified();
jjg@350 757 }
jjg@350 758
jjg@350 759 public boolean delete() {
jjg@350 760 throw new UnsupportedOperationException();
jjg@350 761 }
jjg@350 762
jjg@350 763 };
jjg@350 764 } catch (URISyntaxException ignore) {
jjg@350 765 } catch (IOException ignore) {
jjg@350 766 }
jjg@350 767 }
jjg@350 768
jjg@350 769 return null;
jjg@350 770 }
jjg@350 771
jjg@300 772 public static class ClassFileInfo {
jjg@300 773 ClassFileInfo(JavaFileObject fo, ClassFile cf, byte[] digest, int size) {
jjg@300 774 this.fo = fo;
jjg@300 775 this.cf = cf;
jjg@300 776 this.digest = digest;
jjg@300 777 this.size = size;
jjg@300 778 }
jjg@300 779 public final JavaFileObject fo;
jjg@300 780 public final ClassFile cf;
jjg@300 781 public final byte[] digest;
jjg@300 782 public final int size;
jjg@300 783 }
jjg@300 784
jjg@300 785 public ClassFileInfo read(JavaFileObject fo) throws IOException, ConstantPoolException {
jjg@300 786 InputStream in = fo.openInputStream();
jjg@300 787 try {
jjg@300 788 SizeInputStream sizeIn = null;
jjg@300 789 MessageDigest md = null;
jjg@300 790 if (options.sysInfo || options.verbose) {
jjg@300 791 try {
jjg@300 792 md = MessageDigest.getInstance("MD5");
jjg@300 793 } catch (NoSuchAlgorithmException ignore) {
jjg@300 794 }
jjg@300 795 in = new DigestInputStream(in, md);
jjg@300 796 in = sizeIn = new SizeInputStream(in);
jjg@300 797 }
jjg@300 798
jjg@300 799 ClassFile cf = ClassFile.read(in, attributeFactory);
jjg@300 800 byte[] digest = (md == null) ? null : md.digest();
jjg@300 801 int size = (sizeIn == null) ? -1 : sizeIn.size();
jjg@300 802 return new ClassFileInfo(fo, cf, digest, size);
jjg@300 803 } finally {
jjg@300 804 in.close();
jjg@300 805 }
jjg@300 806 }
jjg@300 807
jjg@300 808 public void write(ClassFileInfo info) {
jjg@300 809 ClassWriter classWriter = ClassWriter.instance(context);
jjg@300 810 if (options.sysInfo || options.verbose) {
jjg@300 811 classWriter.setFile(info.fo.toUri());
jjg@300 812 classWriter.setLastModified(info.fo.getLastModified());
jjg@300 813 classWriter.setDigest("MD5", info.digest);
jjg@300 814 classWriter.setFileSize(info.size);
jjg@300 815 }
jjg@300 816
jjg@300 817 classWriter.write(info.cf);
jjg@300 818 }
jjg@300 819
jjg@300 820 protected void setClassFile(ClassFile classFile) {
jjg@300 821 ClassWriter classWriter = ClassWriter.instance(context);
jjg@300 822 classWriter.setClassFile(classFile);
jjg@300 823 }
jjg@300 824
jjg@300 825 protected void setMethod(Method enclosingMethod) {
jjg@300 826 ClassWriter classWriter = ClassWriter.instance(context);
jjg@300 827 classWriter.setMethod(enclosingMethod);
jjg@300 828 }
jjg@300 829
jjg@300 830 protected void write(Attribute value) {
jjg@300 831 AttributeWriter attrWriter = AttributeWriter.instance(context);
jjg@300 832 ClassWriter classWriter = ClassWriter.instance(context);
jjg@300 833 ClassFile cf = classWriter.getClassFile();
jjg@300 834 attrWriter.write(cf, value, cf.constant_pool);
jjg@300 835 }
jjg@300 836
jjg@300 837 protected void write(Attributes attrs) {
jjg@300 838 AttributeWriter attrWriter = AttributeWriter.instance(context);
jjg@300 839 ClassWriter classWriter = ClassWriter.instance(context);
jjg@300 840 ClassFile cf = classWriter.getClassFile();
jjg@300 841 attrWriter.write(cf, attrs, cf.constant_pool);
jjg@300 842 }
jjg@300 843
jjg@300 844 protected void write(ConstantPool constant_pool) {
jjg@300 845 ConstantWriter constantWriter = ConstantWriter.instance(context);
jjg@300 846 constantWriter.writeConstantPool(constant_pool);
jjg@300 847 }
jjg@300 848
jjg@300 849 protected void write(ConstantPool constant_pool, int value) {
jjg@300 850 ConstantWriter constantWriter = ConstantWriter.instance(context);
jjg@300 851 constantWriter.write(value);
jjg@300 852 }
jjg@300 853
jjg@300 854 protected void write(ConstantPool.CPInfo value) {
jjg@300 855 ConstantWriter constantWriter = ConstantWriter.instance(context);
jjg@300 856 constantWriter.println(value);
jjg@300 857 }
jjg@300 858
jjg@300 859 protected void write(Field value) {
jjg@300 860 ClassWriter classWriter = ClassWriter.instance(context);
jjg@300 861 classWriter.writeField(value);
jjg@300 862 }
jjg@300 863
jjg@300 864 protected void write(Method value) {
jjg@300 865 ClassWriter classWriter = ClassWriter.instance(context);
jjg@300 866 classWriter.writeMethod(value);
jjg@300 867 }
jjg@300 868
jjg@46 869 private JavaFileManager getDefaultFileManager(final DiagnosticListener<? super JavaFileObject> dl, PrintWriter log) {
jjg@402 870 if (defaultFileManager == null)
jjg@402 871 defaultFileManager = JavapFileManager.create(dl, log);
jjg@402 872 return defaultFileManager;
jjg@46 873 }
jjg@46 874
jjg@46 875 private JavaFileObject getClassFileObject(String className) throws IOException {
jjg@46 876 JavaFileObject fo;
jjg@46 877 fo = fileManager.getJavaFileForInput(StandardLocation.PLATFORM_CLASS_PATH, className, JavaFileObject.Kind.CLASS);
jjg@46 878 if (fo == null)
jjg@46 879 fo = fileManager.getJavaFileForInput(StandardLocation.CLASS_PATH, className, JavaFileObject.Kind.CLASS);
jjg@46 880 return fo;
jjg@46 881 }
jjg@46 882
jjg@46 883 private void showHelp() {
jjg@46 884 log.println(getMessage("main.usage", progname));
jjg@46 885 for (Option o: recognizedOptions) {
jjg@46 886 String name = o.aliases[0].substring(1); // there must always be at least one name
jjg@46 887 if (name.startsWith("X") || name.equals("fullversion") || name.equals("h") || name.equals("verify"))
jjg@46 888 continue;
jjg@46 889 log.println(getMessage("main.opt." + name));
jjg@46 890 }
jjg@46 891 String[] fmOptions = { "-classpath", "-bootclasspath" };
jjg@46 892 for (String o: fmOptions) {
jjg@46 893 if (fileManager.isSupportedOption(o) == -1)
jjg@46 894 continue;
jjg@46 895 String name = o.substring(1);
jjg@46 896 log.println(getMessage("main.opt." + name));
jjg@46 897 }
jjg@46 898
jjg@46 899 }
jjg@46 900
jjg@46 901 private void showVersion(boolean full) {
jjg@46 902 log.println(version(full ? "full" : "release"));
jjg@46 903 }
jjg@46 904
jjg@46 905 private static final String versionRBName = "com.sun.tools.javap.resources.version";
jjg@46 906 private static ResourceBundle versionRB;
jjg@46 907
jjg@46 908 private String version(String key) {
jjg@46 909 // key=version: mm.nn.oo[-milestone]
jjg@46 910 // key=full: mm.mm.oo[-milestone]-build
jjg@46 911 if (versionRB == null) {
jjg@46 912 try {
jjg@46 913 versionRB = ResourceBundle.getBundle(versionRBName);
jjg@46 914 } catch (MissingResourceException e) {
jjg@46 915 return getMessage("version.resource.missing", System.getProperty("java.version"));
jjg@46 916 }
jjg@46 917 }
jjg@46 918 try {
jjg@46 919 return versionRB.getString(key);
jjg@46 920 }
jjg@46 921 catch (MissingResourceException e) {
jjg@46 922 return getMessage("version.unknown", System.getProperty("java.version"));
jjg@46 923 }
jjg@46 924 }
jjg@46 925
jjg@340 926 private void reportError(String key, Object... args) {
jjg@340 927 diagnosticListener.report(createDiagnostic(Diagnostic.Kind.ERROR, key, args));
jjg@340 928 }
jjg@340 929
jjg@340 930 private void reportNote(String key, Object... args) {
jjg@340 931 diagnosticListener.report(createDiagnostic(Diagnostic.Kind.NOTE, key, args));
jjg@340 932 }
jjg@340 933
jjg@340 934 private void reportWarning(String key, Object... args) {
jjg@340 935 diagnosticListener.report(createDiagnostic(Diagnostic.Kind.WARNING, key, args));
jjg@340 936 }
jjg@340 937
jjg@340 938 private Diagnostic<JavaFileObject> createDiagnostic(
jjg@340 939 final Diagnostic.Kind kind, final String key, final Object... args) {
jjg@46 940 return new Diagnostic<JavaFileObject>() {
jjg@46 941 public Kind getKind() {
jjg@340 942 return kind;
jjg@46 943 }
jjg@46 944
jjg@46 945 public JavaFileObject getSource() {
jjg@46 946 return null;
jjg@46 947 }
jjg@46 948
jjg@46 949 public long getPosition() {
jjg@46 950 return Diagnostic.NOPOS;
jjg@46 951 }
jjg@46 952
jjg@46 953 public long getStartPosition() {
jjg@46 954 return Diagnostic.NOPOS;
jjg@46 955 }
jjg@46 956
jjg@46 957 public long getEndPosition() {
jjg@46 958 return Diagnostic.NOPOS;
jjg@46 959 }
jjg@46 960
jjg@46 961 public long getLineNumber() {
jjg@46 962 return Diagnostic.NOPOS;
jjg@46 963 }
jjg@46 964
jjg@46 965 public long getColumnNumber() {
jjg@46 966 return Diagnostic.NOPOS;
jjg@46 967 }
jjg@46 968
jjg@46 969 public String getCode() {
jjg@46 970 return key;
jjg@46 971 }
jjg@46 972
jjg@46 973 public String getMessage(Locale locale) {
jjg@46 974 return JavapTask.this.getMessage(locale, key, args);
jjg@46 975 }
jjg@46 976
jjg@346 977 @Override
jjg@340 978 public String toString() {
jjg@340 979 return getClass().getName() + "[key=" + key + ",args=" + Arrays.asList(args) + "]";
jjg@340 980 }
jjg@340 981
jjg@46 982 };
jjg@46 983
jjg@46 984 }
jjg@46 985
jjg@283 986 public String getMessage(String key, Object... args) {
jjg@46 987 return getMessage(task_locale, key, args);
jjg@46 988 }
jjg@46 989
jjg@283 990 public String getMessage(Locale locale, String key, Object... args) {
jjg@46 991 if (bundles == null) {
jjg@46 992 // could make this a HashMap<Locale,SoftReference<ResourceBundle>>
jjg@46 993 // and for efficiency, keep a hard reference to the bundle for the task
jjg@46 994 // locale
jjg@46 995 bundles = new HashMap<Locale, ResourceBundle>();
jjg@46 996 }
jjg@46 997
jjg@46 998 if (locale == null)
jjg@46 999 locale = Locale.getDefault();
jjg@46 1000
jjg@46 1001 ResourceBundle b = bundles.get(locale);
jjg@46 1002 if (b == null) {
jjg@46 1003 try {
jjg@46 1004 b = ResourceBundle.getBundle("com.sun.tools.javap.resources.javap", locale);
jjg@46 1005 bundles.put(locale, b);
jjg@46 1006 } catch (MissingResourceException e) {
jjg@46 1007 throw new InternalError("Cannot find javap resource bundle for locale " + locale);
jjg@46 1008 }
jjg@46 1009 }
jjg@46 1010
jjg@46 1011 try {
jjg@46 1012 return MessageFormat.format(b.getString(key), args);
jjg@46 1013 } catch (MissingResourceException e) {
jjg@46 1014 throw new InternalError(e, key);
jjg@46 1015 }
jjg@46 1016 }
jjg@46 1017
jjg@300 1018 protected Context context;
jjg@46 1019 JavaFileManager fileManager;
jjg@402 1020 JavaFileManager defaultFileManager;
jjg@46 1021 PrintWriter log;
jjg@46 1022 DiagnosticListener<? super JavaFileObject> diagnosticListener;
jjg@46 1023 List<String> classes;
jjg@46 1024 Options options;
jjg@46 1025 //ResourceBundle bundle;
jjg@46 1026 Locale task_locale;
jjg@46 1027 Map<Locale, ResourceBundle> bundles;
jjg@300 1028 protected Attribute.Factory attributeFactory;
jjg@46 1029
jjg@46 1030 private static final String progname = "javap";
jjg@88 1031
jjg@88 1032 private static class SizeInputStream extends FilterInputStream {
jjg@88 1033 SizeInputStream(InputStream in) {
jjg@88 1034 super(in);
jjg@88 1035 }
jjg@88 1036
jjg@88 1037 int size() {
jjg@88 1038 return size;
jjg@88 1039 }
jjg@88 1040
jjg@88 1041 @Override
jjg@88 1042 public int read(byte[] buf, int offset, int length) throws IOException {
jjg@88 1043 int n = super.read(buf, offset, length);
jjg@88 1044 if (n > 0)
jjg@88 1045 size += n;
jjg@88 1046 return n;
jjg@88 1047 }
jjg@88 1048
jjg@88 1049 @Override
jjg@88 1050 public int read() throws IOException {
jjg@88 1051 int b = super.read();
jjg@88 1052 size += 1;
jjg@88 1053 return b;
jjg@88 1054 }
jjg@88 1055
jjg@88 1056 private int size;
jjg@88 1057 }
jjg@46 1058 }

mercurial