1 8 9 package com.sleepycat.persist.model; 10 11 import static com.sleepycat.asm.Opcodes.ACC_ABSTRACT; 12 import static com.sleepycat.asm.Opcodes.ACC_PRIVATE; 13 import static com.sleepycat.asm.Opcodes.ACC_PUBLIC; 14 import static com.sleepycat.asm.Opcodes.ACC_STATIC; 15 import static com.sleepycat.asm.Opcodes.ACC_TRANSIENT; 16 import static com.sleepycat.asm.Opcodes.ACONST_NULL; 17 import static com.sleepycat.asm.Opcodes.ALOAD; 18 import static com.sleepycat.asm.Opcodes.ANEWARRAY; 19 import static com.sleepycat.asm.Opcodes.ARETURN; 20 import static com.sleepycat.asm.Opcodes.BIPUSH; 21 import static com.sleepycat.asm.Opcodes.CHECKCAST; 22 import static com.sleepycat.asm.Opcodes.DCMPL; 23 import static com.sleepycat.asm.Opcodes.DCONST_0; 24 import static com.sleepycat.asm.Opcodes.DUP; 25 import static com.sleepycat.asm.Opcodes.FCMPL; 26 import static com.sleepycat.asm.Opcodes.FCONST_0; 27 import static com.sleepycat.asm.Opcodes.GETFIELD; 28 import static com.sleepycat.asm.Opcodes.GOTO; 29 import static com.sleepycat.asm.Opcodes.ICONST_0; 30 import static com.sleepycat.asm.Opcodes.ICONST_1; 31 import static com.sleepycat.asm.Opcodes.ICONST_2; 32 import static com.sleepycat.asm.Opcodes.ICONST_3; 33 import static com.sleepycat.asm.Opcodes.ICONST_4; 34 import static com.sleepycat.asm.Opcodes.ICONST_5; 35 import static com.sleepycat.asm.Opcodes.IFEQ; 36 import static com.sleepycat.asm.Opcodes.IFGT; 37 import static com.sleepycat.asm.Opcodes.IFLE; 38 import static com.sleepycat.asm.Opcodes.IFNE; 39 import static com.sleepycat.asm.Opcodes.IFNONNULL; 40 import static com.sleepycat.asm.Opcodes.IF_ICMPNE; 41 import static com.sleepycat.asm.Opcodes.ILOAD; 42 import static com.sleepycat.asm.Opcodes.INVOKEINTERFACE; 43 import static com.sleepycat.asm.Opcodes.INVOKESPECIAL; 44 import static com.sleepycat.asm.Opcodes.INVOKESTATIC; 45 import static com.sleepycat.asm.Opcodes.INVOKEVIRTUAL; 46 import static com.sleepycat.asm.Opcodes.IRETURN; 47 import static com.sleepycat.asm.Opcodes.ISUB; 48 import static com.sleepycat.asm.Opcodes.LCMP; 49 import static com.sleepycat.asm.Opcodes.LCONST_0; 50 import static com.sleepycat.asm.Opcodes.NEW; 51 import static com.sleepycat.asm.Opcodes.POP; 52 import static com.sleepycat.asm.Opcodes.PUTFIELD; 53 import static com.sleepycat.asm.Opcodes.RETURN; 54 55 import java.math.BigInteger ; 56 import java.util.ArrayList ; 57 import java.util.Collections ; 58 import java.util.Comparator ; 59 import java.util.Date ; 60 import java.util.HashMap ; 61 import java.util.List ; 62 import java.util.Map ; 63 64 import com.sleepycat.asm.AnnotationVisitor; 65 import com.sleepycat.asm.Attribute; 66 import com.sleepycat.asm.ClassAdapter; 67 import com.sleepycat.asm.ClassVisitor; 68 import com.sleepycat.asm.FieldVisitor; 69 import com.sleepycat.asm.Label; 70 import com.sleepycat.asm.MethodVisitor; 71 import com.sleepycat.asm.Type; 72 73 89 class BytecodeEnhancer extends ClassAdapter { 90 91 92 static class NotPersistentException extends RuntimeException {} 93 94 95 private static final NotPersistentException NOT_PERSISTENT = 96 new NotPersistentException(); 97 98 private static final Map <String ,Integer > PRIMITIVE_WRAPPERS = 99 new HashMap <String ,Integer >(); 100 static { 101 PRIMITIVE_WRAPPERS.put(Boolean .class.getName(), Type.BOOLEAN); 102 PRIMITIVE_WRAPPERS.put(Character .class.getName(), Type.CHAR); 103 PRIMITIVE_WRAPPERS.put(Byte .class.getName(), Type.BYTE); 104 PRIMITIVE_WRAPPERS.put(Short .class.getName(), Type.SHORT); 105 PRIMITIVE_WRAPPERS.put(Integer .class.getName(), Type.INT); 106 PRIMITIVE_WRAPPERS.put(Long .class.getName(), Type.LONG); 107 PRIMITIVE_WRAPPERS.put(Float .class.getName(), Type.FLOAT); 108 PRIMITIVE_WRAPPERS.put(Double .class.getName(), Type.DOUBLE); 109 } 110 111 private String className; 112 private String superclassName; 113 private boolean isPersistent; 114 private boolean isAbstract; 115 private boolean hasDefaultConstructor; 116 private boolean hasPersistentSuperclass; 117 private boolean isCompositeKey; 118 private FieldInfo priKeyField; 119 private List <FieldInfo> secKeyFields; 120 private List <FieldInfo> nonKeyFields; 121 private String staticBlockMethod; 122 123 BytecodeEnhancer(ClassVisitor parentVisitor) { 124 super(parentVisitor); 125 secKeyFields = new ArrayList <FieldInfo>(); 126 nonKeyFields = new ArrayList <FieldInfo>(); 127 } 128 129 @Override 130 public void visit(int version, 131 int access, 132 String name, 133 String sig, 134 String superName, 135 String [] interfaces) { 136 className = name; 137 superclassName = superName; 138 final String ENHANCED = "com/sleepycat/persist/impl/Enhanced"; 139 if (containsString(interfaces, ENHANCED)) { 140 throw abort(); 141 } 142 interfaces = appendString(interfaces, ENHANCED); 143 isAbstract = ((access & ACC_ABSTRACT) != 0); 144 hasPersistentSuperclass = 145 (superName != null && !superName.equals("java/lang/Object")); 146 super.visit(version, access, name, sig, superName, interfaces); 147 } 148 149 @Override 150 public void visitSource(String source, String debug) { 151 super.visitSource(source, debug); 152 } 153 154 @Override 155 public AnnotationVisitor visitAnnotation(String desc, boolean visible) { 156 if (desc.equals("Lcom/sleepycat/persist/model/Entity;") || 157 desc.equals("Lcom/sleepycat/persist/model/Persistent;")) { 158 isPersistent = true; 159 } 160 return super.visitAnnotation(desc, visible); 161 } 162 163 @Override 164 public FieldVisitor visitField(int access, 165 String name, 166 String desc, 167 String sig, 168 Object value) { 169 if (!isPersistent) { 170 throw abort(); 171 } 172 FieldVisitor ret = super.visitField(access, name, desc, sig, value); 173 if ((access & (ACC_STATIC | ACC_TRANSIENT)) == 0) { 174 FieldInfo info = new FieldInfo(ret, name, desc); 175 nonKeyFields.add(info); 176 ret = info; 177 } 178 return ret; 179 } 180 181 @Override 182 public MethodVisitor visitMethod(int access, 183 String name, 184 String desc, 185 String sig, 186 String [] exceptions) { 187 if (!isPersistent) { 188 throw abort(); 189 } 190 if ("<init>".equals(name) && "()V".equals(desc)) { 191 hasDefaultConstructor = true; 192 } 193 if ("<clinit>".equals(name)) { 194 if (staticBlockMethod != null) { 195 throw new IllegalStateException (); 196 } 197 staticBlockMethod = "bdbExistingStaticBlock"; 198 return cv.visitMethod 199 (ACC_PRIVATE + ACC_STATIC, staticBlockMethod, "()V", null, 200 null); 201 } 202 return super.visitMethod(access, name, desc, sig, exceptions); 203 } 204 205 @Override 206 public void visitEnd() { 207 if (!isPersistent || !hasDefaultConstructor) { 208 throw abort(); 209 } 210 211 sortFields(); 212 genBdbNewInstance(); 213 genBdbNewArray(); 214 genBdbIsPriKeyFieldNullOrZero(); 215 genBdbWritePriKeyField(); 216 genBdbReadPriKeyField(); 217 genBdbWriteSecKeyFields(); 218 genBdbReadSecKeyFields(); 219 genBdbWriteNonKeyFields(); 220 genBdbReadNonKeyFields(); 221 genBdbGetField(); 222 genBdbSetField(); 223 genStaticBlock(); 224 super.visitEnd(); 225 } 226 227 private void sortFields() { 228 231 if (nonKeyFields.size() == 0) { 232 return; 233 } 234 isCompositeKey = true; 235 for (FieldInfo field : nonKeyFields) { 236 if (field.order == null) { 237 isCompositeKey = false; 238 } 239 } 240 if (isCompositeKey) { 241 Collections.sort(nonKeyFields, new Comparator <FieldInfo>() { 242 public int compare(FieldInfo f1, FieldInfo f2) { 243 return f1.order.value - f2.order.value; 244 } 245 }); 246 } else { 247 for (int i = 0; i < nonKeyFields.size();) { 248 FieldInfo field = nonKeyFields.get(i); 249 if (field.isPriKey) { 250 if (priKeyField == null) { 251 priKeyField = field; 252 nonKeyFields.remove(i); 253 } 254 } else if (field.isSecKey) { 255 secKeyFields.add(field); 256 nonKeyFields.remove(i); 257 } else { 258 i += 1; 259 } 260 } 261 Comparator <FieldInfo> cmp = new Comparator <FieldInfo>() { 262 public int compare(FieldInfo f1, FieldInfo f2) { 263 return f1.name.compareTo(f2.name); 264 } 265 }; 266 Collections.sort(secKeyFields, cmp); 267 Collections.sort(nonKeyFields, cmp); 268 } 269 274 } 275 276 285 private void genStaticBlock() { 286 MethodVisitor mv = 287 cv.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null); 288 mv.visitCode(); 289 if (staticBlockMethod != null) { 290 mv.visitMethodInsn 291 (INVOKESTATIC, className, staticBlockMethod, "()V"); 292 } 293 mv.visitLdcInsn(className.replace('/', '.')); 294 if (isAbstract) { 295 mv.visitInsn(ACONST_NULL); 296 } else { 297 mv.visitTypeInsn(NEW, className); 298 mv.visitInsn(DUP); 299 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V"); 300 } 301 mv.visitMethodInsn 302 (INVOKESTATIC, "com/sleepycat/persist/impl/EnhancedAccessor", 303 "registerClass", 304 "(Ljava/lang/String;Lcom/sleepycat/persist/impl/Enhanced;)V"); 305 mv.visitInsn(RETURN); 306 mv.visitMaxs(3, 0); 307 mv.visitEnd(); 308 } 309 310 317 private void genBdbNewInstance() { 318 MethodVisitor mv = cv.visitMethod 319 (ACC_PUBLIC, "bdbNewInstance", "()Ljava/lang/Object;", null, null); 320 mv.visitCode(); 321 if (isAbstract) { 322 mv.visitInsn(ACONST_NULL); 323 mv.visitInsn(ARETURN); 324 mv.visitMaxs(1, 1); 325 } else { 326 mv.visitTypeInsn(NEW, className); 327 mv.visitInsn(DUP); 328 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V"); 329 mv.visitInsn(ARETURN); 330 mv.visitMaxs(2, 1); 331 } 332 mv.visitEnd(); 333 } 334 335 342 private void genBdbNewArray() { 343 MethodVisitor mv = cv.visitMethod 344 (ACC_PUBLIC, "bdbNewArray", "(I)Ljava/lang/Object;", null, null); 345 mv.visitCode(); 346 if (isAbstract) { 347 mv.visitInsn(ACONST_NULL); 348 mv.visitInsn(ARETURN); 349 mv.visitMaxs(1, 2); 350 } else { 351 mv.visitVarInsn(ILOAD, 1); 352 mv.visitTypeInsn(ANEWARRAY, className); 353 mv.visitInsn(ARETURN); 354 mv.visitMaxs(1, 2); 355 mv.visitEnd(); 356 } 357 } 358 359 366 private void genBdbIsPriKeyFieldNullOrZero() { 367 MethodVisitor mv = cv.visitMethod 368 (ACC_PUBLIC, "bdbIsPriKeyFieldNullOrZero", "()Z", null, null); 369 mv.visitCode(); 370 if (priKeyField != null) { 371 mv.visitVarInsn(ALOAD, 0); 372 mv.visitFieldInsn 373 (GETFIELD, className, priKeyField.name, 374 priKeyField.type.getDescriptor()); 375 Label l0 = new Label(); 376 if (isRefType(priKeyField.type)) { 377 mv.visitJumpInsn(IFNONNULL, l0); 378 } else { 379 genBeforeCompareToZero(mv, priKeyField.type); 380 mv.visitJumpInsn(IFNE, l0); 381 } 382 mv.visitInsn(ICONST_1); 383 Label l1 = new Label(); 384 mv.visitJumpInsn(GOTO, l1); 385 mv.visitLabel(l0); 386 mv.visitInsn(ICONST_0); 387 mv.visitLabel(l1); 388 } else if (hasPersistentSuperclass) { 389 mv.visitVarInsn(ALOAD, 0); 390 mv.visitMethodInsn 391 (INVOKESPECIAL, superclassName, "bdbIsPriKeyFieldNullOrZero", 392 "()Z"); 393 } else { 394 mv.visitInsn(ICONST_0); 395 } 396 mv.visitInsn(IRETURN); 397 mv.visitMaxs(1, 1); 398 mv.visitEnd(); 399 } 400 401 410 private void genBdbWritePriKeyField() { 411 MethodVisitor mv = cv.visitMethod 412 (ACC_PUBLIC, "bdbWritePriKeyField", 413 "(Lcom/sleepycat/persist/impl/EntityOutput;" + 414 "Lcom/sleepycat/persist/impl/Format;)V", 415 null, null); 416 mv.visitCode(); 417 if (priKeyField != null) { 418 if (!genWriteSimpleKeyField(mv, priKeyField)) { 419 420 mv.visitVarInsn(ALOAD, 1); 421 mv.visitVarInsn(ALOAD, 0); 422 mv.visitFieldInsn 423 (GETFIELD, className, priKeyField.name, 424 priKeyField.type.getDescriptor()); 425 mv.visitVarInsn(ALOAD, 2); 426 mv.visitMethodInsn 427 (INVOKEINTERFACE, 428 "com/sleepycat/persist/impl/EntityOutput", 429 "writeKeyObject", 430 "(Ljava/lang/Object;" + 431 "Lcom/sleepycat/persist/impl/Format;)V"); 432 } 433 } else if (hasPersistentSuperclass) { 434 mv.visitVarInsn(ALOAD, 0); 435 mv.visitVarInsn(ALOAD, 1); 436 mv.visitVarInsn(ALOAD, 2); 437 mv.visitMethodInsn 438 (INVOKESPECIAL, superclassName, "bdbWritePriKeyField", 439 "(Lcom/sleepycat/persist/impl/EntityOutput;" + 440 "Lcom/sleepycat/persist/impl/Format;)V"); 441 } 442 mv.visitInsn(RETURN); 443 mv.visitMaxs(3, 3); 444 mv.visitEnd(); 445 } 446 447 456 private void genBdbReadPriKeyField() { 457 MethodVisitor mv = cv.visitMethod 458 (ACC_PUBLIC, "bdbReadPriKeyField", 459 "(Lcom/sleepycat/persist/impl/EntityInput;" + 460 "Lcom/sleepycat/persist/impl/Format;)V", 461 null, null); 462 mv.visitCode(); 463 if (priKeyField != null) { 464 if (!genReadSimpleKeyField(mv, priKeyField)) { 465 466 mv.visitVarInsn(ALOAD, 0); 467 mv.visitVarInsn(ALOAD, 1); 468 mv.visitVarInsn(ALOAD, 2); 469 mv.visitMethodInsn 470 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 471 "readKeyObject", 472 "(Lcom/sleepycat/persist/impl/Format;)" + 473 "Ljava/lang/Object;"); 474 mv.visitTypeInsn(CHECKCAST, getTypeInstName(priKeyField.type)); 475 mv.visitFieldInsn 476 (PUTFIELD, className, priKeyField.name, 477 priKeyField.type.getDescriptor()); 478 } 479 } else if (hasPersistentSuperclass) { 480 mv.visitVarInsn(ALOAD, 0); 481 mv.visitVarInsn(ALOAD, 1); 482 mv.visitVarInsn(ALOAD, 2); 483 mv.visitMethodInsn 484 (INVOKESPECIAL, superclassName, "bdbReadPriKeyField", 485 "(Lcom/sleepycat/persist/impl/EntityInput;" + 486 "Lcom/sleepycat/persist/impl/Format;)V"); 487 } 488 mv.visitInsn(RETURN); 489 mv.visitMaxs(3, 3); 490 mv.visitEnd(); 491 } 492 493 502 private void genBdbWriteSecKeyFields() { 503 MethodVisitor mv = cv.visitMethod 504 (ACC_PUBLIC, "bdbWriteSecKeyFields", 505 "(Lcom/sleepycat/persist/impl/EntityOutput;)V", null, null); 506 mv.visitCode(); 507 if (priKeyField != null && isRefType(priKeyField.type)) { 508 genRegisterPrimaryKey(mv, false); 509 } 510 if (hasPersistentSuperclass) { 511 mv.visitVarInsn(ALOAD, 0); 512 mv.visitVarInsn(ALOAD, 1); 513 mv.visitMethodInsn 514 (INVOKESPECIAL, superclassName, "bdbWriteSecKeyFields", 515 "(Lcom/sleepycat/persist/impl/EntityOutput;)V"); 516 } 517 for (FieldInfo field : secKeyFields) { 518 genWriteField(mv, field); 519 } 520 mv.visitInsn(RETURN); 521 mv.visitMaxs(2, 2); 522 mv.visitEnd(); 523 } 524 525 549 private void genBdbReadSecKeyFields() { 550 MethodVisitor mv = cv.visitMethod 551 (ACC_PUBLIC, "bdbReadSecKeyFields", 552 "(Lcom/sleepycat/persist/impl/EntityInput;III)V", null, null); 553 mv.visitCode(); 554 if (priKeyField != null && isRefType(priKeyField.type)) { 555 genRegisterPrimaryKey(mv, true); 556 } 557 genReadSuperKeyFields(mv, true); 558 genReadFieldSwitch(mv, secKeyFields); 559 mv.visitInsn(RETURN); 560 mv.visitMaxs(5, 5); 561 mv.visitEnd(); 562 } 563 564 569 private void genRegisterPrimaryKey(MethodVisitor mv, boolean input) { 570 String entityInputOrOutputClass = 571 input ? "com/sleepycat/persist/impl/EntityInput" 572 : "com/sleepycat/persist/impl/EntityOutput"; 573 mv.visitVarInsn(ALOAD, 1); 574 mv.visitVarInsn(ALOAD, 0); 575 mv.visitFieldInsn 576 (GETFIELD, className, priKeyField.name, 577 priKeyField.type.getDescriptor()); 578 mv.visitMethodInsn 579 (INVOKEINTERFACE, entityInputOrOutputClass, "registerPriKeyObject", 580 "(Ljava/lang/Object;)V"); 581 } 582 583 591 private void genBdbWriteNonKeyFields() { 592 MethodVisitor mv = cv.visitMethod 593 (ACC_PUBLIC, "bdbWriteNonKeyFields", 594 "(Lcom/sleepycat/persist/impl/EntityOutput;)V", null, null); 595 mv.visitCode(); 596 if (hasPersistentSuperclass) { 597 mv.visitVarInsn(ALOAD, 0); 598 mv.visitVarInsn(ALOAD, 1); 599 mv.visitMethodInsn 600 (INVOKESPECIAL, superclassName, "bdbWriteNonKeyFields", 601 "(Lcom/sleepycat/persist/impl/EntityOutput;)V"); 602 } 603 if (isCompositeKey) { 604 for (FieldInfo field : nonKeyFields) { 605 genWriteSimpleKeyField(mv, field); 606 607 } 608 } else { 609 for (FieldInfo field : nonKeyFields) { 610 genWriteField(mv, field); 611 } 612 } 613 mv.visitInsn(RETURN); 614 mv.visitMaxs(2, 2); 615 mv.visitEnd(); 616 } 617 618 633 private void genBdbReadNonKeyFields() { 634 MethodVisitor mv = cv.visitMethod 635 (ACC_PUBLIC, "bdbReadNonKeyFields", 636 "(Lcom/sleepycat/persist/impl/EntityInput;III)V", null, null); 637 mv.visitCode(); 638 if (isCompositeKey) { 639 for (FieldInfo field : nonKeyFields) { 640 genReadSimpleKeyField(mv, field); 641 642 } 643 } else { 644 genReadSuperKeyFields(mv, false); 645 genReadFieldSwitch(mv, nonKeyFields); 646 } 647 mv.visitInsn(RETURN); 648 mv.visitMaxs(5, 5); 649 mv.visitEnd(); 650 } 651 652 657 private void genWriteField(MethodVisitor mv, FieldInfo field) { 658 mv.visitVarInsn(ALOAD, 1); 659 mv.visitVarInsn(ALOAD, 0); 660 mv.visitFieldInsn 661 (GETFIELD, className, field.name, field.type.getDescriptor()); 662 int sort = field.type.getSort(); 663 if (sort == Type.OBJECT || sort == Type.ARRAY) { 664 mv.visitInsn(ACONST_NULL); 665 mv.visitMethodInsn 666 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 667 "writeObject", 668 "(Ljava/lang/Object;Lcom/sleepycat/persist/impl/Format;)V"); 669 } else { 670 genWritePrimitive(mv, sort); 671 } 672 } 673 674 683 private boolean genWriteSimpleKeyField(MethodVisitor mv, FieldInfo field) { 684 if (genWritePrimitiveField(mv, field)) { 685 return true; 686 } 687 String fieldClassName = field.type.getClassName(); 688 if (!isSimpleRefType(fieldClassName)) { 689 return false; 690 } 691 mv.visitVarInsn(ALOAD, 1); 692 mv.visitVarInsn(ALOAD, 0); 693 mv.visitFieldInsn 694 (GETFIELD, className, field.name, field.type.getDescriptor()); 695 Integer sort = PRIMITIVE_WRAPPERS.get(fieldClassName); 696 if (sort != null) { 697 genUnwrapPrimitive(mv, sort); 698 genWritePrimitive(mv, sort); 699 } else if (fieldClassName.equals(Date .class.getName())) { 700 mv.visitMethodInsn 701 (INVOKEVIRTUAL, "java/util/Date", "getTime", "()J"); 702 genWritePrimitive(mv, Type.LONG); 703 } else if (fieldClassName.equals(String .class.getName())) { 704 mv.visitMethodInsn 705 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 706 "writeString", 707 "(Ljava/lang/String;)Lcom/sleepycat/bind/tuple/TupleOutput;"); 708 mv.visitInsn(POP); 709 } else if (fieldClassName.equals(BigInteger .class.getName())) { 710 mv.visitMethodInsn 711 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 712 "writeBigInteger", 713 "(Ljava/math/BigInteger;)Lcom/sleepycat/bind/tuple/TupleOutput;"); 714 mv.visitInsn(POP); 715 } else { 716 throw new IllegalStateException (fieldClassName); 717 } 718 return true; 719 } 720 721 private boolean genWritePrimitiveField(MethodVisitor mv, FieldInfo field) { 722 int sort = field.type.getSort(); 723 if (sort == Type.OBJECT || sort == Type.ARRAY) { 724 return false; 725 } 726 mv.visitVarInsn(ALOAD, 1); 727 mv.visitVarInsn(ALOAD, 0); 728 mv.visitFieldInsn 729 (GETFIELD, className, field.name, field.type.getDescriptor()); 730 genWritePrimitive(mv, sort); 731 return true; 732 } 733 734 740 private void genReadSuperKeyFields(MethodVisitor mv, 741 boolean areSecKeyFields) { 742 if (hasPersistentSuperclass) { 743 Label next = new Label(); 744 mv.visitVarInsn(ILOAD, 4); 745 mv.visitJumpInsn(IFEQ, next); 746 mv.visitVarInsn(ALOAD, 0); 747 mv.visitVarInsn(ALOAD, 1); 748 mv.visitVarInsn(ILOAD, 2); 749 mv.visitVarInsn(ILOAD, 3); 750 mv.visitVarInsn(ILOAD, 4); 751 mv.visitInsn(ICONST_1); 752 mv.visitInsn(ISUB); 753 String name = areSecKeyFields ? "bdbReadSecKeyFields" 754 : "bdbReadNonKeyFields"; 755 mv.visitMethodInsn 756 (INVOKESPECIAL, superclassName, name, 757 "(Lcom/sleepycat/persist/impl/EntityInput;III)V"); 758 mv.visitLabel(next); 759 } 760 } 761 762 781 private void genReadFieldSwitch(MethodVisitor mv, List <FieldInfo> fields) { 782 int nFields = fields.size(); 783 if (nFields > 0) { 784 mv.visitVarInsn(ILOAD, 4); 785 Label pastSwitch = new Label(); 786 mv.visitJumpInsn(IFGT, pastSwitch); 787 Label[] labels = new Label[nFields]; 788 for (int i = 0; i < nFields; i += 1) { 789 labels[i] = new Label(); 790 } 791 mv.visitVarInsn(ILOAD, 2); 792 mv.visitTableSwitchInsn(0, nFields - 1, pastSwitch, labels); 793 for (int i = 0; i < nFields; i += 1) { 794 FieldInfo field = fields.get(i); 795 mv.visitLabel(labels[i]); 796 genReadField(mv, field); 797 if (i < nFields - 1) { 798 Label nextCase = labels[i + 1]; 799 mv.visitVarInsn(ILOAD, 3); 800 if (i == 0) { 801 mv.visitJumpInsn(IFNE, nextCase); 802 } else { 803 switch (i) { 804 case 1: 805 mv.visitInsn(ICONST_1); 806 break; 807 case 2: 808 mv.visitInsn(ICONST_2); 809 break; 810 case 3: 811 mv.visitInsn(ICONST_3); 812 break; 813 case 4: 814 mv.visitInsn(ICONST_4); 815 break; 816 case 5: 817 mv.visitInsn(ICONST_5); 818 break; 819 default: 820 mv.visitIntInsn(BIPUSH, i); 821 } 822 mv.visitJumpInsn(IF_ICMPNE, nextCase); 823 } 824 mv.visitJumpInsn(GOTO, pastSwitch); 825 } 826 } 827 mv.visitLabel(pastSwitch); 828 } 829 } 830 831 836 private void genReadField(MethodVisitor mv, FieldInfo field) { 837 mv.visitVarInsn(ALOAD, 0); 838 mv.visitVarInsn(ALOAD, 1); 839 if (isRefType(field.type)) { 840 mv.visitMethodInsn 841 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 842 "readObject", "()Ljava/lang/Object;"); 843 mv.visitTypeInsn(CHECKCAST, getTypeInstName(field.type)); 844 } else { 845 genReadPrimitive(mv, field.type.getSort()); 846 } 847 mv.visitFieldInsn 848 (PUTFIELD, className, field.name, field.type.getDescriptor()); 849 } 850 851 860 private boolean genReadSimpleKeyField(MethodVisitor mv, FieldInfo field) { 861 if (genReadPrimitiveField(mv, field)) { 862 return true; 863 } 864 String fieldClassName = field.type.getClassName(); 865 if (!isSimpleRefType(fieldClassName)) { 866 return false; 867 } 868 Integer sort = PRIMITIVE_WRAPPERS.get(fieldClassName); 869 if (sort != null) { 870 mv.visitVarInsn(ALOAD, 0); 871 mv.visitVarInsn(ALOAD, 1); 872 genReadPrimitive(mv, sort); 873 genWrapPrimitive(mv, sort); 874 } else if (fieldClassName.equals(Date .class.getName())) { 875 876 mv.visitVarInsn(ALOAD, 0); 877 mv.visitTypeInsn(NEW, "java/util/Date"); 878 mv.visitInsn(DUP); 879 mv.visitVarInsn(ALOAD, 1); 880 genReadPrimitive(mv, Type.LONG); 881 mv.visitMethodInsn 882 (INVOKESPECIAL, "java/util/Date", "<init>", "(J)V"); 883 } else if (fieldClassName.equals(String .class.getName())) { 884 mv.visitVarInsn(ALOAD, 0); 885 mv.visitVarInsn(ALOAD, 1); 886 mv.visitMethodInsn 887 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 888 "readString", "()Ljava/lang/String;"); 889 } else if (fieldClassName.equals(BigInteger .class.getName())) { 890 mv.visitVarInsn(ALOAD, 0); 891 mv.visitVarInsn(ALOAD, 1); 892 mv.visitMethodInsn 893 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 894 "readBigInteger", "()Ljava/math/BigInteger;"); 895 } else { 896 throw new IllegalStateException (fieldClassName); 897 } 898 mv.visitFieldInsn 899 (PUTFIELD, className, field.name, field.type.getDescriptor()); 900 return true; 901 } 902 903 private boolean genReadPrimitiveField(MethodVisitor mv, FieldInfo field) { 904 int sort = field.type.getSort(); 905 if (sort == Type.OBJECT || sort == Type.ARRAY) { 906 return false; 907 } 908 mv.visitVarInsn(ALOAD, 0); 909 mv.visitVarInsn(ALOAD, 1); 910 genReadPrimitive(mv, sort); 911 mv.visitFieldInsn 912 (PUTFIELD, className, field.name, field.type.getDescriptor()); 913 return true; 914 } 915 916 947 private void genBdbGetField() { 948 MethodVisitor mv = cv.visitMethod 949 (ACC_PUBLIC, "bdbGetField", 950 "(Ljava/lang/Object;IIZ)Ljava/lang/Object;", null, null); 951 mv.visitCode(); 952 mv.visitVarInsn(ILOAD, 3); 953 Label l0 = new Label(); 954 mv.visitJumpInsn(IFLE, l0); 955 Label l1 = new Label(); 956 if (hasPersistentSuperclass) { 957 mv.visitVarInsn(ALOAD, 0); 958 mv.visitVarInsn(ALOAD, 1); 959 mv.visitVarInsn(ILOAD, 2); 960 mv.visitVarInsn(ILOAD, 3); 961 mv.visitInsn(ICONST_1); 962 mv.visitInsn(ISUB); 963 mv.visitVarInsn(ILOAD, 4); 964 mv.visitMethodInsn 965 (INVOKESPECIAL, className, "bdbGetField", 966 "(Ljava/lang/Object;IIZ)Ljava/lang/Object;"); 967 mv.visitInsn(ARETURN); 968 } else { 969 mv.visitJumpInsn(GOTO, l1); 970 } 971 mv.visitLabel(l0); 972 mv.visitVarInsn(ILOAD, 4); 973 Label l2 = new Label(); 974 mv.visitJumpInsn(IFEQ, l2); 975 genGetFieldSwitch(mv, secKeyFields, l1); 976 mv.visitLabel(l2); 977 genGetFieldSwitch(mv, nonKeyFields, l1); 978 mv.visitLabel(l1); 979 mv.visitInsn(ACONST_NULL); 980 mv.visitInsn(ARETURN); 981 mv.visitMaxs(1, 5); 982 mv.visitEnd(); 983 } 984 985 1006 private void genGetFieldSwitch(MethodVisitor mv, 1007 List <FieldInfo> fields, 1008 Label defaultLabel) { 1009 int nFields = fields.size(); 1010 if (nFields == 0) { 1011 mv.visitJumpInsn(GOTO, defaultLabel); 1012 return; 1013 } 1014 Label[] labels = new Label[nFields]; 1015 for (int i = 0; i < nFields; i += 1) { 1016 labels[i] = new Label(); 1017 } 1018 mv.visitVarInsn(ILOAD, 2); 1019 mv.visitTableSwitchInsn(0, nFields - 1, defaultLabel, labels); 1020 for (int i = 0; i < nFields; i += 1) { 1021 FieldInfo field = fields.get(i); 1022 mv.visitLabel(labels[i]); 1023 mv.visitVarInsn(ALOAD, 0); 1024 mv.visitFieldInsn 1025 (GETFIELD, className, field.name, field.type.getDescriptor()); 1026 if (!isRefType(field.type)) { 1027 genWrapPrimitive(mv, field.type.getSort()); 1028 } 1029 mv.visitInsn(ARETURN); 1030 } 1031 } 1032 1033 1064 private void genBdbSetField() { 1065 MethodVisitor mv = cv.visitMethod 1066 (ACC_PUBLIC, "bdbSetField", 1067 "(Ljava/lang/Object;IIZLjava/lang/Object;)V", null, null); 1068 mv.visitCode(); 1069 mv.visitVarInsn(ILOAD, 3); 1070 Label l0 = new Label(); 1071 mv.visitJumpInsn(IFLE, l0); 1072 if (hasPersistentSuperclass) { 1073 mv.visitVarInsn(ALOAD, 0); 1074 mv.visitVarInsn(ALOAD, 1); 1075 mv.visitVarInsn(ILOAD, 2); 1076 mv.visitVarInsn(ILOAD, 3); 1077 mv.visitInsn(ICONST_1); 1078 mv.visitInsn(ISUB); 1079 mv.visitVarInsn(ILOAD, 4); 1080 mv.visitVarInsn(ALOAD, 5); 1081 mv.visitMethodInsn 1082 (INVOKESPECIAL, className, "bdbSetField", 1083 "(Ljava/lang/Object;IIZLjava/lang/Object;)V"); 1084 } 1085 mv.visitInsn(RETURN); 1086 mv.visitLabel(l0); 1087 mv.visitVarInsn(ILOAD, 4); 1088 Label l2 = new Label(); 1089 mv.visitJumpInsn(IFEQ, l2); 1090 Label l1 = new Label(); 1091 genSetFieldSwitch(mv, secKeyFields, l1); 1092 mv.visitLabel(l2); 1093 genSetFieldSwitch(mv, nonKeyFields, l1); 1094 mv.visitLabel(l1); 1095 mv.visitInsn(RETURN); 1096 mv.visitMaxs(2, 6); 1097 mv.visitEnd(); 1098 } 1099 1100 1124 private void genSetFieldSwitch(MethodVisitor mv, 1125 List <FieldInfo> fields, 1126 Label defaultLabel) { 1127 int nFields = fields.size(); 1128 if (nFields == 0) { 1129 mv.visitJumpInsn(GOTO, defaultLabel); 1130 return; 1131 } 1132 Label[] labels = new Label[nFields]; 1133 for (int i = 0; i < nFields; i += 1) { 1134 labels[i] = new Label(); 1135 } 1136 mv.visitVarInsn(ILOAD, 2); 1137 mv.visitTableSwitchInsn(0, nFields - 1, defaultLabel, labels); 1138 for (int i = 0; i < nFields; i += 1) { 1139 FieldInfo field = fields.get(i); 1140 mv.visitLabel(labels[i]); 1141 mv.visitVarInsn(ALOAD, 0); 1142 mv.visitVarInsn(ALOAD, 5); 1143 if (isRefType(field.type)) { 1144 mv.visitTypeInsn(CHECKCAST, getTypeInstName(field.type)); 1145 } else { 1146 int sort = field.type.getSort(); 1147 mv.visitTypeInsn 1148 (CHECKCAST, 1149 getPrimitiveWrapperClass(sort).replace('.', '/')); 1150 genUnwrapPrimitive(mv, sort); 1151 } 1152 mv.visitFieldInsn 1153 (PUTFIELD, className, field.name, field.type.getDescriptor()); 1154 mv.visitInsn(RETURN); 1155 } 1156 } 1157 1158 private void genWritePrimitive(MethodVisitor mv, int sort) { 1159 switch (sort) { 1160 case Type.BOOLEAN: 1161 mv.visitMethodInsn 1162 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1163 "writeBoolean", "(Z)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1164 break; 1165 case Type.CHAR: 1166 mv.visitMethodInsn 1167 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1168 "writeChar", "(I)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1169 break; 1170 case Type.BYTE: 1171 mv.visitMethodInsn 1172 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1173 "writeByte", "(I)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1174 break; 1175 case Type.SHORT: 1176 mv.visitMethodInsn 1177 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1178 "writeShort", "(I)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1179 break; 1180 case Type.INT: 1181 mv.visitMethodInsn 1182 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1183 "writeInt", "(I)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1184 break; 1185 case Type.LONG: 1186 mv.visitMethodInsn 1187 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1188 "writeLong", "(J)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1189 break; 1190 case Type.FLOAT: 1191 mv.visitMethodInsn 1192 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1193 "writeSortedFloat", 1194 "(F)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1195 break; 1196 case Type.DOUBLE: 1197 mv.visitMethodInsn 1198 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1199 "writeSortedDouble", 1200 "(D)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1201 break; 1202 default: 1203 throw new IllegalStateException (String.valueOf(sort)); 1204 } 1205 1206 mv.visitInsn(POP); 1207 } 1208 1209 private void genReadPrimitive(MethodVisitor mv, int sort) { 1210 switch (sort) { 1211 case Type.BOOLEAN: 1212 mv.visitMethodInsn 1213 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1214 "readBoolean", "()Z"); 1215 break; 1216 case Type.CHAR: 1217 mv.visitMethodInsn 1218 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1219 "readChar", "()C"); 1220 break; 1221 case Type.BYTE: 1222 mv.visitMethodInsn 1223 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1224 "readByte", "()B"); 1225 break; 1226 case Type.SHORT: 1227 mv.visitMethodInsn 1228 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1229 "readShort", "()S"); 1230 break; 1231 case Type.INT: 1232 mv.visitMethodInsn 1233 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1234 "readInt", "()I"); 1235 break; 1236 case Type.LONG: 1237 mv.visitMethodInsn 1238 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1239 "readLong", "()J"); 1240 break; 1241 case Type.FLOAT: 1242 mv.visitMethodInsn 1243 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1244 "readSortedFloat", "()F"); 1245 break; 1246 case Type.DOUBLE: 1247 mv.visitMethodInsn 1248 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1249 "readSortedDouble", "()D"); 1250 break; 1251 default: 1252 throw new IllegalStateException (String.valueOf(sort)); 1253 } 1254 } 1255 1256 private void genWrapPrimitive(MethodVisitor mv, int sort) { 1257 switch (sort) { 1258 case Type.BOOLEAN: 1259 mv.visitMethodInsn 1260 (INVOKESTATIC, "java/lang/Boolean", "valueOf", 1261 "(Z)Ljava/lang/Boolean;"); 1262 break; 1263 case Type.CHAR: 1264 mv.visitMethodInsn 1265 (INVOKESTATIC, "java/lang/Character", "valueOf", 1266 "(C)Ljava/lang/Character;"); 1267 break; 1268 case Type.BYTE: 1269 mv.visitMethodInsn 1270 (INVOKESTATIC, "java/lang/Byte", "valueOf", 1271 "(B)Ljava/lang/Byte;"); 1272 break; 1273 case Type.SHORT: 1274 mv.visitMethodInsn 1275 (INVOKESTATIC, "java/lang/Short", "valueOf", 1276 "(S)Ljava/lang/Short;"); 1277 break; 1278 case Type.INT: 1279 mv.visitMethodInsn 1280 (INVOKESTATIC, "java/lang/Integer", "valueOf", 1281 "(I)Ljava/lang/Integer;"); 1282 break; 1283 case Type.LONG: 1284 mv.visitMethodInsn 1285 (INVOKESTATIC, "java/lang/Long", "valueOf", 1286 "(J)Ljava/lang/Long;"); 1287 break; 1288 case Type.FLOAT: 1289 mv.visitMethodInsn 1290 (INVOKESTATIC, "java/lang/Float", "valueOf", 1291 "(F)Ljava/lang/Float;"); 1292 break; 1293 case Type.DOUBLE: 1294 mv.visitMethodInsn 1295 (INVOKESTATIC, "java/lang/Double", "valueOf", 1296 "(D)Ljava/lang/Double;"); 1297 break; 1298 default: 1299 throw new IllegalStateException (String.valueOf(sort)); 1300 } 1301 } 1302 1303 private void genUnwrapPrimitive(MethodVisitor mv, int sort) { 1304 switch (sort) { 1305 case Type.BOOLEAN: 1306 mv.visitMethodInsn 1307 (INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z"); 1308 break; 1309 case Type.CHAR: 1310 mv.visitMethodInsn 1311 (INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C"); 1312 break; 1313 case Type.BYTE: 1314 mv.visitMethodInsn 1315 (INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B"); 1316 break; 1317 case Type.SHORT: 1318 mv.visitMethodInsn 1319 (INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S"); 1320 break; 1321 case Type.INT: 1322 mv.visitMethodInsn 1323 (INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I"); 1324 break; 1325 case Type.LONG: 1326 mv.visitMethodInsn 1327 (INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J"); 1328 break; 1329 case Type.FLOAT: 1330 mv.visitMethodInsn 1331 (INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F"); 1332 break; 1333 case Type.DOUBLE: 1334 mv.visitMethodInsn 1335 (INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D"); 1336 break; 1337 default: 1338 throw new IllegalStateException (String.valueOf(sort)); 1339 } 1340 } 1341 1342 1347 private static String getTypeInstName(Type type) { 1348 if (type.getSort() == Type.OBJECT) { 1349 return type.getInternalName(); 1350 } else if (type.getSort() == Type.ARRAY) { 1351 return type.getDescriptor(); 1352 } else { 1353 throw new IllegalStateException (); 1354 } 1355 } 1356 1357 1363 private static void genBeforeCompareToZero(MethodVisitor mv, Type type) { 1364 switch (type.getSort()) { 1365 case Type.LONG: 1366 mv.visitInsn(LCONST_0); 1367 mv.visitInsn(LCMP); 1368 break; 1369 case Type.FLOAT: 1370 mv.visitInsn(FCONST_0); 1371 mv.visitInsn(FCMPL); 1372 break; 1373 case Type.DOUBLE: 1374 mv.visitInsn(DCONST_0); 1375 mv.visitInsn(DCMPL); 1376 break; 1377 } 1378 } 1379 1380 1383 static boolean isSimpleRefType(String className) { 1384 return (PRIMITIVE_WRAPPERS.containsKey(className) || 1385 className.equals(BigInteger .class.getName()) || 1386 className.equals(Date .class.getName()) || 1387 className.equals(String .class.getName())); 1388 } 1389 1390 1393 static String getPrimitiveWrapperClass(int primitiveSort) { 1394 for (Map.Entry <String ,Integer > entry : PRIMITIVE_WRAPPERS.entrySet()) { 1395 if (entry.getValue() == primitiveSort) { 1396 return entry.getKey(); 1397 } 1398 } 1399 throw new IllegalStateException (String.valueOf(primitiveSort)); 1400 } 1401 1402 1405 private static boolean isRefType(Type type) { 1406 int sort = type.getSort(); 1407 return (sort == Type.OBJECT || sort == Type.ARRAY); 1408 } 1409 1410 1413 private static boolean containsString(String [] a, String s) { 1414 if (a != null) { 1415 for (String t : a) { 1416 if (s.equals(t)) { 1417 return true; 1418 } 1419 } 1420 } 1421 return false; 1422 } 1423 1424 1427 private static String [] appendString(String [] a, String s) { 1428 if (a != null) { 1429 int len = a.length; 1430 String [] a2 = new String [len + 1]; 1431 System.arraycopy(a, 0, a2, 0, len); 1432 a2[len] = s; 1433 return a2; 1434 } else { 1435 return new String [] { s }; 1436 } 1437 } 1438 1439 1443 private NotPersistentException abort() { 1444 return NOT_PERSISTENT; 1445 } 1446 1447 private static class FieldInfo implements FieldVisitor { 1448 1449 FieldVisitor parent; 1450 String name; 1451 Type type; 1452 OrderInfo order; 1453 boolean isPriKey; 1454 boolean isSecKey; 1455 1456 FieldInfo(FieldVisitor parent, String name, String desc) { 1457 this.parent = parent; 1458 this.name = name; 1459 type = Type.getType(desc); 1460 } 1461 1462 public AnnotationVisitor visitAnnotation(String desc, 1463 boolean visible) { 1464 AnnotationVisitor ret = parent.visitAnnotation(desc, visible); 1465 if (desc.equals 1466 ("Lcom/sleepycat/persist/model/KeyField;")) { 1467 order = new OrderInfo(ret); 1468 ret = order; 1469 } else if (desc.equals 1470 ("Lcom/sleepycat/persist/model/PrimaryKey;")) { 1471 isPriKey = true; 1472 } else if (desc.equals 1473 ("Lcom/sleepycat/persist/model/SecondaryKey;")) { 1474 isSecKey = true; 1475 } 1476 return ret; 1477 } 1478 1479 public void visitAttribute(Attribute attr) { 1480 parent.visitAttribute(attr); 1481 } 1482 1483 public void visitEnd() { 1484 parent.visitEnd(); 1485 } 1486 1487 @Override 1488 public String toString() { 1489 String label; 1490 if (isPriKey) { 1491 label = "PrimaryKey"; 1492 } else if (isSecKey) { 1493 label = "SecondaryKey"; 1494 } else if (order != null) { 1495 label = "CompositeKeyField " + order.value; 1496 } else { 1497 label = "NonKeyField"; 1498 } 1499 return "[" + label + ' ' + name + ' ' + type + ']'; 1500 } 1501 } 1502 1503 private static class OrderInfo extends AnnotationInfo { 1504 1505 int value; 1506 1507 OrderInfo(AnnotationVisitor parent) { 1508 super(parent); 1509 } 1510 1511 @Override 1512 public void visit(String name, Object value) { 1513 if (name.equals("value")) { 1514 this.value = (Integer ) value; 1515 } 1516 parent.visit(name, value); 1517 } 1518 } 1519 1520 private static abstract class AnnotationInfo implements AnnotationVisitor { 1521 1522 AnnotationVisitor parent; 1523 1524 AnnotationInfo(AnnotationVisitor parent) { 1525 this.parent = parent; 1526 } 1527 1528 public void visit(String name, Object value) { 1529 parent.visit(name, value); 1530 } 1531 1532 public AnnotationVisitor visitAnnotation(String name, String desc) { 1533 return parent.visitAnnotation(name, desc); 1534 } 1535 1536 public AnnotationVisitor visitArray(String name) { 1537 return parent.visitArray(name); 1538 } 1539 1540 public void visitEnum(String name, String desc, String value) { 1541 parent.visitEnum(name, desc, value); 1542 } 1543 1544 public void visitEnd() { 1545 parent.visitEnd(); 1546 } 1547 } 1548} 1549 | Popular Tags |