1 16 package net.sf.cglib.proxy; 17 18 import java.lang.reflect.Constructor ; 19 import java.lang.reflect.InvocationTargetException ; 20 import java.lang.reflect.Method ; 21 import java.util.*; 22 import net.sf.cglib.core.*; 23 import org.objectweb.asm.Attribute; 24 import org.objectweb.asm.ClassVisitor; 25 import org.objectweb.asm.Type; 26 import org.objectweb.asm.Label; 27 28 60 public class Enhancer extends AbstractClassGenerator 61 { 62 private static final CallbackFilter ALL_ZERO = new CallbackFilter(){ 63 public int accept(Method method) { 64 return 0; 65 } 66 }; 67 68 private static final Source SOURCE = new Source(Enhancer.class.getName()); 69 private static final EnhancerKey KEY_FACTORY = 70 (EnhancerKey)KeyFactory.create(EnhancerKey.class); 71 72 private static final String BOUND_FIELD = "CGLIB$BOUND"; 73 private static final String THREAD_CALLBACKS_FIELD = "CGLIB$THREAD_CALLBACKS"; 74 private static final String STATIC_CALLBACKS_FIELD = "CGLIB$STATIC_CALLBACKS"; 75 private static final String SET_THREAD_CALLBACKS_NAME = "CGLIB$SET_THREAD_CALLBACKS"; 76 private static final String SET_STATIC_CALLBACKS_NAME = "CGLIB$SET_STATIC_CALLBACKS"; 77 private static final String CONSTRUCTED_FIELD = "CGLIB$CONSTRUCTED"; 78 79 private static final Type FACTORY = 80 TypeUtils.parseType("net.sf.cglib.proxy.Factory"); 81 private static final Type ILLEGAL_STATE_EXCEPTION = 82 TypeUtils.parseType("IllegalStateException"); 83 private static final Type ILLEGAL_ARGUMENT_EXCEPTION = 84 TypeUtils.parseType("IllegalArgumentException"); 85 private static final Type THREAD_LOCAL = 86 TypeUtils.parseType("ThreadLocal"); 87 private static final Type CALLBACK = 88 TypeUtils.parseType("net.sf.cglib.proxy.Callback"); 89 private static final Type CALLBACK_ARRAY = 90 Type.getType(Callback[].class); 91 private static final Signature CSTRUCT_NULL = 92 TypeUtils.parseConstructor(""); 93 private static final Signature SET_THREAD_CALLBACKS = 94 new Signature(SET_THREAD_CALLBACKS_NAME, Type.VOID_TYPE, new Type[]{ CALLBACK_ARRAY }); 95 private static final Signature SET_STATIC_CALLBACKS = 96 new Signature(SET_STATIC_CALLBACKS_NAME, Type.VOID_TYPE, new Type[]{ CALLBACK_ARRAY }); 97 private static final Signature NEW_INSTANCE = 98 new Signature("newInstance", Constants.TYPE_OBJECT, new Type[]{ CALLBACK_ARRAY }); 99 private static final Signature MULTIARG_NEW_INSTANCE = 100 new Signature("newInstance", Constants.TYPE_OBJECT, new Type[]{ 101 Constants.TYPE_CLASS_ARRAY, 102 Constants.TYPE_OBJECT_ARRAY, 103 CALLBACK_ARRAY, 104 }); 105 private static final Signature SINGLE_NEW_INSTANCE = 106 new Signature("newInstance", Constants.TYPE_OBJECT, new Type[]{ CALLBACK }); 107 private static final Signature SET_CALLBACK = 108 new Signature("setCallback", Type.VOID_TYPE, new Type[]{ Type.INT_TYPE, CALLBACK }); 109 private static final Signature GET_CALLBACK = 110 new Signature("getCallback", CALLBACK, new Type[]{ Type.INT_TYPE }); 111 private static final Signature SET_CALLBACKS = 112 new Signature("setCallbacks", Type.VOID_TYPE, new Type[]{ CALLBACK_ARRAY }); 113 private static final Signature GET_CALLBACKS = 114 new Signature("getCallbacks", CALLBACK_ARRAY, new Type[0]); 115 private static final Signature THREAD_LOCAL_GET = 116 TypeUtils.parseSignature("Object get()"); 117 private static final Signature THREAD_LOCAL_SET = 118 TypeUtils.parseSignature("void set(Object)"); 119 private static final Signature BIND_CALLBACKS = 120 TypeUtils.parseSignature("void CGLIB$BIND_CALLBACKS(Object)"); 121 122 123 public interface EnhancerKey { 124 public Object newInstance(String type, 125 String [] interfaces, 126 CallbackFilter filter, 127 Type[] callbackTypes, 128 boolean useFactory, 129 boolean interceptDuringConstruction, 130 Long serialVersionUID); 131 } 132 133 private Class [] interfaces; 134 private CallbackFilter filter; 135 private Callback[] callbacks; 136 private Type[] callbackTypes; 137 private boolean classOnly; 138 private Class superclass; 139 private Class [] argumentTypes; 140 private Object [] arguments; 141 private boolean useFactory = true; 142 private Long serialVersionUID; 143 private boolean interceptDuringConstruction = true; 144 145 152 public Enhancer() { 153 super(SOURCE); 154 } 155 156 165 public void setSuperclass(Class superclass) { 166 if (superclass != null && superclass.isInterface()) { 167 setInterfaces(new Class []{ superclass }); 168 } else if (superclass != null && superclass.equals(Object .class)) { 169 this.superclass = null; 171 } else { 172 this.superclass = superclass; 173 } 174 } 175 176 182 public void setInterfaces(Class [] interfaces) { 183 this.interfaces = interfaces; 184 } 185 186 194 public void setCallbackFilter(CallbackFilter filter) { 195 this.filter = filter; 196 } 197 198 199 205 public void setCallback(final Callback callback) { 206 setCallbacks(new Callback[]{ callback }); 207 } 208 209 218 public void setCallbacks(Callback[] callbacks) { 219 if (callbacks != null && callbacks.length == 0) { 220 throw new IllegalArgumentException ("Array cannot be empty"); 221 } 222 this.callbacks = callbacks; 223 } 224 225 234 public void setUseFactory(boolean useFactory) { 235 this.useFactory = useFactory; 236 } 237 238 244 public void setInterceptDuringConstruction(boolean interceptDuringConstruction) { 245 this.interceptDuringConstruction = interceptDuringConstruction; 246 } 247 248 256 public void setCallbackType(Class callbackType) { 257 setCallbackTypes(new Class []{ callbackType }); 258 } 259 260 269 public void setCallbackTypes(Class [] callbackTypes) { 270 if (callbackTypes != null && callbackTypes.length == 0) { 271 throw new IllegalArgumentException ("Array cannot be empty"); 272 } 273 this.callbackTypes = CallbackInfo.determineTypes(callbackTypes); 274 } 275 276 282 public Object create() { 283 classOnly = false; 284 argumentTypes = null; 285 return createHelper(); 286 } 287 288 297 public Object create(Class [] argumentTypes, Object [] arguments) { 298 classOnly = false; 299 if (argumentTypes == null || arguments == null || argumentTypes.length != arguments.length) { 300 throw new IllegalArgumentException ("Arguments must be non-null and of equal length"); 301 } 302 this.argumentTypes = argumentTypes; 303 this.arguments = arguments; 304 return createHelper(); 305 } 306 307 315 public Class createClass() { 316 classOnly = true; 317 return (Class )createHelper(); 318 } 319 320 324 public void setSerialVersionUID(Long sUID) { 325 serialVersionUID = sUID; 326 } 327 328 private void validate() { 329 if (classOnly ^ (callbacks == null)) { 330 if (classOnly) { 331 throw new IllegalStateException ("createClass does not accept callbacks"); 332 } else { 333 throw new IllegalStateException ("Callbacks are required"); 334 } 335 } 336 if (classOnly && (callbackTypes == null)) { 337 throw new IllegalStateException ("Callback types are required"); 338 } 339 if (callbacks != null && callbackTypes != null) { 340 if (callbacks.length != callbackTypes.length) { 341 throw new IllegalStateException ("Lengths of callback and callback types array must be the same"); 342 } 343 Type[] check = CallbackInfo.determineTypes(callbacks); 344 for (int i = 0; i < check.length; i++) { 345 if (!check[i].equals(callbackTypes[i])) { 346 throw new IllegalStateException ("Callback " + check[i] + " is not assignable to " + callbackTypes[i]); 347 } 348 } 349 } else if (callbacks != null) { 350 callbackTypes = CallbackInfo.determineTypes(callbacks); 351 } 352 if (filter == null) { 353 if (callbackTypes.length > 1) { 354 throw new IllegalStateException ("Multiple callback types possible but no filter specified"); 355 } 356 filter = ALL_ZERO; 357 } 358 if (interfaces != null) { 359 for (int i = 0; i < interfaces.length; i++) { 360 if (interfaces[i] == null) { 361 throw new IllegalStateException ("Interfaces cannot be null"); 362 } 363 if (!interfaces[i].isInterface()) { 364 throw new IllegalStateException (interfaces[i] + " is not an interface"); 365 } 366 } 367 } 368 } 369 370 private Object createHelper() { 371 validate(); 372 if (superclass != null) { 373 setNamePrefix(superclass.getName()); 374 } else if (interfaces != null) { 375 setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName()); 376 } 377 return super.create(KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, 378 ReflectUtils.getNames(interfaces), 379 filter, 380 callbackTypes, 381 useFactory, 382 interceptDuringConstruction, 383 serialVersionUID)); 384 } 385 386 protected ClassLoader getDefaultClassLoader() { 387 if (superclass != null) { 388 return superclass.getClassLoader(); 389 } else if (interfaces != null) { 390 return interfaces[0].getClassLoader(); 391 } else { 392 return null; 393 } 394 } 395 396 private Signature rename(Signature sig, int index) { 397 return new Signature("CGLIB$" + sig.getName() + "$" + index, 398 sig.getDescriptor()); 399 } 400 401 414 public static void getMethods(Class superclass, Class [] interfaces, List methods) 415 { 416 getMethods(superclass, interfaces, methods, null, null); 417 } 418 419 private static void getMethods(Class superclass, Class [] interfaces, List methods, List interfaceMethods, Set forcePublic) 420 { 421 ReflectUtils.addAllMethods(superclass, methods); 422 List target = (interfaceMethods != null) ? interfaceMethods : methods; 423 if (interfaces != null) { 424 for (int i = 0; i < interfaces.length; i++) { 425 if (interfaces[i] != Factory.class) { 426 ReflectUtils.addAllMethods(interfaces[i], target); 427 } 428 } 429 } 430 if (interfaceMethods != null) { 431 if (forcePublic != null) { 432 forcePublic.addAll(MethodWrapper.createSet(interfaceMethods)); 433 } 434 methods.addAll(interfaceMethods); 435 } 436 CollectionUtils.filter(methods, new RejectModifierPredicate(Constants.ACC_STATIC)); 437 CollectionUtils.filter(methods, new VisibilityPredicate(superclass, true)); 438 CollectionUtils.filter(methods, new DuplicatesPredicate()); 439 CollectionUtils.filter(methods, new RejectModifierPredicate(Constants.ACC_FINAL)); 440 } 441 442 public void generateClass(ClassVisitor v) throws Exception { 443 Class sc = (superclass == null) ? Object .class : superclass; 444 445 if (TypeUtils.isFinal(sc.getModifiers())) 446 throw new IllegalArgumentException ("Cannot subclass final class " + sc); 447 List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors())); 448 filterConstructors(sc, constructors); 449 450 List actualMethods = new ArrayList(); 454 List interfaceMethods = new ArrayList(); 455 final Set forcePublic = new HashSet(); 456 getMethods(sc, interfaces, actualMethods, interfaceMethods, forcePublic); 457 458 List methods = CollectionUtils.transform(actualMethods, new Transformer() { 459 public Object transform(Object value) { 460 Method method = (Method )value; 461 int modifiers = Constants.ACC_FINAL 462 | (method.getModifiers() 463 & ~Constants.ACC_ABSTRACT 464 & ~Constants.ACC_NATIVE 465 & ~Constants.ACC_SYNCHRONIZED); 466 if (forcePublic.contains(MethodWrapper.create(method))) { 467 modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC; 468 } 469 return ReflectUtils.getMethodInfo(method, modifiers); 470 } 471 }); 472 473 ClassEmitter e = new ClassEmitter(v); 474 e.begin_class(Constants.V1_2, 475 Constants.ACC_PUBLIC, 476 getClassName(), 477 Type.getType(sc), 478 (useFactory ? 479 TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY) : 480 TypeUtils.getTypes(interfaces)), 481 Constants.SOURCE_FILE); 482 List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance()); 483 484 e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null); 485 if (!interceptDuringConstruction) { 486 e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null); 487 } 488 e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null); 489 e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null); 490 if (serialVersionUID != null) { 491 e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID); 492 } 493 494 for (int i = 0; i < callbackTypes.length; i++) { 495 e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null); 496 } 497 498 emitMethods(e, methods, actualMethods); 499 emitConstructors(e, constructorInfo); 500 emitSetThreadCallbacks(e); 501 emitSetStaticCallbacks(e); 502 emitBindCallbacks(e); 503 504 if (useFactory) { 505 int[] keys = getCallbackKeys(); 506 emitNewInstanceCallbacks(e); 507 emitNewInstanceCallback(e); 508 emitNewInstanceMultiarg(e, constructorInfo); 509 emitGetCallback(e, keys); 510 emitSetCallback(e, keys); 511 emitGetCallbacks(e); 512 emitSetCallbacks(e); 513 } 514 515 e.end_class(); 516 } 517 518 528 protected void filterConstructors(Class sc, List constructors) { 529 CollectionUtils.filter(constructors, new VisibilityPredicate(sc, true)); 530 if (constructors.size() == 0) 531 throw new IllegalArgumentException ("No visible constructors in " + sc); 532 } 533 534 protected Object firstInstance(Class type) throws Exception { 535 if (classOnly) { 536 return type; 537 } else { 538 return createUsingReflection(type); 539 } 540 } 541 542 protected Object nextInstance(Object instance) { 543 Class protoclass = (instance instanceof Class ) ? (Class )instance : instance.getClass(); 544 if (classOnly) { 545 return protoclass; 546 } else if (instance instanceof Factory) { 547 if (argumentTypes != null) { 548 return ((Factory)instance).newInstance(argumentTypes, arguments, callbacks); 549 } else { 550 return ((Factory)instance).newInstance(callbacks); 551 } 552 } else { 553 return createUsingReflection(protoclass); 554 } 555 } 556 557 577 public static void registerCallbacks(Class generatedClass, Callback[] callbacks) { 578 setThreadCallbacks(generatedClass, callbacks); 579 } 580 581 590 public static void registerStaticCallbacks(Class generatedClass, Callback[] callbacks) { 591 setCallbacksHelper(generatedClass, callbacks, SET_STATIC_CALLBACKS_NAME); 592 } 593 594 599 public static boolean isEnhanced(Class type) { 600 try { 601 getCallbacksSetter(type, SET_THREAD_CALLBACKS_NAME); 602 return true; 603 } catch (NoSuchMethodException e) { 604 return false; 605 } 606 } 607 608 private static void setThreadCallbacks(Class type, Callback[] callbacks) { 609 setCallbacksHelper(type, callbacks, SET_THREAD_CALLBACKS_NAME); 610 } 611 612 private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName) { 613 try { 615 Method setter = getCallbacksSetter(type, methodName); 616 setter.invoke(null, new Object []{ callbacks }); 617 } catch (NoSuchMethodException e) { 618 throw new IllegalArgumentException (type + " is not an enhanced class"); 619 } catch (IllegalAccessException e) { 620 throw new CodeGenerationException(e); 621 } catch (InvocationTargetException e) { 622 throw new CodeGenerationException(e); 623 } 624 } 625 626 private static Method getCallbacksSetter(Class type, String methodName) throws NoSuchMethodException { 627 return type.getDeclaredMethod(methodName, new Class []{ Callback[].class }); 628 } 629 630 private Object createUsingReflection(Class type) { 631 setThreadCallbacks(type, callbacks); 632 try{ 633 634 if (argumentTypes != null) { 635 636 return ReflectUtils.newInstance(type, argumentTypes, arguments); 637 638 } else { 639 640 return ReflectUtils.newInstance(type); 641 642 } 643 }finally{ 644 setThreadCallbacks(type, null); 646 } 647 } 648 649 656 public static Object create(Class type, Callback callback) { 657 Enhancer e = new Enhancer(); 658 e.setSuperclass(type); 659 e.setCallback(callback); 660 return e.create(); 661 } 662 663 671 public static Object create(Class superclass, Class interfaces[], Callback callback) { 672 Enhancer e = new Enhancer(); 673 e.setSuperclass(superclass); 674 e.setInterfaces(interfaces); 675 e.setCallback(callback); 676 return e.create(); 677 } 678 679 688 public static Object create(Class superclass, Class [] interfaces, CallbackFilter filter, Callback[] callbacks) { 689 Enhancer e = new Enhancer(); 690 e.setSuperclass(superclass); 691 e.setInterfaces(interfaces); 692 e.setCallbackFilter(filter); 693 e.setCallbacks(callbacks); 694 return e.create(); 695 } 696 697 private void emitConstructors(ClassEmitter ce, List constructors) { 698 boolean seenNull = false; 699 for (Iterator it = constructors.iterator(); it.hasNext();) { 700 MethodInfo constructor = (MethodInfo)it.next(); 701 CodeEmitter e = EmitUtils.begin_method(ce, constructor, Constants.ACC_PUBLIC); 702 e.load_this(); 703 e.dup(); 704 e.load_args(); 705 Signature sig = constructor.getSignature(); 706 seenNull = seenNull || sig.getDescriptor().equals("()V"); 707 e.super_invoke_constructor(sig); 708 e.invoke_static_this(BIND_CALLBACKS); 709 if (!interceptDuringConstruction) { 710 e.load_this(); 711 e.push(1); 712 e.putfield(CONSTRUCTED_FIELD); 713 } 714 e.return_value(); 715 e.end_method(); 716 } 717 if (!classOnly && !seenNull && arguments == null) 718 throw new IllegalArgumentException ("Superclass has no null constructors but no arguments were given"); 719 } 720 721 private int[] getCallbackKeys() { 722 int[] keys = new int[callbackTypes.length]; 723 for (int i = 0; i < callbackTypes.length; i++) { 724 keys[i] = i; 725 } 726 return keys; 727 } 728 729 private void emitGetCallback(ClassEmitter ce, int[] keys) { 730 final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, GET_CALLBACK, null); 731 e.load_this(); 732 e.invoke_static_this(BIND_CALLBACKS); 733 e.load_this(); 734 e.load_arg(0); 735 e.process_switch(keys, new ProcessSwitchCallback() { 736 public void processCase(int key, Label end) { 737 e.getfield(getCallbackField(key)); 738 e.goTo(end); 739 } 740 public void processDefault() { 741 e.pop(); e.aconst_null(); 743 } 744 }); 745 e.return_value(); 746 e.end_method(); 747 } 748 749 private void emitSetCallback(ClassEmitter ce, int[] keys) { 750 final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, SET_CALLBACK, null); 751 e.load_arg(0); 752 e.process_switch(keys, new ProcessSwitchCallback() { 753 public void processCase(int key, Label end) { 754 e.load_this(); 755 e.load_arg(1); 756 e.checkcast(callbackTypes[key]); 757 e.putfield(getCallbackField(key)); 758 e.goTo(end); 759 } 760 public void processDefault() { 761 } 763 }); 764 e.return_value(); 765 e.end_method(); 766 } 767 768 private void emitSetCallbacks(ClassEmitter ce) { 769 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, SET_CALLBACKS, null); 770 e.load_this(); 771 e.load_arg(0); 772 for (int i = 0; i < callbackTypes.length; i++) { 773 e.dup2(); 774 e.aaload(i); 775 e.checkcast(callbackTypes[i]); 776 e.putfield(getCallbackField(i)); 777 } 778 e.return_value(); 779 e.end_method(); 780 } 781 782 private void emitGetCallbacks(ClassEmitter ce) { 783 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, GET_CALLBACKS, null); 784 e.load_this(); 785 e.invoke_static_this(BIND_CALLBACKS); 786 e.load_this(); 787 e.push(callbackTypes.length); 788 e.newarray(CALLBACK); 789 for (int i = 0; i < callbackTypes.length; i++) { 790 e.dup(); 791 e.push(i); 792 e.load_this(); 793 e.getfield(getCallbackField(i)); 794 e.aastore(); 795 } 796 e.return_value(); 797 e.end_method(); 798 } 799 800 private void emitNewInstanceCallbacks(ClassEmitter ce) { 801 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null); 802 e.load_arg(0); 803 e.invoke_static_this(SET_THREAD_CALLBACKS); 804 emitCommonNewInstance(e); 805 } 806 807 private void emitCommonNewInstance(CodeEmitter e) { 808 e.new_instance_this(); 809 e.dup(); 810 e.invoke_constructor_this(); 811 e.aconst_null(); 812 e.invoke_static_this(SET_THREAD_CALLBACKS); 813 e.return_value(); 814 e.end_method(); 815 } 816 817 private void emitNewInstanceCallback(ClassEmitter ce) { 818 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, SINGLE_NEW_INSTANCE, null); 819 switch (callbackTypes.length) { 820 case 0: 821 break; 823 case 1: 824 e.push(1); 826 e.newarray(CALLBACK); 827 e.dup(); 828 e.push(0); 829 e.load_arg(0); 830 e.aastore(); 831 e.invoke_static_this(SET_THREAD_CALLBACKS); 832 break; 833 default: 834 e.throw_exception(ILLEGAL_STATE_EXCEPTION, "More than one callback object required"); 835 } 836 emitCommonNewInstance(e); 837 } 838 839 private void emitNewInstanceMultiarg(ClassEmitter ce, List constructors) { 840 final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, MULTIARG_NEW_INSTANCE, null); 841 e.load_arg(2); 842 e.invoke_static_this(SET_THREAD_CALLBACKS); 843 e.new_instance_this(); 844 e.dup(); 845 e.load_arg(0); 846 EmitUtils.constructor_switch(e, constructors, new ObjectSwitchCallback() { 847 public void processCase(Object key, Label end) { 848 MethodInfo constructor = (MethodInfo)key; 849 Type types[] = constructor.getSignature().getArgumentTypes(); 850 for (int i = 0; i < types.length; i++) { 851 e.load_arg(1); 852 e.push(i); 853 e.aaload(); 854 e.unbox(types[i]); 855 } 856 e.invoke_constructor_this(constructor.getSignature()); 857 e.goTo(end); 858 } 859 public void processDefault() { 860 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Constructor not found"); 861 } 862 }); 863 e.aconst_null(); 864 e.invoke_static_this(SET_THREAD_CALLBACKS); 865 e.return_value(); 866 e.end_method(); 867 } 868 869 private void emitMethods(final ClassEmitter ce, List methods, List actualMethods) { 870 CallbackGenerator[] generators = CallbackInfo.getGenerators(callbackTypes); 871 872 Map groups = new HashMap(); 873 final Map indexes = new HashMap(); 874 final Map originalModifiers = new HashMap(); 875 final Map positions = CollectionUtils.getIndexMap(methods); 876 877 Iterator it1 = methods.iterator(); 878 Iterator it2 = (actualMethods != null) ? actualMethods.iterator() : null; 879 880 while (it1.hasNext()) { 881 MethodInfo method = (MethodInfo)it1.next(); 882 Method actualMethod = (it2 != null) ? (Method )it2.next() : null; 883 int index = filter.accept(actualMethod); 884 if (index >= callbackTypes.length) { 885 throw new IllegalArgumentException ("Callback filter returned an index that is too large: " + index); 886 } 887 originalModifiers.put(method, new Integer ((actualMethod != null) ? actualMethod.getModifiers() : method.getModifiers())); 888 indexes.put(method, new Integer (index)); 889 List group = (List)groups.get(generators[index]); 890 if (group == null) { 891 groups.put(generators[index], group = new ArrayList(methods.size())); 892 } 893 group.add(method); 894 } 895 896 Set seenGen = new HashSet(); 897 CodeEmitter se = ce.getStaticHook(); 898 se.new_instance(THREAD_LOCAL); 899 se.dup(); 900 se.invoke_constructor(THREAD_LOCAL, CSTRUCT_NULL); 901 se.putfield(THREAD_CALLBACKS_FIELD); 902 903 final Object [] state = new Object [1]; 904 CallbackGenerator.Context context = new CallbackGenerator.Context() { 905 public ClassLoader getClassLoader() { 906 return Enhancer.this.getClassLoader(); 907 } 908 public int getOriginalModifiers(MethodInfo method) { 909 return ((Integer )originalModifiers.get(method)).intValue(); 910 } 911 public int getIndex(MethodInfo method) { 912 return ((Integer )indexes.get(method)).intValue(); 913 } 914 public void emitCallback(CodeEmitter e, int index) { 915 emitCurrentCallback(e, index); 916 } 917 public Signature getImplSignature(MethodInfo method) { 918 return rename(method.getSignature(), ((Integer )positions.get(method)).intValue()); 919 } 920 public CodeEmitter beginMethod(ClassEmitter ce, MethodInfo method) { 921 CodeEmitter e = EmitUtils.begin_method(ce, method); 922 if (!interceptDuringConstruction && 923 !TypeUtils.isAbstract(method.getModifiers())) { 924 Label constructed = e.make_label(); 925 e.load_this(); 926 e.getfield(CONSTRUCTED_FIELD); 927 e.if_jump(e.NE, constructed); 928 e.load_this(); 929 e.load_args(); 930 e.super_invoke(); 931 e.return_value(); 932 e.mark(constructed); 933 } 934 return e; 935 } 936 }; 937 for (int i = 0; i < callbackTypes.length; i++) { 938 CallbackGenerator gen = generators[i]; 939 if (!seenGen.contains(gen)) { 940 seenGen.add(gen); 941 final List fmethods = (List)groups.get(gen); 942 if (fmethods != null) { 943 try { 944 gen.generate(ce, context, fmethods); 945 gen.generateStatic(se, context, fmethods); 946 } catch (RuntimeException x) { 947 throw x; 948 } catch (Exception x) { 949 throw new CodeGenerationException(x); 950 } 951 } 952 } 953 } 954 se.return_value(); 955 se.end_method(); 956 } 957 958 private void emitSetThreadCallbacks(ClassEmitter ce) { 959 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC, 960 SET_THREAD_CALLBACKS, 961 null); 962 e.getfield(THREAD_CALLBACKS_FIELD); 963 e.load_arg(0); 964 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_SET); 965 e.return_value(); 966 e.end_method(); 967 } 968 969 private void emitSetStaticCallbacks(ClassEmitter ce) { 970 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC, 971 SET_STATIC_CALLBACKS, 972 null); 973 e.load_arg(0); 974 e.putfield(STATIC_CALLBACKS_FIELD); 975 e.return_value(); 976 e.end_method(); 977 } 978 979 private void emitCurrentCallback(CodeEmitter e, int index) { 980 e.load_this(); 981 e.getfield(getCallbackField(index)); 982 e.dup(); 983 Label end = e.make_label(); 984 e.ifnonnull(end); 985 e.pop(); e.load_this(); 987 e.invoke_static_this(BIND_CALLBACKS); 988 e.load_this(); 989 e.getfield(getCallbackField(index)); 990 e.mark(end); 991 } 992 993 private void emitBindCallbacks(ClassEmitter ce) { 994 CodeEmitter e = ce.begin_method(Constants.PRIVATE_FINAL_STATIC, 995 BIND_CALLBACKS, 996 null); 997 Local me = e.make_local(); 998 e.load_arg(0); 999 e.checkcast_this(); 1000 e.store_local(me); 1001 1002 Label end = e.make_label(); 1003 e.load_local(me); 1004 e.getfield(BOUND_FIELD); 1005 e.if_jump(e.NE, end); 1006 e.load_local(me); 1007 e.push(1); 1008 e.putfield(BOUND_FIELD); 1009 1010 e.getfield(THREAD_CALLBACKS_FIELD); 1011 e.invoke_virtual(THREAD_LOCAL, THREAD_LOCAL_GET); 1012 e.dup(); 1013 Label found_callback = e.make_label(); 1014 e.ifnonnull(found_callback); 1015 e.pop(); 1016 1017 e.getfield(STATIC_CALLBACKS_FIELD); 1018 e.dup(); 1019 e.ifnonnull(found_callback); 1020 e.pop(); 1021 e.goTo(end); 1022 1023 e.mark(found_callback); 1024 e.checkcast(CALLBACK_ARRAY); 1025 e.load_local(me); 1026 e.swap(); 1027 for (int i = callbackTypes.length - 1; i >= 0; i--) { 1028 if (i != 0) { 1029 e.dup2(); 1030 } 1031 e.aaload(i); 1032 e.checkcast(callbackTypes[i]); 1033 e.putfield(getCallbackField(i)); 1034 } 1035 1036 e.mark(end); 1037 e.return_value(); 1038 e.end_method(); 1039 } 1040 1041 private static String getCallbackField(int index) { 1042 return "CGLIB$CALLBACK_" + index; 1043 } 1044} 1045 | Popular Tags |