1
16
17 package javassist.util.proxy;
18
19 import java.lang.ref.Reference;
20 import java.lang.ref.WeakReference;
21 import java.lang.reflect.Constructor;
22 import java.lang.reflect.Field;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Member;
25 import java.lang.reflect.Method;
26 import java.lang.reflect.Modifier;
27 import java.security.ProtectionDomain;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.Comparator;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.WeakHashMap;
38 import java.lang.invoke.MethodHandles.Lookup;
39
40 import javassist.CannotCompileException;
41 import javassist.bytecode.AccessFlag;
42 import javassist.bytecode.Bytecode;
43 import javassist.bytecode.ClassFile;
44 import javassist.bytecode.CodeAttribute;
45 import javassist.bytecode.ConstPool;
46 import javassist.bytecode.Descriptor;
47 import javassist.bytecode.DuplicateMemberException;
48 import javassist.bytecode.ExceptionsAttribute;
49 import javassist.bytecode.FieldInfo;
50 import javassist.bytecode.MethodInfo;
51 import javassist.bytecode.Opcode;
52 import javassist.bytecode.StackMapTable;
53
54
58
59
177 public class ProxyFactory {
178 private Class<?> superClass;
179 private Class<?>[] interfaces;
180 private MethodFilter methodFilter;
181 private MethodHandler handler;
182 private List<Map.Entry<String,Method>> signatureMethods;
183 private boolean hasGetHandler;
184 private byte[] signature;
185 private String classname;
186 private String basename;
187 private String superName;
188 private Class<?> thisClass;
189
192 private boolean factoryUseCache;
193
196 private boolean factoryWriteReplace;
197
198
220 public static boolean onlyPublicMethods = false;
221
222
231 public String writeDirectory;
232
233 private static final Class<?> OBJECT_TYPE = Object.class;
234
235 private static final String HOLDER = "_methods_";
236 private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;";
237 private static final String FILTER_SIGNATURE_FIELD = "_filter_signature";
238 private static final String FILTER_SIGNATURE_TYPE = "[B";
239 private static final String HANDLER = "handler";
240 private static final String NULL_INTERCEPTOR_HOLDER = "javassist.util.proxy.RuntimeSupport";
241 private static final String DEFAULT_INTERCEPTOR = "default_interceptor";
242 private static final String HANDLER_TYPE
243 = 'L' + MethodHandler.class.getName().replace('.', '/') + ';';
244 private static final String HANDLER_SETTER = "setHandler";
245 private static final String HANDLER_SETTER_TYPE = "(" + HANDLER_TYPE + ")V";
246
247 private static final String HANDLER_GETTER = "getHandler";
248 private static final String HANDLER_GETTER_TYPE = "()" + HANDLER_TYPE;
249
250 private static final String SERIAL_VERSION_UID_FIELD = "serialVersionUID";
251 private static final String SERIAL_VERSION_UID_TYPE = "J";
252 private static final long SERIAL_VERSION_UID_VALUE = -1L;
253
254
265 public static volatile boolean useCache = true;
266
267
286 public static volatile boolean useWriteReplace = true;
287
288
291
292
296 public boolean isUseCache()
297 {
298 return factoryUseCache;
299 }
300
301
306 public void setUseCache(boolean useCache)
307 {
308
309
310 if (handler != null && useCache) {
311 throw new RuntimeException("caching cannot be enabled if the factory default interceptor has been set");
312 }
313 factoryUseCache = useCache;
314 }
315
316
320 public boolean isUseWriteReplace()
321 {
322 return factoryWriteReplace;
323 }
324
325
330 public void setUseWriteReplace(boolean useWriteReplace)
331 {
332 factoryWriteReplace = useWriteReplace;
333 }
334
335 private static Map<ClassLoader,Map<String,ProxyDetails>> proxyCache =
336 new WeakHashMap<ClassLoader,Map<String,ProxyDetails>>();
337
338
343 public static boolean isProxyClass(Class<?> cl)
344 {
345
346 return (Proxy.class.isAssignableFrom(cl));
347 }
348
349
354 static class ProxyDetails {
355
360 byte[] signature;
361
365 Reference<Class<?>> proxyClass;
366
370 boolean isUseWriteReplace;
371
372 ProxyDetails(byte[] signature, Class<?> proxyClass, boolean isUseWriteReplace)
373 {
374 this.signature = signature;
375 this.proxyClass = new WeakReference<Class<?>>(proxyClass);
376 this.isUseWriteReplace = isUseWriteReplace;
377 }
378 }
379
380
383 public ProxyFactory() {
384 superClass = null;
385 interfaces = null;
386 methodFilter = null;
387 handler = null;
388 signature = null;
389 signatureMethods = null;
390 hasGetHandler = false;
391 thisClass = null;
392 writeDirectory = null;
393 factoryUseCache = useCache;
394 factoryWriteReplace = useWriteReplace;
395 }
396
397
400 public void setSuperclass(Class<?> clazz) {
401 superClass = clazz;
402
403 signature = null;
404 }
405
406
411 public Class<?> getSuperclass() { return superClass; }
412
413
416 public void setInterfaces(Class<?>[] ifs) {
417 interfaces = ifs;
418
419 signature = null;
420 }
421
422
427 public Class<?>[] getInterfaces() { return interfaces; }
428
429
432 public void setFilter(MethodFilter mf) {
433 methodFilter = mf;
434
435 signature = null;
436 }
437
438
445 public Class<?> createClass() {
446 if (signature == null) {
447 computeSignature(methodFilter);
448 }
449 return createClass1(null);
450 }
451
452
457 public Class<?> createClass(MethodFilter filter) {
458 computeSignature(filter);
459 return createClass1(null);
460 }
461
462
467 Class<?> createClass(byte[] signature)
468 {
469 installSignature(signature);
470 return createClass1(null);
471 }
472
473
481 public Class<?> createClass(Lookup lookup) {
482 if (signature == null) {
483 computeSignature(methodFilter);
484 }
485 return createClass1(lookup);
486 }
487
488
497 public Class<?> createClass(Lookup lookup, MethodFilter filter) {
498 computeSignature(filter);
499 return createClass1(lookup);
500 }
501
502
511 Class<?> createClass(Lookup lookup, byte[] signature)
512 {
513 installSignature(signature);
514 return createClass1(lookup);
515 }
516
517 private Class<?> createClass1(Lookup lookup) {
518 Class<?> result = thisClass;
519 if (result == null) {
520 ClassLoader cl = getClassLoader();
521 synchronized (proxyCache) {
522 if (factoryUseCache)
523 createClass2(cl, lookup);
524 else
525 createClass3(cl, lookup);
526
527 result = thisClass;
528
529 thisClass = null;
530 }
531 }
532
533 return result;
534 }
535
536 private static char[] hexDigits =
537 { '0', '1', '2', '3', '4', '5', '6', '7',
538 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
539
540 public String getKey(Class<?> superClass, Class<?>[] interfaces, byte[] signature, boolean useWriteReplace)
541 {
542 StringBuffer sbuf = new StringBuffer();
543 if (superClass != null){
544 sbuf.append(superClass.getName());
545 }
546 sbuf.append(":");
547 for (int i = 0; i < interfaces.length; i++) {
548 sbuf.append(interfaces[i].getName());
549 sbuf.append(":");
550 }
551 for (int i = 0; i < signature.length; i++) {
552 byte b = signature[i];
553 int lo = b & 0xf;
554 int hi = (b >> 4) & 0xf;
555 sbuf.append(hexDigits[lo]);
556 sbuf.append(hexDigits[hi]);
557 }
558 if (useWriteReplace) {
559 sbuf.append(":w");
560 }
561
562 return sbuf.toString();
563 }
564
565 private void createClass2(ClassLoader cl, Lookup lookup) {
566 String key = getKey(superClass, interfaces, signature, factoryWriteReplace);
567
572
573 Map<String,ProxyDetails> cacheForTheLoader = proxyCache.get(cl);
574 ProxyDetails details;
575 if (cacheForTheLoader == null) {
576 cacheForTheLoader = new HashMap<String,ProxyDetails>();
577 proxyCache.put(cl, cacheForTheLoader);
578 }
579 details = cacheForTheLoader.get(key);
580 if (details != null) {
581 Reference<Class<?>> reference = details.proxyClass;
582 thisClass = reference.get();
583 if (thisClass != null) {
584 return;
585 }
586 }
587 createClass3(cl, lookup);
588 details = new ProxyDetails(signature, thisClass, factoryWriteReplace);
589 cacheForTheLoader.put(key, details);
590
591 }
592
593 private void createClass3(ClassLoader cl, Lookup lookup) {
594
595 allocateClassName();
596
597 try {
598 ClassFile cf = make();
599 if (writeDirectory != null)
600 FactoryHelper.writeFile(cf, writeDirectory);
601
602 if (lookup == null)
603 thisClass = FactoryHelper.toClass(cf, getClassInTheSamePackage(), cl, getDomain());
604 else
605 thisClass = FactoryHelper.toClass(cf, lookup);
606
607 setField(FILTER_SIGNATURE_FIELD, signature);
608
609 if (!factoryUseCache) {
610 setField(DEFAULT_INTERCEPTOR, handler);
611 }
612 }
613 catch (CannotCompileException e) {
614 throw new RuntimeException(e.getMessage(), e);
615 }
616
617 }
618
619
624 private Class<?> getClassInTheSamePackage() {
625 if (superClass != null && superClass != OBJECT_TYPE)
626 return superClass;
627 else if (interfaces != null && interfaces.length > 0)
628 return interfaces[0];
629 else
630 return this.getClass();
631 }
632
633 private void setField(String fieldName, Object value) {
634 if (thisClass != null && value != null)
635 try {
636 Field f = thisClass.getField(fieldName);
637 SecurityActions.setAccessible(f, true);
638 f.set(null, value);
639 SecurityActions.setAccessible(f, false);
640 }
641 catch (Exception e) {
642 throw new RuntimeException(e);
643 }
644 }
645
646 static byte[] getFilterSignature(Class<?> clazz) {
647 return (byte[])getField(clazz, FILTER_SIGNATURE_FIELD);
648 }
649
650 private static Object getField(Class<?> clazz, String fieldName) {
651 try {
652 Field f = clazz.getField(fieldName);
653 f.setAccessible(true);
654 Object value = f.get(null);
655 f.setAccessible(false);
656 return value;
657 }
658 catch (Exception e) {
659 throw new RuntimeException(e);
660 }
661 }
662
663
670 public static MethodHandler getHandler(Proxy p) {
671 try {
672 Field f = p.getClass().getDeclaredField(HANDLER);
673 f.setAccessible(true);
674 Object value = f.get(p);
675 f.setAccessible(false);
676 return (MethodHandler)value;
677 }
678 catch (Exception e) {
679 throw new RuntimeException(e);
680 }
681 }
682
683
689 public static interface ClassLoaderProvider {
690
695 public ClassLoader get(ProxyFactory pf);
696 }
697
698
718 public static ClassLoaderProvider classLoaderProvider =
719 new ClassLoaderProvider() {
720 @Override
721 public ClassLoader get(ProxyFactory pf) {
722 return pf.getClassLoader0();
723 }
724 };
725
726 protected ClassLoader getClassLoader() {
727 return classLoaderProvider.get(this);
728 }
729
730 protected ClassLoader getClassLoader0() {
731 ClassLoader loader = null;
732 if (superClass != null && !superClass.getName().equals("java.lang.Object"))
733 loader = superClass.getClassLoader();
734 else if (interfaces != null && interfaces.length > 0)
735 loader = interfaces[0].getClassLoader();
736
737 if (loader == null) {
738 loader = getClass().getClassLoader();
739
740 if (loader == null) {
741 loader = Thread.currentThread().getContextClassLoader();
742 if (loader == null)
743 loader = ClassLoader.getSystemClassLoader();
744 }
745 }
746
747 return loader;
748 }
749
750 protected ProtectionDomain getDomain() {
751 Class<?> clazz;
752 if (superClass != null && !superClass.getName().equals("java.lang.Object"))
753 clazz = superClass;
754 else if (interfaces != null && interfaces.length > 0)
755 clazz = interfaces[0];
756 else
757 clazz = this.getClass();
758
759 return clazz.getProtectionDomain();
760 }
761
762
770 public Object create(Class<?>[] paramTypes, Object[] args, MethodHandler mh)
771 throws NoSuchMethodException, IllegalArgumentException,
772 InstantiationException, IllegalAccessException, InvocationTargetException
773 {
774 Object obj = create(paramTypes, args);
775 ((Proxy)obj).setHandler(mh);
776 return obj;
777 }
778
779
785 public Object create(Class<?>[] paramTypes, Object[] args)
786 throws NoSuchMethodException, IllegalArgumentException,
787 InstantiationException, IllegalAccessException, InvocationTargetException
788 {
789 Class<?> c = createClass();
790 Constructor<?> cons = c.getConstructor(paramTypes);
791 return cons.newInstance(args);
792 }
793
794
804 @Deprecated
805 public void setHandler(MethodHandler mi) {
806
807 if (factoryUseCache && mi != null) {
808 factoryUseCache = false;
809
810 thisClass = null;
811 }
812 handler = mi;
813
814
815 setField(DEFAULT_INTERCEPTOR, handler);
816 }
817
818
821 public static interface UniqueName {
822
827 String get(String classname);
828 }
829
830
837 public static UniqueName nameGenerator = new UniqueName() {
838 private final String sep = "_$$_jvst" + Integer.toHexString(this.hashCode() & 0xfff) + "_";
839 private int counter = 0;
840
841 @Override
842 public String get(String classname) {
843 return classname + sep + Integer.toHexString(counter++);
844 }
845 };
846
847 private static String makeProxyName(String classname) {
848 synchronized (nameGenerator) {
849 return nameGenerator.get(classname);
850 }
851 }
852
853 private ClassFile make() throws CannotCompileException {
854 ClassFile cf = new ClassFile(false, classname, superName);
855 cf.setAccessFlags(AccessFlag.PUBLIC);
856 setInterfaces(cf, interfaces, hasGetHandler ? Proxy.class : ProxyObject.class);
857 ConstPool pool = cf.getConstPool();
858
859
860 if (!factoryUseCache) {
861 FieldInfo finfo = new FieldInfo(pool, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
862 finfo.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
863 cf.addField(finfo);
864 }
865
866
867 FieldInfo finfo2 = new FieldInfo(pool, HANDLER, HANDLER_TYPE);
868 finfo2.setAccessFlags(AccessFlag.PRIVATE);
869 cf.addField(finfo2);
870
871
872 FieldInfo finfo3 = new FieldInfo(pool, FILTER_SIGNATURE_FIELD, FILTER_SIGNATURE_TYPE);
873 finfo3.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
874 cf.addField(finfo3);
875
876
877 FieldInfo finfo4 = new FieldInfo(pool, SERIAL_VERSION_UID_FIELD, SERIAL_VERSION_UID_TYPE);
878 finfo4.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC| AccessFlag.FINAL);
879 cf.addField(finfo4);
880
881
882
883 makeConstructors(classname, cf, pool, classname);
884
885 List<Find2MethodsArgs> forwarders = new ArrayList<Find2MethodsArgs>();
886 int s = overrideMethods(cf, pool, classname, forwarders);
887 addClassInitializer(cf, pool, classname, s, forwarders);
888 addSetter(classname, cf, pool);
889 if (!hasGetHandler)
890 addGetter(classname, cf, pool);
891
892 if (factoryWriteReplace) {
893 try {
894 cf.addMethod(makeWriteReplace(pool));
895 }
896 catch (DuplicateMemberException e) {
897
898 }
899 }
900
901 thisClass = null;
902 return cf;
903 }
904
905 private void checkClassAndSuperName() {
906 if (interfaces == null)
907 interfaces = new Class[0];
908
909 if (superClass == null) {
910 superClass = OBJECT_TYPE;
911 superName = superClass.getName();
912 basename = interfaces.length == 0 ? superName
913 : interfaces[0].getName();
914 } else {
915 superName = superClass.getName();
916 basename = superName;
917 }
918
919 if (Modifier.isFinal(superClass.getModifiers()))
920 throw new RuntimeException(superName + " is final");
921
922 if (basename.startsWith("java.") || onlyPublicMethods)
923 basename = "javassist.util.proxy." + basename.replace('.', '_');
924 }
925
926 private void allocateClassName() {
927 classname = makeProxyName(basename);
928 }
929
930 private static Comparator<Map.Entry<String,Method>> sorter =
931 new Comparator<Map.Entry<String,Method>>() {
932 @Override
933 public int compare(Map.Entry<String,Method> e1, Map.Entry<String,Method> e2) {
934 return e1.getKey().compareTo(e2.getKey());
935 }
936 };
937
938 private void makeSortedMethodList() {
939 checkClassAndSuperName();
940
941 hasGetHandler = false;
942 Map<String,Method> allMethods = getMethods(superClass, interfaces);
943 signatureMethods = new ArrayList<Map.Entry<String,Method>>(allMethods.entrySet());
944 Collections.sort(signatureMethods, sorter);
945 }
946
947 private void computeSignature(MethodFilter filter)
948 {
949 makeSortedMethodList();
950
951 int l = signatureMethods.size();
952 int maxBytes = ((l + 7) >> 3);
953 signature = new byte[maxBytes];
954 for (int idx = 0; idx < l; idx++)
955 {
956 Method m = signatureMethods.get(idx).getValue();
957 int mod = m.getModifiers();
958 if (!Modifier.isFinal(mod) && !Modifier.isStatic(mod)
959 && isVisible(mod, basename, m) && (filter == null || filter.isHandled(m))) {
960 setBit(signature, idx);
961 }
962 }
963 }
964
965 private void installSignature(byte[] signature)
966 {
967 makeSortedMethodList();
968
969 int l = signatureMethods.size();
970 int maxBytes = ((l + 7) >> 3);
971 if (signature.length != maxBytes) {
972 throw new RuntimeException("invalid filter signature length for deserialized proxy class");
973 }
974
975 this.signature = signature;
976 }
977
978 private boolean testBit(byte[] signature, int idx) {
979 int byteIdx = idx >> 3;
980 if (byteIdx > signature.length)
981 return false;
982 int bitIdx = idx & 0x7;
983 int mask = 0x1 << bitIdx;
984 int sigByte = signature[byteIdx];
985 return ((sigByte & mask) != 0);
986 }
987
988 private void setBit(byte[] signature, int idx) {
989 int byteIdx = idx >> 3;
990 if (byteIdx < signature.length) {
991 int bitIdx = idx & 0x7;
992 int mask = 0x1 << bitIdx;
993 int sigByte = signature[byteIdx];
994 signature[byteIdx] = (byte)(sigByte | mask);
995 }
996 }
997
998 private static void setInterfaces(ClassFile cf, Class<?>[] interfaces, Class<?> proxyClass) {
999 String setterIntf = proxyClass.getName();
1000 String[] list;
1001 if (interfaces == null || interfaces.length == 0)
1002 list = new String[] { setterIntf };
1003 else {
1004 list = new String[interfaces.length + 1];
1005 for (int i = 0; i < interfaces.length; i++)
1006 list[i] = interfaces[i].getName();
1007
1008 list[interfaces.length] = setterIntf;
1009 }
1010
1011 cf.setInterfaces(list);
1012 }
1013
1014 private static void addClassInitializer(ClassFile cf, ConstPool cp,
1015 String classname, int size, List<Find2MethodsArgs> forwarders)
1016 throws CannotCompileException
1017 {
1018 FieldInfo finfo = new FieldInfo(cp, HOLDER, HOLDER_TYPE);
1019 finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.STATIC);
1020 cf.addField(finfo);
1021 MethodInfo minfo = new MethodInfo(cp, "<clinit>", "()V");
1022 minfo.setAccessFlags(AccessFlag.STATIC);
1023 setThrows(minfo, cp, new Class<?>[] { ClassNotFoundException.class });
1024
1025 Bytecode code = new Bytecode(cp, 0, 2);
1026 code.addIconst(size * 2);
1027 code.addAnewarray("java.lang.reflect.Method");
1028 final int varArray = 0;
1029 code.addAstore(varArray);
1030
1031
1032
1033 code.addLdc(classname);
1034 code.addInvokestatic("java.lang.Class",
1035 "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
1036 final int varClass = 1;
1037 code.addAstore(varClass);
1038
1039 for (Find2MethodsArgs args:forwarders)
1040 callFind2Methods(code, args.methodName, args.delegatorName,
1041 args.origIndex, args.descriptor, varClass, varArray);
1042
1043 code.addAload(varArray);
1044 code.addPutstatic(classname, HOLDER, HOLDER_TYPE);
1045
1046 code.addLconst(SERIAL_VERSION_UID_VALUE);
1047 code.addPutstatic(classname, SERIAL_VERSION_UID_FIELD, SERIAL_VERSION_UID_TYPE);
1048 code.addOpcode(Bytecode.RETURN);
1049 minfo.setCodeAttribute(code.toCodeAttribute());
1050 cf.addMethod(minfo);
1051 }
1052
1053
1056 private static void callFind2Methods(Bytecode code, String superMethod, String thisMethod,
1057 int index, String desc, int classVar, int arrayVar) {
1058 String findClass = RuntimeSupport.class.getName();
1059 String findDesc
1060 = "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V";
1061
1062 code.addAload(classVar);
1063 code.addLdc(superMethod);
1064 if (thisMethod == null)
1065 code.addOpcode(Opcode.ACONST_NULL);
1066 else
1067 code.addLdc(thisMethod);
1068
1069 code.addIconst(index);
1070 code.addLdc(desc);
1071 code.addAload(arrayVar);
1072 code.addInvokestatic(findClass, "find2Methods", findDesc);
1073 }
1074
1075 private static void addSetter(String classname, ClassFile cf, ConstPool cp)
1076 throws CannotCompileException
1077 {
1078 MethodInfo minfo = new MethodInfo(cp, HANDLER_SETTER,
1079 HANDLER_SETTER_TYPE);
1080 minfo.setAccessFlags(AccessFlag.PUBLIC);
1081 Bytecode code = new Bytecode(cp, 2, 2);
1082 code.addAload(0);
1083 code.addAload(1);
1084 code.addPutfield(classname, HANDLER, HANDLER_TYPE);
1085 code.addOpcode(Bytecode.RETURN);
1086 minfo.setCodeAttribute(code.toCodeAttribute());
1087 cf.addMethod(minfo);
1088 }
1089
1090 private static void addGetter(String classname, ClassFile cf, ConstPool cp)
1091 throws CannotCompileException
1092 {
1093 MethodInfo minfo = new MethodInfo(cp, HANDLER_GETTER,
1094 HANDLER_GETTER_TYPE);
1095 minfo.setAccessFlags(AccessFlag.PUBLIC);
1096 Bytecode code = new Bytecode(cp, 1, 1);
1097 code.addAload(0);
1098 code.addGetfield(classname, HANDLER, HANDLER_TYPE);
1099 code.addOpcode(Bytecode.ARETURN);
1100 minfo.setCodeAttribute(code.toCodeAttribute());
1101 cf.addMethod(minfo);
1102 }
1103
1104 private int overrideMethods(ClassFile cf, ConstPool cp, String className, List<Find2MethodsArgs> forwarders)
1105 throws CannotCompileException
1106 {
1107 String prefix = makeUniqueName("_d", signatureMethods);
1108 Iterator<Map.Entry<String,Method>> it = signatureMethods.iterator();
1109 int index = 0;
1110 while (it.hasNext()) {
1111 Map.Entry<String,Method> e = it.next();
1112 if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_5 || !isBridge(e.getValue()))
1113 if (testBit(signature, index)) {
1114 override(className, e.getValue(), prefix, index,
1115 keyToDesc(e.getKey(), e.getValue()), cf, cp, forwarders);
1116 }
1117
1118 index++;
1119 }
1120
1121 return index;
1122 }
1123
1124 private static boolean isBridge(Method m) {
1125 return m.isBridge();
1126 }
1127
1128 private void override(String thisClassname, Method meth, String prefix,
1129 int index, String desc, ClassFile cf, ConstPool cp,
1130 List<Find2MethodsArgs> forwarders)
1131 throws CannotCompileException
1132 {
1133 Class<?> declClass = meth.getDeclaringClass();
1134 String delegatorName = prefix + index + meth.getName();
1135 if (Modifier.isAbstract(meth.getModifiers()))
1136 delegatorName = null;
1137 else {
1138 MethodInfo delegator
1139 = makeDelegator(meth, desc, cp, declClass, delegatorName);
1140
1141 delegator.setAccessFlags(delegator.getAccessFlags() & ~AccessFlag.BRIDGE);
1142 cf.addMethod(delegator);
1143 }
1144
1145 MethodInfo forwarder
1146 = makeForwarder(thisClassname, meth, desc, cp, declClass,
1147 delegatorName, index, forwarders);
1148 cf.addMethod(forwarder);
1149 }
1150
1151 private void makeConstructors(String thisClassName, ClassFile cf,
1152 ConstPool cp, String classname) throws CannotCompileException
1153 {
1154 Constructor<?>[] cons = SecurityActions.getDeclaredConstructors(superClass);
1155
1156 boolean doHandlerInit = !factoryUseCache;
1157 for (int i = 0; i < cons.length; i++) {
1158 Constructor<?> c = cons[i];
1159 int mod = c.getModifiers();
1160 if (!Modifier.isFinal(mod) && !Modifier.isPrivate(mod)
1161 && isVisible(mod, basename, c)) {
1162 MethodInfo m = makeConstructor(thisClassName, c, cp, superClass, doHandlerInit);
1163 cf.addMethod(m);
1164 }
1165 }
1166 }
1167
1168 private static String makeUniqueName(String name, List<Map.Entry<String,Method>> sortedMethods) {
1169 if (makeUniqueName0(name, sortedMethods.iterator()))
1170 return name;
1171
1172 for (int i = 100; i < 999; i++) {
1173 String s = name + i;
1174 if (makeUniqueName0(s, sortedMethods.iterator()))
1175 return s;
1176 }
1177
1178 throw new RuntimeException("cannot make a unique method name");
1179 }
1180
1181 private static boolean makeUniqueName0(String name, Iterator<Map.Entry<String,Method>> it) {
1182 while (it.hasNext())
1183 if (it.next().getKey().startsWith(name))
1184 return false;
1185 return true;
1186 }
1187
1188
1193 private static boolean isVisible(int mod, String from, Member meth) {
1194 if ((mod & Modifier.PRIVATE) != 0)
1195 return false;
1196 else if ((mod & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0)
1197 return true;
1198 else {
1199 String p = getPackageName(from);
1200 String q = getPackageName(meth.getDeclaringClass().getName());
1201 if (p == null)
1202 return q == null;
1203 return p.equals(q);
1204 }
1205 }
1206
1207 private static String getPackageName(String name) {
1208 int i = name.lastIndexOf('.');
1209 if (i < 0)
1210 return null;
1211 return name.substring(0, i);
1212 }
1213
1214
1216 private Map<String,Method> getMethods(Class<?> superClass, Class<?>[] interfaceTypes) {
1217 Map<String,Method> hash = new HashMap<String,Method>();
1218 Set<Class<?>> set = new HashSet<Class<?>>();
1219 for (int i = 0; i < interfaceTypes.length; i++)
1220 getMethods(hash, interfaceTypes[i], set);
1221
1222 getMethods(hash, superClass, set);
1223 return hash;
1224 }
1225
1226 private void getMethods(Map<String,Method> hash, Class<?> clazz, Set<Class<?>> visitedClasses) {
1227
1228
1229 if (!visitedClasses.add(clazz))
1230 return;
1231
1232 Class<?>[] ifs = clazz.getInterfaces();
1233 for (int i = 0; i < ifs.length; i++)
1234 getMethods(hash, ifs[i], visitedClasses);
1235
1236 Class<?> parent = clazz.getSuperclass();
1237 if (parent != null)
1238 getMethods(hash, parent, visitedClasses);
1239
1240
1245 Method[] methods = SecurityActions.getDeclaredMethods(clazz);
1246 for (int i = 0; i < methods.length; i++)
1247 if (!Modifier.isPrivate(methods[i].getModifiers())) {
1248 Method m = methods[i];
1249 String key = m.getName() + ':' + RuntimeSupport.makeDescriptor(m);
1250 if (key.startsWith(HANDLER_GETTER_KEY))
1251 hasGetHandler = true;
1252
1253
1254
1255 Method oldMethod = hash.put(key, m);
1256
1257
1258
1259 if (null != oldMethod && isBridge(m)
1260 && !Modifier.isPublic(oldMethod.getDeclaringClass().getModifiers())
1261 && !Modifier.isAbstract(oldMethod.getModifiers()) && !isDuplicated(i, methods))
1262 hash.put(key, oldMethod);
1263
1264
1265 if (null != oldMethod && Modifier.isPublic(oldMethod.getModifiers())
1266 && !Modifier.isPublic(m.getModifiers())) {
1267
1268
1269 hash.put(key, oldMethod);
1270 }
1271 }
1272 }
1273
1274 private static boolean isDuplicated(int index, Method[] methods) {
1275 String name = methods[index].getName();
1276 for (int i = 0; i < methods.length; i++)
1277 if (i != index)
1278 if (name.equals(methods[i].getName()) && areParametersSame(methods[index], methods[i]))
1279 return true;
1280
1281 return false;
1282 }
1283
1284 private static boolean areParametersSame(Method method, Method targetMethod) {
1285 Class<?>[] methodTypes = method.getParameterTypes();
1286 Class<?>[] targetMethodTypes = targetMethod.getParameterTypes();
1287 if (methodTypes.length == targetMethodTypes.length) {
1288 for (int i = 0; i< methodTypes.length; i++) {
1289 if (methodTypes[i].getName().equals(targetMethodTypes[i].getName())) {
1290 continue;
1291 } else {
1292 return false;
1293 }
1294 }
1295 return true;
1296 }
1297 return false;
1298 }
1299
1300 private static final String HANDLER_GETTER_KEY
1301 = HANDLER_GETTER + ":()";
1302
1303 private static String keyToDesc(String key, Method m) {
1304 return key.substring(key.indexOf(':') + 1);
1305 }
1306
1307 private static MethodInfo makeConstructor(String thisClassName, Constructor<?> cons,
1308 ConstPool cp, Class<?> superClass, boolean doHandlerInit) {
1309 String desc = RuntimeSupport.makeDescriptor(cons.getParameterTypes(),
1310 Void.TYPE);
1311 MethodInfo minfo = new MethodInfo(cp, "<init>", desc);
1312 minfo.setAccessFlags(Modifier.PUBLIC);
1313 setThrows(minfo, cp, cons.getExceptionTypes());
1314 Bytecode code = new Bytecode(cp, 0, 0);
1315
1316
1317
1318
1319 if (doHandlerInit) {
1320 code.addAload(0);
1321 code.addGetstatic(thisClassName, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
1322 code.addPutfield(thisClassName, HANDLER, HANDLER_TYPE);
1323 code.addGetstatic(thisClassName, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
1324 code.addOpcode(Opcode.IFNONNULL);
1325 code.addIndex(10);
1326 }
1327
1328
1329 code.addAload(0);
1330 code.addGetstatic(NULL_INTERCEPTOR_HOLDER, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
1331 code.addPutfield(thisClassName, HANDLER, HANDLER_TYPE);
1332 int pc = code.currentPc();
1333
1334 code.addAload(0);
1335 int s = addLoadParameters(code, cons.getParameterTypes(), 1);
1336 code.addInvokespecial(superClass.getName(), "<init>", desc);
1337 code.addOpcode(Opcode.RETURN);
1338 code.setMaxLocals(s + 1);
1339 CodeAttribute ca = code.toCodeAttribute();
1340 minfo.setCodeAttribute(ca);
1341
1342 StackMapTable.Writer writer = new StackMapTable.Writer(32);
1343 writer.sameFrame(pc);
1344 ca.setAttribute(writer.toStackMapTable(cp));
1345 return minfo;
1346 }
1347
1348 private MethodInfo makeDelegator(Method meth, String desc,
1349 ConstPool cp, Class<?> declClass, String delegatorName) {
1350 MethodInfo delegator = new MethodInfo(cp, delegatorName, desc);
1351 delegator.setAccessFlags(Modifier.FINAL | Modifier.PUBLIC
1352 | (meth.getModifiers() & ~(Modifier.PRIVATE
1353 | Modifier.PROTECTED
1354 | Modifier.ABSTRACT
1355 | Modifier.NATIVE
1356 | Modifier.SYNCHRONIZED)));
1357 setThrows(delegator, cp, meth);
1358 Bytecode code = new Bytecode(cp, 0, 0);
1359 code.addAload(0);
1360 int s = addLoadParameters(code, meth.getParameterTypes(), 1);
1361 Class<?> targetClass = invokespecialTarget(declClass);
1362 code.addInvokespecial(targetClass.isInterface(), cp.addClassInfo(targetClass.getName()),
1363 meth.getName(), desc);
1364 addReturn(code, meth.getReturnType());
1365 code.setMaxLocals(++s);
1366 delegator.setCodeAttribute(code.toCodeAttribute());
1367 return delegator;
1368 }
1369
1370
1375 private Class<?> invokespecialTarget(Class<?> declClass) {
1376 if (declClass.isInterface())
1377 for (Class<?> i: interfaces)
1378 if (declClass.isAssignableFrom(i))
1379 return i;
1380
1381 return superClass;
1382 }
1383
1384
1387 private static MethodInfo makeForwarder(String thisClassName,
1388 Method meth, String desc, ConstPool cp,
1389 Class<?> declClass, String delegatorName, int index,
1390 List<Find2MethodsArgs> forwarders) {
1391 MethodInfo forwarder = new MethodInfo(cp, meth.getName(), desc);
1392 forwarder.setAccessFlags(Modifier.FINAL
1393 | (meth.getModifiers() & ~(Modifier.ABSTRACT
1394 | Modifier.NATIVE
1395 | Modifier.SYNCHRONIZED)));
1396 setThrows(forwarder, cp, meth);
1397 int args = Descriptor.paramSize(desc);
1398 Bytecode code = new Bytecode(cp, 0, args + 2);
1399
1411 int origIndex = index * 2;
1412 int delIndex = index * 2 + 1;
1413 int arrayVar = args + 1;
1414 code.addGetstatic(thisClassName, HOLDER, HOLDER_TYPE);
1415 code.addAstore(arrayVar);
1416
1417 forwarders.add(new Find2MethodsArgs(meth.getName(), delegatorName, desc, origIndex));
1418
1419 code.addAload(0);
1420 code.addGetfield(thisClassName, HANDLER, HANDLER_TYPE);
1421 code.addAload(0);
1422
1423 code.addAload(arrayVar);
1424 code.addIconst(origIndex);
1425 code.addOpcode(Opcode.AALOAD);
1426
1427 code.addAload(arrayVar);
1428 code.addIconst(delIndex);
1429 code.addOpcode(Opcode.AALOAD);
1430
1431 makeParameterList(code, meth.getParameterTypes());
1432 code.addInvokeinterface(MethodHandler.class.getName(), "invoke",
1433 "(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;",
1434 5);
1435 Class<?> retType = meth.getReturnType();
1436 addUnwrapper(code, retType);
1437 addReturn(code, retType);
1438
1439 CodeAttribute ca = code.toCodeAttribute();
1440 forwarder.setCodeAttribute(ca);
1441 return forwarder;
1442 }
1443
1444 static class Find2MethodsArgs {
1445 String methodName, delegatorName, descriptor;
1446 int origIndex;
1447
1448 Find2MethodsArgs(String mname, String dname, String desc, int index) {
1449 methodName = mname;
1450 delegatorName = dname;
1451 descriptor = desc;
1452 origIndex = index;
1453 }
1454 }
1455
1456 private static void setThrows(MethodInfo minfo, ConstPool cp, Method orig) {
1457 Class<?>[] exceptions = orig.getExceptionTypes();
1458 setThrows(minfo, cp, exceptions);
1459 }
1460
1461 private static void setThrows(MethodInfo minfo, ConstPool cp,
1462 Class<?>[] exceptions) {
1463 if (exceptions.length == 0)
1464 return;
1465
1466 String[] list = new String[exceptions.length];
1467 for (int i = 0; i < exceptions.length; i++)
1468 list[i] = exceptions[i].getName();
1469
1470 ExceptionsAttribute ea = new ExceptionsAttribute(cp);
1471 ea.setExceptions(list);
1472 minfo.setExceptionsAttribute(ea);
1473 }
1474
1475 private static int addLoadParameters(Bytecode code, Class<?>[] params,
1476 int offset) {
1477 int stacksize = 0;
1478 int n = params.length;
1479 for (int i = 0; i < n; ++i)
1480 stacksize += addLoad(code, stacksize + offset, params[i]);
1481
1482 return stacksize;
1483 }
1484
1485 private static int addLoad(Bytecode code, int n, Class<?> type) {
1486 if (type.isPrimitive()) {
1487 if (type == Long.TYPE) {
1488 code.addLload(n);
1489 return 2;
1490 }
1491 else if (type == Float.TYPE)
1492 code.addFload(n);
1493 else if (type == Double.TYPE) {
1494 code.addDload(n);
1495 return 2;
1496 }
1497 else
1498 code.addIload(n);
1499 }
1500 else
1501 code.addAload(n);
1502
1503 return 1;
1504 }
1505
1506 private static int addReturn(Bytecode code, Class<?> type) {
1507 if (type.isPrimitive()) {
1508 if (type == Long.TYPE) {
1509 code.addOpcode(Opcode.LRETURN);
1510 return 2;
1511 }
1512 else if (type == Float.TYPE)
1513 code.addOpcode(Opcode.FRETURN);
1514 else if (type == Double.TYPE) {
1515 code.addOpcode(Opcode.DRETURN);
1516 return 2;
1517 }
1518 else if (type == Void.TYPE) {
1519 code.addOpcode(Opcode.RETURN);
1520 return 0;
1521 }
1522 else
1523 code.addOpcode(Opcode.IRETURN);
1524 }
1525 else
1526 code.addOpcode(Opcode.ARETURN);
1527
1528 return 1;
1529 }
1530
1531 private static void makeParameterList(Bytecode code, Class<?>[] params) {
1532 int regno = 1;
1533 int n = params.length;
1534 code.addIconst(n);
1535 code.addAnewarray("java/lang/Object");
1536 for (int i = 0; i < n; i++) {
1537 code.addOpcode(Opcode.DUP);
1538 code.addIconst(i);
1539 Class<?> type = params[i];
1540 if (type.isPrimitive())
1541 regno = makeWrapper(code, type, regno);
1542 else {
1543 code.addAload(regno);
1544 regno++;
1545 }
1546
1547 code.addOpcode(Opcode.AASTORE);
1548 }
1549 }
1550
1551 private static int makeWrapper(Bytecode code, Class<?> type, int regno) {
1552 int index = FactoryHelper.typeIndex(type);
1553 String wrapper = FactoryHelper.wrapperTypes[index];
1554 code.addNew(wrapper);
1555 code.addOpcode(Opcode.DUP);
1556 addLoad(code, regno, type);
1557 code.addInvokespecial(wrapper, "<init>",
1558 FactoryHelper.wrapperDesc[index]);
1559 return regno + FactoryHelper.dataSize[index];
1560 }
1561
1562 private static void addUnwrapper(Bytecode code, Class<?> type) {
1563 if (type.isPrimitive()) {
1564 if (type == Void.TYPE)
1565 code.addOpcode(Opcode.POP);
1566 else {
1567 int index = FactoryHelper.typeIndex(type);
1568 String wrapper = FactoryHelper.wrapperTypes[index];
1569 code.addCheckcast(wrapper);
1570 code.addInvokevirtual(wrapper,
1571 FactoryHelper.unwarpMethods[index],
1572 FactoryHelper.unwrapDesc[index]);
1573 }
1574 }
1575 else
1576 code.addCheckcast(type.getName());
1577 }
1578
1579 private static MethodInfo makeWriteReplace(ConstPool cp) {
1580 MethodInfo minfo = new MethodInfo(cp, "writeReplace", "()Ljava/lang/Object;");
1581 String[] list = new String[1];
1582 list[0] = "java.io.ObjectStreamException";
1583 ExceptionsAttribute ea = new ExceptionsAttribute(cp);
1584 ea.setExceptions(list);
1585 minfo.setExceptionsAttribute(ea);
1586 Bytecode code = new Bytecode(cp, 0, 1);
1587 code.addAload(0);
1588 code.addInvokestatic("javassist.util.proxy.RuntimeSupport",
1589 "makeSerializedProxy",
1590 "(Ljava/lang/Object;)Ljavassist/util/proxy/SerializedProxy;");
1591 code.addOpcode(Opcode.ARETURN);
1592 minfo.setCodeAttribute(code.toCodeAttribute());
1593 return minfo;
1594 }
1595 }
1596