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.Attribute; 034import io.ebean.enhance.asm.ClassVisitor; 035import io.ebean.enhance.asm.FieldVisitor; 036import io.ebean.enhance.asm.MethodVisitor; 037import io.ebean.enhance.asm.ModuleVisitor; 038import io.ebean.enhance.asm.Opcodes; 039import io.ebean.enhance.asm.Type; 040import io.ebean.enhance.asm.TypePath; 041 042import java.util.ArrayList; 043import java.util.Arrays; 044import java.util.List; 045 046/** 047 * A node that represents a class. 048 * 049 * @author Eric Bruneton 050 */ 051public class ClassNode extends ClassVisitor { 052 053 /** 054 * The class version. 055 */ 056 public int version; 057 058 /** 059 * The class's access flags (see {@link Opcodes}). This 060 * field also indicates if the class is deprecated. 061 */ 062 public int access; 063 064 /** 065 * The internal name of the class (see 066 * {@link Type#getInternalName() getInternalName}). 067 */ 068 public String name; 069 070 /** 071 * The signature of the class. May be <tt>null</tt>. 072 */ 073 public String signature; 074 075 /** 076 * The internal of name of the super class (see 077 * {@link Type#getInternalName() getInternalName}). For 078 * interfaces, the super class is {@link Object}. May be <tt>null</tt>, but 079 * only for the {@link Object} class. 080 */ 081 public String superName; 082 083 /** 084 * The internal names of the class's interfaces (see 085 * {@link Type#getInternalName() getInternalName}). This 086 * list is a list of {@link String} objects. 087 */ 088 public List<String> interfaces; 089 090 /** 091 * The name of the source file from which this class was compiled. May be 092 * <tt>null</tt>. 093 */ 094 public String sourceFile; 095 096 /** 097 * Debug information to compute the correspondence between source and 098 * compiled elements of the class. May be <tt>null</tt>. 099 */ 100 public String sourceDebug; 101 102 /** 103 * Module information. May be <tt>null</tt>. 104 */ 105 public ModuleNode module; 106 107 /** 108 * The internal name of the enclosing class of the class. May be 109 * <tt>null</tt>. 110 */ 111 public String outerClass; 112 113 /** 114 * The name of the method that contains the class, or <tt>null</tt> if the 115 * class is not enclosed in a method. 116 */ 117 public String outerMethod; 118 119 /** 120 * The descriptor of the method that contains the class, or <tt>null</tt> if 121 * the class is not enclosed in a method. 122 */ 123 public String outerMethodDesc; 124 125 /** 126 * The runtime visible annotations of this class. This list is a list of 127 * {@link AnnotationNode} objects. May be <tt>null</tt>. 128 * 129 * @associates org.objectweb.asm.tree.AnnotationNode 130 * @label visible 131 */ 132 public List<AnnotationNode> visibleAnnotations; 133 134 /** 135 * The runtime invisible annotations of this class. This list is a list of 136 * {@link AnnotationNode} objects. May be <tt>null</tt>. 137 * 138 * @associates org.objectweb.asm.tree.AnnotationNode 139 * @label invisible 140 */ 141 public List<AnnotationNode> invisibleAnnotations; 142 143 /** 144 * The runtime visible type annotations of this class. This list is a list 145 * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>. 146 * 147 * @associates org.objectweb.asm.tree.TypeAnnotationNode 148 * @label visible 149 */ 150 public List<TypeAnnotationNode> visibleTypeAnnotations; 151 152 /** 153 * The runtime invisible type annotations of this class. This list is a list 154 * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>. 155 * 156 * @associates org.objectweb.asm.tree.TypeAnnotationNode 157 * @label invisible 158 */ 159 public List<TypeAnnotationNode> invisibleTypeAnnotations; 160 161 /** 162 * The non standard attributes of this class. This list is a list of 163 * {@link Attribute} objects. May be <tt>null</tt>. 164 * 165 * @associates org.objectweb.asm.Attribute 166 */ 167 public List<Attribute> attrs; 168 169 /** 170 * Informations about the inner classes of this class. This list is a list 171 * of {@link InnerClassNode} objects. 172 * 173 * @associates org.objectweb.asm.tree.InnerClassNode 174 */ 175 public List<InnerClassNode> innerClasses; 176 177 /** 178 * The fields of this class. This list is a list of {@link FieldNode} 179 * objects. 180 * 181 * @associates org.objectweb.asm.tree.FieldNode 182 */ 183 public List<FieldNode> fields; 184 185 /** 186 * The methods of this class. This list is a list of {@link MethodNode} 187 * objects. 188 * 189 * @associates org.objectweb.asm.tree.MethodNode 190 */ 191 public List<MethodNode> methods; 192 193 /** 194 * Constructs a new {@link ClassNode}. <i>Subclasses must not use this 195 * constructor</i>. Instead, they must use the {@link #ClassNode(int)} 196 * version. 197 * 198 * @throws IllegalStateException 199 * If a subclass calls this constructor. 200 */ 201 public ClassNode() { 202 this(Opcodes.ASM6); 203 if (getClass() != ClassNode.class) { 204 throw new IllegalStateException(); 205 } 206 } 207 208 /** 209 * Constructs a new {@link ClassNode}. 210 * 211 * @param api 212 * the ASM API version implemented by this visitor. Must be one 213 * of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. 214 */ 215 public ClassNode(final int api) { 216 super(api); 217 this.interfaces = new ArrayList<String>(); 218 this.innerClasses = new ArrayList<InnerClassNode>(); 219 this.fields = new ArrayList<FieldNode>(); 220 this.methods = new ArrayList<MethodNode>(); 221 } 222 223 // ------------------------------------------------------------------------ 224 // Implementation of the ClassVisitor abstract class 225 // ------------------------------------------------------------------------ 226 227 @Override 228 public void visit(final int version, final int access, final String name, 229 final String signature, final String superName, 230 final String[] interfaces) { 231 this.version = version; 232 this.access = access; 233 this.name = name; 234 this.signature = signature; 235 this.superName = superName; 236 if (interfaces != null) { 237 this.interfaces.addAll(Arrays.asList(interfaces)); 238 } 239 } 240 241 @Override 242 public void visitSource(final String file, final String debug) { 243 sourceFile = file; 244 sourceDebug = debug; 245 } 246 247 @Override 248 public ModuleVisitor visitModule(final String name, final int access, 249 final String version) { 250 return module = new ModuleNode(name, access, version); 251 } 252 253 @Override 254 public void visitOuterClass(final String owner, final String name, 255 final String desc) { 256 outerClass = owner; 257 outerMethod = name; 258 outerMethodDesc = desc; 259 } 260 261 @Override 262 public AnnotationVisitor visitAnnotation(final String desc, 263 final boolean visible) { 264 AnnotationNode an = new AnnotationNode(desc); 265 if (visible) { 266 if (visibleAnnotations == null) { 267 visibleAnnotations = new ArrayList<AnnotationNode>(1); 268 } 269 visibleAnnotations.add(an); 270 } else { 271 if (invisibleAnnotations == null) { 272 invisibleAnnotations = new ArrayList<AnnotationNode>(1); 273 } 274 invisibleAnnotations.add(an); 275 } 276 return an; 277 } 278 279 @Override 280 public AnnotationVisitor visitTypeAnnotation(int typeRef, 281 TypePath typePath, String desc, boolean visible) { 282 TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc); 283 if (visible) { 284 if (visibleTypeAnnotations == null) { 285 visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1); 286 } 287 visibleTypeAnnotations.add(an); 288 } else { 289 if (invisibleTypeAnnotations == null) { 290 invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1); 291 } 292 invisibleTypeAnnotations.add(an); 293 } 294 return an; 295 } 296 297 @Override 298 public void visitAttribute(final Attribute attr) { 299 if (attrs == null) { 300 attrs = new ArrayList<Attribute>(1); 301 } 302 attrs.add(attr); 303 } 304 305 @Override 306 public void visitInnerClass(final String name, final String outerName, 307 final String innerName, final int access) { 308 InnerClassNode icn = new InnerClassNode(name, outerName, innerName, 309 access); 310 innerClasses.add(icn); 311 } 312 313 @Override 314 public FieldVisitor visitField(final int access, final String name, 315 final String desc, final String signature, final Object value) { 316 FieldNode fn = new FieldNode(access, name, desc, signature, value); 317 fields.add(fn); 318 return fn; 319 } 320 321 @Override 322 public MethodVisitor visitMethod(final int access, final String name, 323 final String desc, final String signature, final String[] exceptions) { 324 MethodNode mn = new MethodNode(access, name, desc, signature, 325 exceptions); 326 methods.add(mn); 327 return mn; 328 } 329 330 @Override 331 public void visitEnd() { 332 } 333 334 // ------------------------------------------------------------------------ 335 // Accept method 336 // ------------------------------------------------------------------------ 337 338 /** 339 * Checks that this class node is compatible with the given ASM API version. 340 * This methods checks that this node, and all its nodes recursively, do not 341 * contain elements that were introduced in more recent versions of the ASM 342 * API than the given version. 343 * 344 * @param api 345 * an ASM API version. Must be one of {@link Opcodes#ASM4}, 346 * {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. 347 */ 348 public void check(final int api) { 349 if (api < Opcodes.ASM6) { 350 if (module != null) { 351 throw new RuntimeException(); 352 } 353 } 354 if (api < Opcodes.ASM5) { 355 if (visibleTypeAnnotations != null 356 && visibleTypeAnnotations.size() > 0) { 357 throw new RuntimeException(); 358 } 359 if (invisibleTypeAnnotations != null 360 && invisibleTypeAnnotations.size() > 0) { 361 throw new RuntimeException(); 362 } 363 } 364 // checks attributes 365 int i, n; 366 n = visibleAnnotations == null ? 0 : visibleAnnotations.size(); 367 for (i = 0; i < n; ++i) { 368 visibleAnnotations.get(i).check(api); 369 } 370 n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size(); 371 for (i = 0; i < n; ++i) { 372 invisibleAnnotations.get(i).check(api); 373 } 374 n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size(); 375 for (i = 0; i < n; ++i) { 376 visibleTypeAnnotations.get(i).check(api); 377 } 378 n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations 379 .size(); 380 for (i = 0; i < n; ++i) { 381 invisibleTypeAnnotations.get(i).check(api); 382 } 383 for (FieldNode f : fields) { 384 f.check(api); 385 } 386 for (MethodNode m : methods) { 387 m.check(api); 388 } 389 } 390 391 /** 392 * Makes the given class visitor visit this class. 393 * 394 * @param cv 395 * a class visitor. 396 */ 397 public void accept(final ClassVisitor cv) { 398 // visits header 399 String[] interfaces = new String[this.interfaces.size()]; 400 this.interfaces.toArray(interfaces); 401 cv.visit(version, access, name, signature, superName, interfaces); 402 // visits source 403 if (sourceFile != null || sourceDebug != null) { 404 cv.visitSource(sourceFile, sourceDebug); 405 } 406 // visits module 407 if (module != null) { 408 module.accept(cv); 409 } 410 // visits outer class 411 if (outerClass != null) { 412 cv.visitOuterClass(outerClass, outerMethod, outerMethodDesc); 413 } 414 // visits attributes 415 int i, n; 416 n = visibleAnnotations == null ? 0 : visibleAnnotations.size(); 417 for (i = 0; i < n; ++i) { 418 AnnotationNode an = visibleAnnotations.get(i); 419 an.accept(cv.visitAnnotation(an.desc, true)); 420 } 421 n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size(); 422 for (i = 0; i < n; ++i) { 423 AnnotationNode an = invisibleAnnotations.get(i); 424 an.accept(cv.visitAnnotation(an.desc, false)); 425 } 426 n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size(); 427 for (i = 0; i < n; ++i) { 428 TypeAnnotationNode an = visibleTypeAnnotations.get(i); 429 an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc, 430 true)); 431 } 432 n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations 433 .size(); 434 for (i = 0; i < n; ++i) { 435 TypeAnnotationNode an = invisibleTypeAnnotations.get(i); 436 an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc, 437 false)); 438 } 439 n = attrs == null ? 0 : attrs.size(); 440 for (i = 0; i < n; ++i) { 441 cv.visitAttribute(attrs.get(i)); 442 } 443 // visits inner classes 444 for (i = 0; i < innerClasses.size(); ++i) { 445 innerClasses.get(i).accept(cv); 446 } 447 // visits fields 448 for (i = 0; i < fields.size(); ++i) { 449 fields.get(i).accept(cv); 450 } 451 // visits methods 452 for (i = 0; i < methods.size(); ++i) { 453 methods.get(i).accept(cv); 454 } 455 // visits end 456 cv.visitEnd(); 457 } 458}