001/*** 002 * ASM: a very small and fast Java bytecode manipulation framework 003 * Copyright (c) 2000-2011 INRIA, France Telecom 004 * All rights reserved. 005 * 006 * Redistribution and use in source and binary forms, with or without 007 * modification, are permitted provided that the following conditions 008 * are met: 009 * 1. Redistributions of source code must retain the above copyright 010 * notice, this list of conditions and the following disclaimer. 011 * 2. Redistributions in binary form must reproduce the above copyright 012 * notice, this list of conditions and the following disclaimer in the 013 * documentation and/or other materials provided with the distribution. 014 * 3. Neither the name of the copyright holders nor the names of its 015 * contributors may be used to endorse or promote products derived from 016 * this software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 028 * THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package io.ebean.enhance.asm.tree; 031 032import io.ebean.enhance.asm.AnnotationVisitor; 033import io.ebean.enhance.asm.Opcodes; 034import io.ebean.enhance.asm.Type; 035 036import java.util.ArrayList; 037import java.util.List; 038 039/** 040 * A node that represents an annotation. 041 * 042 * @author Eric Bruneton 043 */ 044public class AnnotationNode extends AnnotationVisitor { 045 046 /** 047 * The class descriptor of the annotation class. 048 */ 049 public String desc; 050 051 /** 052 * The name value pairs of this annotation. Each name value pair is stored 053 * as two consecutive elements in the list. The name is a {@link String}, 054 * and the value may be a {@link Byte}, {@link Boolean}, {@link Character}, 055 * {@link Short}, {@link Integer}, {@link Long}, {@link Float}, 056 * {@link Double}, {@link String} or {@link Type}, or a 057 * two elements String array (for enumeration values), an 058 * {@link AnnotationNode}, or a {@link List} of values of one of the 059 * preceding types. The list may be <tt>null</tt> if there is no name value 060 * pair. 061 */ 062 public List<Object> values; 063 064 /** 065 * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this 066 * constructor</i>. Instead, they must use the 067 * {@link #AnnotationNode(int, String)} version. 068 * 069 * @param desc 070 * the class descriptor of the annotation class. 071 * @throws IllegalStateException 072 * If a subclass calls this constructor. 073 */ 074 public AnnotationNode(final String desc) { 075 this(Opcodes.ASM6, desc); 076 if (getClass() != AnnotationNode.class) { 077 throw new IllegalStateException(); 078 } 079 } 080 081 /** 082 * Constructs a new {@link AnnotationNode}. 083 * 084 * @param api 085 * the ASM API version implemented by this visitor. Must be one 086 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. 087 * @param desc 088 * the class descriptor of the annotation class. 089 */ 090 public AnnotationNode(final int api, final String desc) { 091 super(api); 092 this.desc = desc; 093 } 094 095 /** 096 * Constructs a new {@link AnnotationNode} to visit an array value. 097 * 098 * @param values 099 * where the visited values must be stored. 100 */ 101 AnnotationNode(final List<Object> values) { 102 super(Opcodes.ASM6); 103 this.values = values; 104 } 105 106 // ------------------------------------------------------------------------ 107 // Implementation of the AnnotationVisitor abstract class 108 // ------------------------------------------------------------------------ 109 110 @Override 111 public void visit(final String name, final Object value) { 112 if (values == null) { 113 values = new ArrayList<Object>(this.desc != null ? 2 : 1); 114 } 115 if (this.desc != null) { 116 values.add(name); 117 } 118 if (value instanceof byte[]) { 119 byte[] v = (byte[]) value; 120 ArrayList<Byte> l = new ArrayList<Byte>(v.length); 121 for (byte b : v) { 122 l.add(b); 123 } 124 values.add(l); 125 } else if (value instanceof boolean[]) { 126 boolean[] v = (boolean[]) value; 127 ArrayList<Boolean> l = new ArrayList<Boolean>(v.length); 128 for (boolean b : v) { 129 l.add(b); 130 } 131 values.add(l); 132 } else if (value instanceof short[]) { 133 short[] v = (short[]) value; 134 ArrayList<Short> l = new ArrayList<Short>(v.length); 135 for (short s : v) { 136 l.add(s); 137 } 138 values.add(l); 139 } else if (value instanceof char[]) { 140 char[] v = (char[]) value; 141 ArrayList<Character> l = new ArrayList<Character>(v.length); 142 for (char c : v) { 143 l.add(c); 144 } 145 values.add(l); 146 } else if (value instanceof int[]) { 147 int[] v = (int[]) value; 148 ArrayList<Integer> l = new ArrayList<Integer>(v.length); 149 for (int i : v) { 150 l.add(i); 151 } 152 values.add(l); 153 } else if (value instanceof long[]) { 154 long[] v = (long[]) value; 155 ArrayList<Long> l = new ArrayList<Long>(v.length); 156 for (long lng : v) { 157 l.add(lng); 158 } 159 values.add(l); 160 } else if (value instanceof float[]) { 161 float[] v = (float[]) value; 162 ArrayList<Float> l = new ArrayList<Float>(v.length); 163 for (float f : v) { 164 l.add(f); 165 } 166 values.add(l); 167 } else if (value instanceof double[]) { 168 double[] v = (double[]) value; 169 ArrayList<Double> l = new ArrayList<Double>(v.length); 170 for (double d : v) { 171 l.add(d); 172 } 173 values.add(l); 174 } else { 175 values.add(value); 176 } 177 } 178 179 @Override 180 public void visitEnum(final String name, final String desc, 181 final String value) { 182 if (values == null) { 183 values = new ArrayList<Object>(this.desc != null ? 2 : 1); 184 } 185 if (this.desc != null) { 186 values.add(name); 187 } 188 values.add(new String[] { desc, value }); 189 } 190 191 @Override 192 public AnnotationVisitor visitAnnotation(final String name, 193 final String desc) { 194 if (values == null) { 195 values = new ArrayList<Object>(this.desc != null ? 2 : 1); 196 } 197 if (this.desc != null) { 198 values.add(name); 199 } 200 AnnotationNode annotation = new AnnotationNode(desc); 201 values.add(annotation); 202 return annotation; 203 } 204 205 @Override 206 public AnnotationVisitor visitArray(final String name) { 207 if (values == null) { 208 values = new ArrayList<Object>(this.desc != null ? 2 : 1); 209 } 210 if (this.desc != null) { 211 values.add(name); 212 } 213 List<Object> array = new ArrayList<Object>(); 214 values.add(array); 215 return new AnnotationNode(array); 216 } 217 218 @Override 219 public void visitEnd() { 220 } 221 222 // ------------------------------------------------------------------------ 223 // Accept methods 224 // ------------------------------------------------------------------------ 225 226 /** 227 * Checks that this annotation node is compatible with the given ASM API 228 * version. This methods checks that this node, and all its nodes 229 * recursively, do not contain elements that were introduced in more recent 230 * versions of the ASM API than the given version. 231 * 232 * @param api 233 * an ASM API version. Must be one of {@link Opcodes#ASM4}, 234 * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. 235 */ 236 public void check(final int api) { 237 // nothing to do 238 } 239 240 /** 241 * Makes the given visitor visit this annotation. 242 * 243 * @param av 244 * an annotation visitor. Maybe <tt>null</tt>. 245 */ 246 public void accept(final AnnotationVisitor av) { 247 if (av != null) { 248 if (values != null) { 249 for (int i = 0; i < values.size(); i += 2) { 250 String name = (String) values.get(i); 251 Object value = values.get(i + 1); 252 accept(av, name, value); 253 } 254 } 255 av.visitEnd(); 256 } 257 } 258 259 /** 260 * Makes the given visitor visit a given annotation value. 261 * 262 * @param av 263 * an annotation visitor. Maybe <tt>null</tt>. 264 * @param name 265 * the value name. 266 * @param value 267 * the actual value. 268 */ 269 static void accept(final AnnotationVisitor av, final String name, 270 final Object value) { 271 if (av != null) { 272 if (value instanceof String[]) { 273 String[] typeconst = (String[]) value; 274 av.visitEnum(name, typeconst[0], typeconst[1]); 275 } else if (value instanceof AnnotationNode) { 276 AnnotationNode an = (AnnotationNode) value; 277 an.accept(av.visitAnnotation(name, an.desc)); 278 } else if (value instanceof List) { 279 AnnotationVisitor v = av.visitArray(name); 280 if (v != null) { 281 List<?> array = (List<?>) value; 282 for (int j = 0; j < array.size(); ++j) { 283 accept(v, null, array.get(j)); 284 } 285 v.visitEnd(); 286 } 287 } else { 288 av.visit(name, value); 289 } 290 } 291 } 292}