| /* |
| * 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<String> value; |
| |
| Element(String name) { |
| this.name = name; |
| this.value = new ArrayList<String>(); |
| } |
| |
| 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<Void, Element> { |
| |
| 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); |
| |
| ClassPath.setJDKHome(jdkhome); |
| ClassPath.parseAllClassFiles(); |
| |
| 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<String, Set<Klass.Method>> 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 <options>"); |
| System.out.println("Options: "); |
| System.out.println("\t-jdkhome <JDK home> where all jars will be parsed"); |
| System.out.println("\t-depconfig <output file for annotated dependencies>"); |
| System.out.println("\t-optional <output file for optional dependencies>"); |
| System.exit(-1); |
| } |
| } |