/* * Copyright (c) 2007, 2013, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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.tools.javap; import com.sun.tools.classfile.Annotation; import com.sun.tools.classfile.TypeAnnotation; 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.ConstantPool; import com.sun.tools.classfile.ConstantPoolException; import com.sun.tools.classfile.Descriptor; import com.sun.tools.classfile.Descriptor.InvalidDescriptor; /** * A writer for writing annotations as text. * * <p><b>This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice.</b> */ public class AnnotationWriter extends BasicWriter { static AnnotationWriter instance(Context context) { AnnotationWriter instance = context.get(AnnotationWriter.class); if (instance == null) instance = new AnnotationWriter(context); return instance; } protected AnnotationWriter(Context context) { super(context); classWriter = ClassWriter.instance(context); constantWriter = ConstantWriter.instance(context); } public void write(Annotation annot) { write(annot, false); } public void write(Annotation annot, boolean resolveIndices) { writeDescriptor(annot.type_index, resolveIndices); boolean showParens = annot.num_element_value_pairs > 0 || !resolveIndices; if (showParens) print("("); for (int i = 0; i < annot.num_element_value_pairs; i++) { if (i > 0) print(","); write(annot.element_value_pairs[i], resolveIndices); } if (showParens) print(")"); } public void write(TypeAnnotation annot) { write(annot, true, false); } public void write(TypeAnnotation annot, boolean showOffsets, boolean resolveIndices) { write(annot.annotation, resolveIndices); print(": "); write(annot.position, showOffsets); } public void write(TypeAnnotation.Position pos, boolean showOffsets) { print(pos.type); switch (pos.type) { // instanceof case INSTANCEOF: // new expression case NEW: // constructor/method reference receiver case CONSTRUCTOR_REFERENCE: case METHOD_REFERENCE: if (showOffsets) { print(", offset="); print(pos.offset); } break; // local variable case LOCAL_VARIABLE: // resource variable case RESOURCE_VARIABLE: if (pos.lvarOffset == null) { print(", lvarOffset is Null!"); break; } print(", {"); for (int i = 0; i < pos.lvarOffset.length; ++i) { if (i != 0) print("; "); if (showOffsets) { print("start_pc="); print(pos.lvarOffset[i]); } print(", length="); print(pos.lvarLength[i]); print(", index="); print(pos.lvarIndex[i]); } print("}"); break; // exception parameter case EXCEPTION_PARAMETER: print(", exception_index="); print(pos.exception_index); break; // method receiver case METHOD_RECEIVER: // Do nothing break; // type parameter case CLASS_TYPE_PARAMETER: case METHOD_TYPE_PARAMETER: print(", param_index="); print(pos.parameter_index); break; // type parameter bound case CLASS_TYPE_PARAMETER_BOUND: case METHOD_TYPE_PARAMETER_BOUND: print(", param_index="); print(pos.parameter_index); print(", bound_index="); print(pos.bound_index); break; // class extends or implements clause case CLASS_EXTENDS: print(", type_index="); print(pos.type_index); break; // throws case THROWS: print(", type_index="); print(pos.type_index); break; // method parameter case METHOD_FORMAL_PARAMETER: print(", param_index="); print(pos.parameter_index); break; // type cast case CAST: // method/constructor/reference type argument case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: case METHOD_INVOCATION_TYPE_ARGUMENT: case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: case METHOD_REFERENCE_TYPE_ARGUMENT: if (showOffsets) { print(", offset="); print(pos.offset); } print(", type_index="); print(pos.type_index); break; // We don't need to worry about these case METHOD_RETURN: case FIELD: break; case UNKNOWN: throw new AssertionError("AnnotationWriter: UNKNOWN target type should never occur!"); default: throw new AssertionError("AnnotationWriter: Unknown target type for position: " + pos); } // Append location data for generics/arrays. if (!pos.location.isEmpty()) { print(", location="); print(pos.location); } } public void write(Annotation.element_value_pair pair) { write(pair, false); } public void write(Annotation.element_value_pair pair, boolean resolveIndices) { writeIndex(pair.element_name_index, resolveIndices); print("="); write(pair.value, resolveIndices); } public void write(Annotation.element_value value) { write(value, false); } public void write(Annotation.element_value value, boolean resolveIndices) { ev_writer.write(value, resolveIndices); } private void writeDescriptor(int index, boolean resolveIndices) { if (resolveIndices) { try { ConstantPool constant_pool = classWriter.getClassFile().constant_pool; Descriptor d = new Descriptor(index); print(d.getFieldType(constant_pool)); return; } catch (ConstantPoolException | InvalidDescriptor ignore) { } } print("#" + index); } private void writeIndex(int index, boolean resolveIndices) { if (resolveIndices) { print(constantWriter.stringValue(index)); } else print("#" + index); } element_value_Writer ev_writer = new element_value_Writer(); class element_value_Writer implements Annotation.element_value.Visitor<Void,Boolean> { public void write(Annotation.element_value value, boolean resolveIndices) { value.accept(this, resolveIndices); } public Void visitPrimitive(Primitive_element_value ev, Boolean resolveIndices) { if (resolveIndices) writeIndex(ev.const_value_index, resolveIndices); else print(((char) ev.tag) + "#" + ev.const_value_index); return null; } public Void visitEnum(Enum_element_value ev, Boolean resolveIndices) { if (resolveIndices) { writeIndex(ev.type_name_index, resolveIndices); print("."); writeIndex(ev.const_name_index, resolveIndices); } else print(((char) ev.tag) + "#" + ev.type_name_index + ".#" + ev.const_name_index); return null; } public Void visitClass(Class_element_value ev, Boolean resolveIndices) { if (resolveIndices) { writeIndex(ev.class_info_index, resolveIndices); print(".class"); } else print(((char) ev.tag) + "#" + ev.class_info_index); return null; } public Void visitAnnotation(Annotation_element_value ev, Boolean resolveIndices) { print((char) ev.tag); AnnotationWriter.this.write(ev.annotation_value, resolveIndices); return null; } public Void visitArray(Array_element_value ev, Boolean resolveIndices) { print("["); for (int i = 0; i < ev.num_values; i++) { if (i > 0) print(","); write(ev.values[i], resolveIndices); } print("]"); return null; } } private ClassWriter classWriter; private ConstantWriter constantWriter; }