package annotations.io.classfile; /*>>> import org.checkerframework.checker.nullness.qual.*; */ import java.io.*; import plume.*; import com.sun.tools.javac.main.CommandLine; import org.objectweb.asm.ClassReader; import annotations.el.AScene; import annotations.io.IndexFileWriter; /** * A <code> ClassFileReader </code> provides methods for reading in annotations * from a class file into an {@link annotations.el.AScene}. */ public class ClassFileReader { public static final String INDEX_UTILS_VERSION = "Annotation File Utilities v3.6.44"; @Option("-b omit annotations from bridge (compiler-created) methods") public static boolean ignore_bridge_methods = false; @Option("-h print usage information and exit") public static boolean help = false; @Option("-v print version information and exit") public static boolean version = false; private static String linesep = System.getProperty("line.separator"); static String usage = "extract-annotations [options] class1 class2 ..." + linesep + "Each argument is a class a.b.C (that is on your classpath) or a class file" + linesep + "a/b/C.class. Extracts the annotations from each such argument and prints" + linesep + "them in index-file format to a.b.C.jaif . Arguments beginning with a" + linesep + "single '@' are interpreted as argument files to be read and expanded into" + linesep + "the command line. Options:"; /** * From the command line, read annotations from a class file and write * them to an index file. Also see the Anncat tool, which is more * versatile (and which calls this as a subroutine). * <p> * * For usage information, supply the -h or --help option. * <p> * * For programmatic access to this tool, use the read() methods instead. * <p> * * @param args options and classes to analyze; * @throws IOException if a class file cannot be found */ public static void main(String[] args) throws IOException { Options options = new Options(usage, ClassFileReader.class); String[] file_args; try { String[] cl_args = CommandLine.parse(args); file_args = options.parse_or_usage(cl_args); } catch (IOException ex) { System.err.println(ex); System.err.println("(For non-argfile beginning with \"@\", use \"@@\" for initial \"@\"."); System.err.println("Alternative for filenames: indicate directory, e.g. as './@file'."); System.err.println("Alternative for flags: use '=', as in '-o=@Deprecated'.)"); file_args = null; // Eclipse compiler issue workaround System.exit(1); } if (version) { System.out.printf("extract-annotations (%s)", INDEX_UTILS_VERSION); } if (help) { options.print_usage(); } if (version || help) { System.exit(-1); } if (file_args.length == 0) { options.print_usage("No arguments given."); System.exit(-1); } // check args for well-formed names for (String arg : file_args) { if (!checkClass(arg)) { System.exit(-1); } } for (String origName : file_args) { System.out.println("reading: " + origName); String className = origName; if (origName.endsWith(".class")) { origName = origName.replace(".class", ""); } AScene scene = new AScene(); try { if (className.endsWith(".class")) { read(scene, className); } else { readFromClass(scene, className); } String outputFile = origName + ".jaif"; System.out.println("printing results to : " + outputFile); IndexFileWriter.write(scene, outputFile); } catch (IOException e) { System.out.println("There was an error in reading class: " + origName); System.out.println( "Did you ensure that this class is on your classpath?"); return; } catch (Exception e) { System.out.println("Unknown error trying to extract annotations from: " + origName); System.out.println(e.getMessage()); e.printStackTrace(); System.out.println("Please submit a bug report at"); System.out.println(" https://github.com/typetools/annotation-tools/issues"); System.out.println("Be sure to include a copy of the output trace, instructions on how"); System.out.println("to reproduce this error, and all input files. Thanks!"); return; } } } /** * If s is not a valid representation of a class, print a warning message * and return false. */ public static boolean checkClass(String arg) { // check for invalid class file paths with '.' if (!arg.contains(".class") && arg.contains("/")) { System.out.println("Error: bad class " + arg); System.out.println("Use a fully qualified class name such as java.lang.Object"); System.out.println("or a filename such as .../path/to/MyClass.class"); return false; } return true; } /** * Reads the annotations from the class file <code> fileName </code> * and inserts them into <code> scene </code>. * <code> fileName </code> should be a file name that can be resolved from * the current working directory, which means it should end in ".class" * for standard Java class files. * * @param scene the scene into which the annotations should be inserted * @param fileName the file name of the class the annotations should be * read from * @throws IOException if there is a problem reading from * <code> fileName </code> */ public static void read(AScene scene, String fileName) throws IOException { read(scene, new FileInputStream(fileName)); } /** * Reads the annotations from the class <code> className </code>, * assumed to be in your classpath, * and inserts them into <code> scene </code>. * * @param scene the scene into which the annotations should be inserted * @param className the name of the class to read in * @throws IOException if there is a problem reading <code> className </code> */ public static void readFromClass(AScene scene, String className) throws IOException { read(scene, new ClassReader(className)); } /** * Reads the annotations from the class file <code> fileName </code> * and inserts them into <code> scene </code>. * * @param scene the scene into which the annotations should be inserted * @param in an input stream containing the class that the annotations * should be read from * @throws IOException if there is a problem reading from <code> in </code> */ public static void read(AScene scene, InputStream in) throws IOException { read(scene, new ClassReader(in)); } public static void read(AScene scene, ClassReader cr) { ClassAnnotationSceneReader ca = new ClassAnnotationSceneReader(cr, scene, ignore_bridge_methods); cr.accept(ca, true); } }