1 // ASM: a very small and fast Java bytecode manipulation framework 2 // Copyright (c) 2000-2011 INRIA, France Telecom 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions 7 // are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. Neither the name of the copyright holders nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 // THE POSSIBILITY OF SUCH DAMAGE. 28 package org.objectweb.asm.tree; 29 30 import java.util.ArrayList; 31 import java.util.List; 32 import org.objectweb.asm.AnnotationVisitor; 33 import org.objectweb.asm.Opcodes; 34 35 /** 36 * A node that represents an annotation. 37 * 38 * @author Eric Bruneton 39 */ 40 public class AnnotationNode extends AnnotationVisitor { 41 42 /** The class descriptor of the annotation class. */ 43 public String desc; 44 45 /** 46 * The name value pairs of this annotation. Each name value pair is stored as two consecutive 47 * elements in the list. The name is a {@link String}, and the value may be a {@link Byte}, {@link 48 * Boolean}, {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Float}, 49 * {@link Double}, {@link String} or {@link org.objectweb.asm.Type}, or a two elements String 50 * array (for enumeration values), an {@link AnnotationNode}, or a {@link List} of values of one 51 * of the preceding types. The list may be {@literal null} if there is no name value pair. 52 */ 53 public List<Object> values; 54 55 /** 56 * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this constructor</i>. 57 * Instead, they must use the {@link #AnnotationNode(int, String)} version. 58 * 59 * @param descriptor the class descriptor of the annotation class. 60 * @throws IllegalStateException If a subclass calls this constructor. 61 */ AnnotationNode(final String descriptor)62 public AnnotationNode(final String descriptor) { 63 this(/* latest api = */ Opcodes.ASM9, descriptor); 64 if (getClass() != AnnotationNode.class) { 65 throw new IllegalStateException(); 66 } 67 } 68 69 /** 70 * Constructs a new {@link AnnotationNode}. 71 * 72 * @param api the ASM API version implemented by this visitor. Must be one of the {@code 73 * ASM}<i>x</i> values in {@link Opcodes}. 74 * @param descriptor the class descriptor of the annotation class. 75 */ AnnotationNode(final int api, final String descriptor)76 public AnnotationNode(final int api, final String descriptor) { 77 super(api); 78 this.desc = descriptor; 79 } 80 81 /** 82 * Constructs a new {@link AnnotationNode} to visit an array value. 83 * 84 * @param values where the visited values must be stored. 85 */ AnnotationNode(final List<Object> values)86 AnnotationNode(final List<Object> values) { 87 super(/* latest api = */ Opcodes.ASM9); 88 this.values = values; 89 } 90 91 // ------------------------------------------------------------------------ 92 // Implementation of the AnnotationVisitor abstract class 93 // ------------------------------------------------------------------------ 94 95 @Override visit(final String name, final Object value)96 public void visit(final String name, final Object value) { 97 if (values == null) { 98 values = new ArrayList<>(this.desc != null ? 2 : 1); 99 } 100 if (this.desc != null) { 101 values.add(name); 102 } 103 if (value instanceof byte[]) { 104 values.add(Util.asArrayList((byte[]) value)); 105 } else if (value instanceof boolean[]) { 106 values.add(Util.asArrayList((boolean[]) value)); 107 } else if (value instanceof short[]) { 108 values.add(Util.asArrayList((short[]) value)); 109 } else if (value instanceof char[]) { 110 values.add(Util.asArrayList((char[]) value)); 111 } else if (value instanceof int[]) { 112 values.add(Util.asArrayList((int[]) value)); 113 } else if (value instanceof long[]) { 114 values.add(Util.asArrayList((long[]) value)); 115 } else if (value instanceof float[]) { 116 values.add(Util.asArrayList((float[]) value)); 117 } else if (value instanceof double[]) { 118 values.add(Util.asArrayList((double[]) value)); 119 } else { 120 values.add(value); 121 } 122 } 123 124 @Override visitEnum(final String name, final String descriptor, final String value)125 public void visitEnum(final String name, final String descriptor, final String value) { 126 if (values == null) { 127 values = new ArrayList<>(this.desc != null ? 2 : 1); 128 } 129 if (this.desc != null) { 130 values.add(name); 131 } 132 values.add(new String[] {descriptor, value}); 133 } 134 135 @Override visitAnnotation(final String name, final String descriptor)136 public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { 137 if (values == null) { 138 values = new ArrayList<>(this.desc != null ? 2 : 1); 139 } 140 if (this.desc != null) { 141 values.add(name); 142 } 143 AnnotationNode annotation = new AnnotationNode(descriptor); 144 values.add(annotation); 145 return annotation; 146 } 147 148 @Override visitArray(final String name)149 public AnnotationVisitor visitArray(final String name) { 150 if (values == null) { 151 values = new ArrayList<>(this.desc != null ? 2 : 1); 152 } 153 if (this.desc != null) { 154 values.add(name); 155 } 156 List<Object> array = new ArrayList<>(); 157 values.add(array); 158 return new AnnotationNode(array); 159 } 160 161 @Override visitEnd()162 public void visitEnd() { 163 // Nothing to do. 164 } 165 166 // ------------------------------------------------------------------------ 167 // Accept methods 168 // ------------------------------------------------------------------------ 169 170 /** 171 * Checks that this annotation node is compatible with the given ASM API version. This method 172 * checks that this node, and all its children recursively, do not contain elements that were 173 * introduced in more recent versions of the ASM API than the given version. 174 * 175 * @param api an ASM API version. Must be one of the {@code ASM}<i>x</i> values in {@link 176 * Opcodes}. 177 */ check(final int api)178 public void check(final int api) { 179 // nothing to do 180 } 181 182 /** 183 * Makes the given visitor visit this annotation. 184 * 185 * @param annotationVisitor an annotation visitor. Maybe {@literal null}. 186 */ accept(final AnnotationVisitor annotationVisitor)187 public void accept(final AnnotationVisitor annotationVisitor) { 188 if (annotationVisitor != null) { 189 if (values != null) { 190 for (int i = 0, n = values.size(); i < n; i += 2) { 191 String name = (String) values.get(i); 192 Object value = values.get(i + 1); 193 accept(annotationVisitor, name, value); 194 } 195 } 196 annotationVisitor.visitEnd(); 197 } 198 } 199 200 /** 201 * Makes the given visitor visit a given annotation value. 202 * 203 * @param annotationVisitor an annotation visitor. Maybe {@literal null}. 204 * @param name the value name. 205 * @param value the actual value. 206 */ accept( final AnnotationVisitor annotationVisitor, final String name, final Object value)207 static void accept( 208 final AnnotationVisitor annotationVisitor, final String name, final Object value) { 209 if (annotationVisitor != null) { 210 if (value instanceof String[]) { 211 String[] typeValue = (String[]) value; 212 annotationVisitor.visitEnum(name, typeValue[0], typeValue[1]); 213 } else if (value instanceof AnnotationNode) { 214 AnnotationNode annotationValue = (AnnotationNode) value; 215 annotationValue.accept(annotationVisitor.visitAnnotation(name, annotationValue.desc)); 216 } else if (value instanceof List) { 217 AnnotationVisitor arrayAnnotationVisitor = annotationVisitor.visitArray(name); 218 if (arrayAnnotationVisitor != null) { 219 List<?> arrayValue = (List<?>) value; 220 for (int i = 0, n = arrayValue.size(); i < n; ++i) { 221 accept(arrayAnnotationVisitor, null, arrayValue.get(i)); 222 } 223 arrayAnnotationVisitor.visitEnd(); 224 } 225 } else { 226 annotationVisitor.visit(name, value); 227 } 228 } 229 } 230 } 231