/* * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.classanalyzer; import com.sun.tools.classfile.*; import com.sun.tools.classfile.Annotation; import com.sun.tools.classfile.ExtendedAnnotation; import com.sun.tools.classfile.Annotation.Annotation_element_value; import com.sun.tools.classfile.Annotation.Array_element_value; import com.sun.tools.classfile.Annotation.Class_element_value; import com.sun.tools.classfile.Annotation.Enum_element_value; import com.sun.tools.classfile.Annotation.Primitive_element_value; import com.sun.tools.classfile.ConstantPoolException; import com.sun.tools.classfile.Descriptor; import com.sun.tools.classfile.Descriptor.InvalidDescriptor; import java.util.ArrayList; import java.util.List; import com.sun.classanalyzer.AnnotatedDependency.*; import java.io.File; import java.io.PrintWriter; import java.util.Map; import java.util.Set; /** * * @author Mandy Chung */ public class AnnotationParser { static boolean parseAnnotation = false; static void setParseAnnotation(boolean newValue) { parseAnnotation = newValue; } private final ClassFileParser cfparser; public AnnotationParser(ClassFileParser cfparser) { this.cfparser = cfparser; } private AnnotatedDependency addAnnotation(Annotation annot, Klass.Method method) { String type = getType(annot.type_index); AnnotatedDependency dep = AnnotatedDependency.newAnnotatedDependency(type, cfparser.this_klass); if (dep != null) { for (int i = 0; i < annot.num_element_value_pairs; i++) { Element element = getElement(annot.element_value_pairs[i]); dep.addElement(element.name, element.value); } dep.setMethod(method); } return dep; } private AnnotatedDependency addAnnotation(ExtendedAnnotation annot, Klass.Method method) { return addAnnotation(annot.annotation, method); } class Element { String name; List value; Element(String name) { this.name = name; this.value = new ArrayList(); } void add(String v) { value.add(v); } } Element getElement(Annotation.element_value_pair pair) { Element element = new Element(getName(pair.element_name_index)); evp.parse(pair.value, element); return element; } private String getType(int index) { try { Descriptor d = new Descriptor(index); return d.getFieldType(cfparser.classfile.constant_pool); } catch (ConstantPoolException ignore) { } catch (InvalidDescriptor ignore) { } return "Unknown"; } private String getName(int index) { return cfparser.constantPoolParser.stringValue(index); } element_value_Parser evp = new element_value_Parser(); class element_value_Parser implements Annotation.element_value.Visitor { public Void parse(Annotation.element_value value, Element element) { value.accept(this, element); return null; } public Void visitPrimitive(Primitive_element_value ev, Element element) { String value = getName(ev.const_value_index); element.add(value); return null; } public Void visitEnum(Enum_element_value ev, Element element) { String value = getName(ev.type_name_index) + "." + getName(ev.const_name_index); element.add(value); return null; } public Void visitClass(Class_element_value ev, Element element) { String value = getName(ev.class_info_index) + ".class"; element.add(value); return null; } public Void visitAnnotation(Annotation_element_value ev, Element element) { // AnnotationParser.this.addAnnotation(ev.annotation_value); throw new UnsupportedOperationException("Not supported: " + ev); } public Void visitArray(Array_element_value ev, Element element) { for (int i = 0; i < ev.num_values; i++) { parse(ev.values[i], element); } return null; } } void parseAttributes(Attributes attributes, Klass.Method method) { if (!parseAnnotation) { return; } visitRuntimeAnnotations((RuntimeVisibleAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleAnnotations), method); visitRuntimeAnnotations((RuntimeInvisibleAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleAnnotations), method); visitRuntimeTypeAnnotations((RuntimeVisibleTypeAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleTypeAnnotations), method); visitRuntimeTypeAnnotations((RuntimeInvisibleTypeAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleTypeAnnotations), method); visitRuntimeParameterAnnotations((RuntimeVisibleParameterAnnotations_attribute) attributes.get(Attribute.RuntimeVisibleParameterAnnotations), method); visitRuntimeParameterAnnotations((RuntimeInvisibleParameterAnnotations_attribute) attributes.get(Attribute.RuntimeInvisibleParameterAnnotations), method); } public void visitRuntimeAnnotations(RuntimeAnnotations_attribute attr, Klass.Method method) { if (attr == null) { return; } for (int i = 0; i < attr.annotations.length; i++) { addAnnotation(attr.annotations[i], method); } } public void visitRuntimeTypeAnnotations(RuntimeTypeAnnotations_attribute attr, Klass.Method method) { if (attr == null) { return; } for (int i = 0; i < attr.annotations.length; i++) { addAnnotation(attr.annotations[i], method); } } public void visitRuntimeParameterAnnotations(RuntimeParameterAnnotations_attribute attr, Klass.Method method) { if (attr == null) { return; } for (int param = 0; param < attr.parameter_annotations.length; param++) { for (int i = 0; i < attr.parameter_annotations[param].length; i++) { addAnnotation(attr.parameter_annotations[param][i], method); } } } void parseAttributes(Attributes attributes) { parseAttributes(attributes, null); } public static void main(String[] args) throws Exception { String jdkhome = null; String output = "."; // process arguments int i = 0; while (i < args.length) { String arg = args[i++]; if (arg.equals("-jdkhome")) { if (i < args.length) { jdkhome = args[i++]; } else { usage(); } } else if (arg.equals("-output")) { output = args[i++]; } else { usage(); } } if (jdkhome == null) { usage(); } // parse annotation and code attribute to find all references // to Class.forName etc CodeAttributeParser.setParseCodeAttribute(true); AnnotationParser.setParseAnnotation(true); ClassPaths cpaths = ClassPaths.newJDKClassPaths(jdkhome); cpaths.parse(); PrintWriter writer = new PrintWriter(new File(output, "jdk7.depconfig")); try { for (Klass k : Klass.getAllClasses()) { for (AnnotatedDependency dep : k.getAnnotatedDeps()) { if (dep.isEmpty()) { continue; } writer.format("# %s \n", dep.method == null ? dep.from : dep.method); writer.format("%s\n\n", dep); } } } finally { writer.close(); } writer = new PrintWriter(new File(output, "optional.depconfig")); try { AnnotatedDependency prev = null; for (AnnotatedDependency dep : AnnotatedDependency.optionalDependencies) { if (prev != null && !dep.equals(prev)) { writer.format("%s\n\n", prev); } writer.format("# %s \n", dep.method == null ? dep.from : dep.method); prev = dep; } if (prev != null) { writer.format("%s\n\n", prev); } } finally { writer.close(); } writer = new PrintWriter(new File(output, "runtime.references")); try { for (Map.Entry> entry : CodeAttributeParser.runtimeReferences.entrySet()) { writer.format("References to %s\n", entry.getKey()); Klass prev = null; for (Klass.Method m : entry.getValue()) { if (prev == null || prev != m.getKlass()) { writer.format(" %-50s # %s\n", m.getKlass(), m); } else if (prev == m.getKlass()) { writer.format(" %-50s # %s\n", "", m); } prev = m.getKlass(); } } } finally { writer.close(); } } private static void usage() { System.out.println("Usage: AnnotationParser "); System.out.println("Options: "); System.out.println("\t-jdkhome where all jars will be parsed"); System.out.println("\t-depconfig "); System.out.println("\t-optional "); System.exit(-1); } }