1 52 53 package freemarker.ext.beans; 54 55 import java.beans.BeanInfo ; 56 import java.beans.IndexedPropertyDescriptor ; 57 import java.beans.IntrospectionException ; 58 import java.beans.Introspector ; 59 import java.beans.MethodDescriptor ; 60 import java.beans.PropertyDescriptor ; 61 import java.io.InputStream ; 62 import java.lang.reflect.AccessibleObject ; 63 import java.lang.reflect.Constructor ; 64 import java.lang.reflect.InvocationTargetException ; 65 import java.lang.reflect.Method ; 66 import java.lang.reflect.Modifier ; 67 import java.math.BigDecimal ; 68 import java.util.Arrays ; 69 import java.util.Collection ; 70 import java.util.Collections ; 71 import java.util.Date ; 72 import java.util.Enumeration ; 73 import java.util.HashMap ; 74 import java.util.HashSet ; 75 import java.util.Iterator ; 76 import java.util.List ; 77 import java.util.Map ; 78 import java.util.Properties ; 79 import java.util.ResourceBundle ; 80 import java.util.Set ; 81 import java.util.StringTokenizer ; 82 83 import freemarker.ext.util.ModelCache; 84 import freemarker.ext.util.ModelFactory; 85 import freemarker.ext.util.WrapperTemplateModel; 86 import freemarker.log.Logger; 87 import freemarker.template.AdapterTemplateModel; 88 import freemarker.template.ObjectWrapper; 89 import freemarker.template.TemplateBooleanModel; 90 import freemarker.template.TemplateCollectionModel; 91 import freemarker.template.TemplateDateModel; 92 import freemarker.template.TemplateHashModel; 93 import freemarker.template.TemplateModel; 94 import freemarker.template.TemplateModelAdapter; 95 import freemarker.template.TemplateModelException; 96 import freemarker.template.TemplateNumberModel; 97 import freemarker.template.TemplateScalarModel; 98 import freemarker.template.TemplateSequenceModel; 99 import freemarker.template.utility.ClassUtil; 100 import freemarker.template.utility.Collections12; 101 import freemarker.template.utility.SecurityUtilities; 102 103 109 public class BeansWrapper implements ObjectWrapper 110 { 111 private static final Class BIGINTEGER_CLASS = java.math.BigInteger .class; 112 private static final Class BOOLEAN_CLASS = Boolean .class; 113 private static final Class CHARACTER_CLASS = Character .class; 114 private static final Class COLLECTION_CLASS = Collection .class; 115 private static final Class DATE_CLASS = Date .class; 116 private static final Class LIST_CLASS = List .class; 117 private static final Class MAP_CLASS = Map .class; 118 private static final Class NUMBER_CLASS = Number .class; 119 private static final Class OBJECT_CLASS = Object .class; 120 private static final Class SET_CLASS = Set .class; 121 private static final Class STRING_CLASS = String .class; 122 private static final Class TEMPLATE_MODEL_CLASS = TemplateModel.class; 123 124 private static final boolean DEVELOPMENT = "true".equals(SecurityUtilities.getSystemProperty("freemarker.development")); 128 129 private static final Logger logger = Logger.getLogger("freemarker.beans"); 130 131 private static final Set UNSAFE_METHODS = createUnsafeMethodsSet(); 132 133 static final Object GENERIC_GET_KEY = new Object (); 134 private static final Object CONSTRUCTORS = new Object (); 135 private static final Object ARGTYPES = new Object (); 136 137 140 private static final BeansWrapper INSTANCE = new BeansWrapper(); 141 142 private final Map classCache = new HashMap (); 147 private Set cachedClassNames = new HashSet (); 148 149 private final StaticModels staticModels = new StaticModels(this); 150 151 private final ModelCache modelCache = new ModelCache(this); 152 153 private final BooleanModel FALSE = new BooleanModel(Boolean.FALSE, this); 154 private final BooleanModel TRUE = new BooleanModel(Boolean.TRUE, this); 155 156 160 public static final int EXPOSE_ALL = 0; 161 162 173 public static final int EXPOSE_SAFE = 1; 174 175 180 public static final int EXPOSE_PROPERTIES_ONLY = 2; 181 182 190 public static final int EXPOSE_NOTHING = 3; 191 192 private int exposureLevel = EXPOSE_SAFE; 193 private TemplateModel nullModel = null; 194 private boolean methodsShadowItems = true; 195 private int defaultDateType = TemplateDateModel.UNKNOWN; 196 197 private ObjectWrapper outerIdentity = this; 198 private boolean simpleMapWrapper; 199 200 206 public BeansWrapper() 207 { 208 } 209 210 219 public void setOuterIdentity(ObjectWrapper outerIdentity) 220 { 221 this.outerIdentity = outerIdentity; 222 } 223 224 228 public ObjectWrapper getOuterIdentity() 229 { 230 return outerIdentity; 231 } 232 233 243 public void setSimpleMapWrapper(boolean simpleMapWrapper) 244 { 245 this.simpleMapWrapper = simpleMapWrapper; 246 } 247 248 public boolean isSimpleMapWrapper() 249 { 250 return simpleMapWrapper; 251 } 252 253 258 public void setExposureLevel(int exposureLevel) 259 { 260 if(exposureLevel < EXPOSE_ALL || exposureLevel > EXPOSE_NOTHING) 261 { 262 throw new IllegalArgumentException ("Illegal exposure level " + exposureLevel); 263 } 264 this.exposureLevel = exposureLevel; 265 } 266 267 int getExposureLevel() 268 { 269 return exposureLevel; 270 } 271 272 282 public synchronized void setMethodsShadowItems(boolean methodsShadowItems) 283 { 284 this.methodsShadowItems = methodsShadowItems; 285 } 286 287 boolean isMethodsShadowItems() 288 { 289 return methodsShadowItems; 290 } 291 292 299 public synchronized void setDefaultDateType(int defaultDateType) { 300 this.defaultDateType = defaultDateType; 301 } 302 303 protected int getDefaultDateType() { 304 return defaultDateType; 305 } 306 307 313 public void setUseCache(boolean useCache) 314 { 315 modelCache.setUseCache(useCache); 316 } 317 318 326 public void setNullModel(TemplateModel nullModel) 327 { 328 this.nullModel = nullModel; 329 } 330 331 342 public static final BeansWrapper getDefaultInstance() 343 { 344 return INSTANCE; 345 } 346 347 367 public TemplateModel wrap(Object object) throws TemplateModelException 368 { 369 if(object == null) 370 return nullModel; 371 if(object instanceof TemplateModel) 372 return (TemplateModel)object; 373 if(object instanceof TemplateModelAdapter) 374 return ((TemplateModelAdapter)object).getTemplateModel(); 375 if(object instanceof Map ) 376 return modelCache.getInstance(object, simpleMapWrapper ? SimpleMapModel.FACTORY : MapModel.FACTORY); 377 if(object instanceof Collection ) 378 return modelCache.getInstance(object, CollectionModel.FACTORY); 379 if(object.getClass().isArray()) 380 return modelCache.getInstance(object, ArrayModel.FACTORY); 381 if(object instanceof Number ) 382 return modelCache.getInstance(object, NumberModel.FACTORY); 383 if(object instanceof Date ) 384 return modelCache.getInstance(object, DateModel.FACTORY); 385 if(object instanceof Boolean ) 386 return ((Boolean )object).booleanValue() ? TRUE : FALSE; 387 if(object instanceof ResourceBundle ) 388 return modelCache.getInstance(object, ResourceBundleModel.FACTORY); 389 if(object instanceof Iterator ) 390 return new IteratorModel((Iterator )object, this); 391 if(object instanceof Enumeration ) 392 return new EnumerationModel((Enumeration )object, this); 393 return modelCache.getInstance(object, StringModel.FACTORY); 394 } 395 396 protected TemplateModel getInstance(Object object, ModelFactory factory) 397 { 398 return modelCache.getInstance(object, factory); 399 } 400 401 protected TemplateModel create(Object object, Object factory) 402 { 403 return ((ModelFactory)factory).create(object, this); 404 } 405 406 415 public Object unwrap(TemplateModel model) throws TemplateModelException 416 { 417 return unwrap(model, OBJECT_CLASS); 418 } 419 420 public Object unwrap(TemplateModel model, Class hint) 421 throws TemplateModelException 422 { 423 if(model == nullModel) { 424 return null; 425 } 426 427 if(TEMPLATE_MODEL_CLASS.isAssignableFrom(hint)) { 430 return model; 431 } 432 433 if(model instanceof AdapterTemplateModel) { 438 return ((AdapterTemplateModel)model).getAdaptedObject(hint); 439 } 440 if(model instanceof WrapperTemplateModel) { 441 return ((WrapperTemplateModel)model).getWrappedObject(); 442 } 443 444 449 if(STRING_CLASS == hint) { 450 if(model instanceof TemplateScalarModel) { 451 return ((TemplateScalarModel)model).getAsString(); 452 } 453 } 454 boolean isBoolean = Boolean.TYPE == hint; 455 if(isBoolean || BOOLEAN_CLASS == hint) { 456 if(model instanceof TemplateBooleanModel) { 457 return ((TemplateBooleanModel)model).getAsBoolean() ? Boolean.TRUE : Boolean.FALSE; 458 } 459 } 460 if(MAP_CLASS == hint) { 461 if(model instanceof TemplateHashModel) { 462 return new HashAdapter((TemplateHashModel)model, this); 463 } 464 } 465 if(LIST_CLASS == hint) { 466 if(model instanceof TemplateSequenceModel) { 467 return new SequenceAdapter((TemplateSequenceModel)model, this); 468 } 469 } 470 if(SET_CLASS == hint || COLLECTION_CLASS == hint) { 471 if(model instanceof TemplateCollectionModel) { 472 return new CollectionAdapter((TemplateCollectionModel)model, this); 473 } 474 } 475 476 boolean isChar = hint == Character.TYPE; 478 if(isChar || hint == CHARACTER_CLASS) { 479 if(model instanceof TemplateScalarModel) { 480 String s = ((TemplateScalarModel)model).getAsString(); 481 if(s.length() == 1) { 482 return new Character (s.charAt(0)); 483 } 484 } 485 } 486 487 if((hint.isPrimitive() && !isChar && !isBoolean) 489 || NUMBER_CLASS.isAssignableFrom(hint)) { 490 if(model instanceof TemplateNumberModel) { 491 return ((TemplateNumberModel)model).getAsNumber(); 492 } 493 } 494 if(DATE_CLASS.isAssignableFrom(hint)) { 495 if(model instanceof TemplateDateModel) { 496 return ((TemplateDateModel)model).getAsDate(); 497 } 498 } 499 500 if(model instanceof TemplateNumberModel) 503 return ((TemplateNumberModel)model).getAsNumber(); 504 if(model instanceof TemplateDateModel) 505 return ((TemplateDateModel)model).getAsDate(); 506 if(model instanceof TemplateScalarModel) 507 return ((TemplateScalarModel)model).getAsString(); 508 if(model instanceof TemplateBooleanModel) 509 return ((TemplateBooleanModel)model).getAsBoolean() ? Boolean.TRUE : Boolean.FALSE; 510 if(model instanceof TemplateHashModel) 511 return new HashAdapter((TemplateHashModel)model, this); 512 if(model instanceof TemplateSequenceModel) 513 return new SequenceAdapter((TemplateSequenceModel)model, this); 514 if(model instanceof TemplateCollectionModel) 515 return new CollectionAdapter((TemplateCollectionModel)model, this); 516 517 return model; 521 } 522 523 531 Object [] unwrapArguments(List arguments, Class [] argTypes) throws 532 TemplateModelException 533 { 534 Object [] args = null; 535 if(arguments != null) { 536 int size = arguments.size(); 537 args = new Object [size]; 538 Iterator it = arguments.iterator(); 539 for(int i = 0; it.hasNext(); ++i) { 540 args[i] = unwrap((TemplateModel)it.next(), argTypes[i]); 541 } 542 } 543 return args; 544 } 545 546 Object [] unwrapArguments(List arguments) throws TemplateModelException 547 { 548 Object [] args = null; 549 if(arguments != null) { 550 int size = arguments.size(); 551 args = new Object [size]; 552 Iterator it = arguments.iterator(); 553 int i = 0; 554 while(it.hasNext()) { 555 args[i++] = unwrap((TemplateModel)it.next()); 556 } 557 } 558 return args; 559 } 560 561 577 TemplateModel invokeMethod(Object object, Method method, Object [] args) 578 throws 579 InvocationTargetException , 580 IllegalAccessException , 581 TemplateModelException 582 { 583 Object retval = method.invoke(object, args); 584 return 585 method.getReturnType() == Void.TYPE 586 ? TemplateModel.NOTHING 587 : getOuterIdentity().wrap(retval); 588 } 589 590 603 public TemplateHashModel getStaticModels() 604 { 605 return staticModels; 606 } 607 608 public Object newInstance(Class clazz, List arguments) 609 throws 610 TemplateModelException 611 { 612 try 613 { 614 introspectClass(clazz); 615 Map classInfo = (Map )classCache.get(clazz); 616 Object ctors = classInfo.get(CONSTRUCTORS); 617 if(ctors == null) 618 { 619 throw new TemplateModelException("Class " + clazz.getName() + 620 " has no public constructors."); 621 } 622 Constructor ctor = null; 623 Object [] objargs; 624 if(ctors instanceof Constructor ) 625 { 626 ctor = (Constructor )ctors; 627 objargs = unwrapArguments(arguments, getArgTypes(classInfo, ctor)); 628 } 629 else if(ctors instanceof MethodMap) 630 { 631 MethodMap methodMap = (MethodMap)ctors; 632 objargs = unwrapArguments(arguments, methodMap.getUnwrapTypes(arguments)); 633 ctor = (Constructor )methodMap.getMostSpecific(objargs); 634 } 635 else 636 { 637 throw new Error (); 639 } 640 if(objargs != null) { 641 coerceBigDecimals(ctor, objargs); 642 } 643 return ctor.newInstance(objargs); 644 } 645 catch (TemplateModelException e) 646 { 647 throw e; 648 } 649 catch (Exception e) 650 { 651 throw new TemplateModelException( 652 "Could not create instance of class " + clazz.getName(), e); 653 } 654 } 655 656 void introspectClass(Class clazz) 657 { 658 synchronized(classCache) 659 { 660 if(!classCache.containsKey(clazz)) 661 { 662 String className = clazz.getName(); 663 if(cachedClassNames.contains(className)) 664 { 665 if(logger.isInfoEnabled()) 666 { 667 logger.info("Detected a reloaded class [" + className + 668 "]. Clearing BeansWrapper caches."); 669 } 670 classCache.clear(); 672 cachedClassNames = new HashSet (); 673 synchronized(this) 674 { 675 modelCache.clearCache(); 676 } 677 staticModels.clearCache(); 678 } 679 classCache.put(clazz, populateClassMap(clazz)); 680 cachedClassNames.add(className); 681 } 682 } 683 } 684 685 Map getClassKeyMap(Class clazz) 686 { 687 synchronized(classCache) 688 { 689 return (Map )classCache.get(clazz); 690 } 691 } 692 693 699 int keyCount(Class clazz) 700 { 701 Map map = getClassKeyMap(clazz); 702 int count = map.size(); 703 if (map.containsKey(CONSTRUCTORS)) 704 count--; 705 if (map.containsKey(GENERIC_GET_KEY)) 706 count--; 707 if (map.containsKey(ARGTYPES)) 708 count--; 709 return count; 710 } 711 712 718 Set keySet(Class clazz) 719 { 720 Set set = new HashSet (getClassKeyMap(clazz).keySet()); 721 set.remove(CONSTRUCTORS); 722 set.remove(GENERIC_GET_KEY); 723 set.remove(ARGTYPES); 724 return set; 725 } 726 727 733 private Map populateClassMap(Class clazz) 734 { 735 Map map = populateClassMapWithBeanInfo(clazz); 737 try 739 { 740 Constructor [] ctors = clazz.getConstructors(); 741 if(ctors.length == 1) 742 { 743 Constructor ctor = ctors[0]; 744 map.put(CONSTRUCTORS, ctor); 745 getArgTypes(map).put(ctor, ctor.getParameterTypes()); 746 } 747 else if(ctors.length > 1) 748 { 749 MethodMap ctorMap = new MethodMap("<init>"); 750 for (int i = 0; i < ctors.length; i++) 751 { 752 ctorMap.addConstructor(ctors[i]); 753 } 754 map.put(CONSTRUCTORS, ctorMap); 755 } 756 } 757 catch(SecurityException e) 758 { 759 logger.warn("Canont discover constructors for class " + 760 clazz.getName(), e); 761 } 762 switch(map.size()) 763 { 764 case 0: 765 { 766 map = Collections12.EMPTY_MAP; 767 break; 768 } 769 case 1: 770 { 771 Map.Entry e = (Map.Entry )map.entrySet().iterator().next(); 772 map = Collections12.singletonMap(e.getKey(), e.getValue()); 773 break; 774 } 775 } 776 return map; 777 } 778 779 private Map populateClassMapWithBeanInfo(Class clazz) 780 { 781 Map classMap = new HashMap (); 782 Map accessibleMethods = discoverAccessibleMethods(clazz); 783 Method genericGet = (Method )accessibleMethods.get(MethodSignature.GET_STRING_SIGNATURE); 784 if(genericGet == null) 785 { 786 genericGet = (Method )accessibleMethods.get(MethodSignature.GET_OBJECT_SIGNATURE); 787 } 788 if(genericGet != null) 789 { 790 classMap.put(GENERIC_GET_KEY, genericGet); 791 } 792 if(exposureLevel == EXPOSE_NOTHING) 793 { 794 return classMap; 795 } 796 797 try 798 { 799 BeanInfo beanInfo = Introspector.getBeanInfo(clazz); 800 PropertyDescriptor [] pda = beanInfo.getPropertyDescriptors(); 801 MethodDescriptor [] mda = beanInfo.getMethodDescriptors(); 802 803 for(int i = pda.length - 1; i >= 0; --i) { 804 PropertyDescriptor pd = pda[i]; 805 if(pd instanceof IndexedPropertyDescriptor ) { 806 IndexedPropertyDescriptor ipd = 807 (IndexedPropertyDescriptor )pd; 808 Method readMethod = ipd.getIndexedReadMethod(); 809 Method publicReadMethod = getAccessibleMethod(readMethod, 810 accessibleMethods); 811 if(publicReadMethod != null && isSafeMethod(publicReadMethod)) { 812 try { 813 if(readMethod != publicReadMethod) { 814 ipd = new IndexedPropertyDescriptor ( 815 ipd.getName(), ipd.getReadMethod(), 816 ipd.getWriteMethod(), publicReadMethod, 817 ipd.getWriteMethod()); 818 } 819 classMap.put(ipd.getName(), ipd); 820 getArgTypes(classMap).put(publicReadMethod, 821 publicReadMethod.getParameterTypes()); 822 } 823 catch(IntrospectionException e) { 824 logger.warn("Couldn't properly perform introspection", e); 825 } 826 } 827 } 828 else { 829 Method readMethod = pd.getReadMethod(); 830 Method publicReadMethod = getAccessibleMethod(readMethod, accessibleMethods); 831 if(publicReadMethod != null && isSafeMethod(publicReadMethod)) { 832 try { 833 if(readMethod != publicReadMethod) { 834 pd = new PropertyDescriptor (pd.getName(), 835 publicReadMethod, pd.getWriteMethod()); 836 pd.setReadMethod(publicReadMethod); 837 } 838 classMap.put(pd.getName(), pd); 839 } 840 catch(IntrospectionException e) 841 { 842 logger.warn("Couldn't properly perform introspection", e); 843 } 844 } 845 } 846 } 847 if(exposureLevel < EXPOSE_PROPERTIES_ONLY) 848 { 849 for(int i = mda.length - 1; i >= 0; --i) 850 { 851 MethodDescriptor md = mda[i]; 852 Method method = md.getMethod(); 853 Method publicMethod = getAccessibleMethod(method, accessibleMethods); 854 if(publicMethod != null && isSafeMethod(publicMethod)) 855 { 856 String name = md.getName(); 857 Object previous = classMap.get(name); 858 if(previous instanceof Method ) 859 { 860 MethodMap methodMap = new MethodMap(name); 862 methodMap.addMethod((Method )previous); 863 methodMap.addMethod(publicMethod); 864 classMap.put(name, methodMap); 865 getArgTypes(classMap).remove(previous); 867 } 868 else if(previous instanceof MethodMap) 869 { 870 ((MethodMap)previous).addMethod(publicMethod); 872 } 873 else 874 { 875 classMap.put(name, publicMethod); 877 getArgTypes(classMap).put(publicMethod, 878 publicMethod.getParameterTypes()); 879 } 880 } 881 } 882 } 883 return classMap; 884 } 885 catch(IntrospectionException e) 886 { 887 logger.warn("Couldn't properly perform introspection", e); 888 return new HashMap (); 889 } 890 } 891 892 private static Map getArgTypes(Map classMap) { 893 Map argTypes = (Map )classMap.get(ARGTYPES); 894 if(argTypes == null) { 895 argTypes = new HashMap (); 896 classMap.put(ARGTYPES, argTypes); 897 } 898 return argTypes; 899 } 900 901 static Class [] getArgTypes(Map classMap, AccessibleObject methodOrCtor) { 902 return (Class [])((Map )classMap.get(ARGTYPES)).get(methodOrCtor); 903 } 904 905 private static Method getAccessibleMethod(Method m, Map accessibles) 906 { 907 return m == null ? null : (Method )accessibles.get(new MethodSignature(m)); 908 } 909 910 boolean isSafeMethod(Method method) 911 { 912 return exposureLevel < EXPOSE_SAFE || !UNSAFE_METHODS.contains(method); 913 } 914 915 922 private static Map discoverAccessibleMethods(Class clazz) 923 { 924 Map map = new HashMap (); 925 discoverAccessibleMethods(clazz, map); 926 return map; 927 } 928 929 private static void discoverAccessibleMethods(Class clazz, Map map) 930 { 931 if(Modifier.isPublic(clazz.getModifiers())) 932 { 933 try 934 { 935 Method [] methods = clazz.getMethods(); 936 for(int i = 0; i < methods.length; i++) 937 { 938 Method method = methods[i]; 939 MethodSignature sig = new MethodSignature(method); 940 map.put(sig, method); 941 } 942 return; 943 } 944 catch(SecurityException e) 945 { 946 logger.warn("Could not discover accessible methods of class " + 947 clazz.getName() + 948 ", attemping superclasses/interfaces.", e); 949 } 952 } 953 954 Class [] interfaces = clazz.getInterfaces(); 955 for(int i = 0; i < interfaces.length; i++) 956 { 957 discoverAccessibleMethods(interfaces[i], map); 958 } 959 Class superclass = clazz.getSuperclass(); 960 if(superclass != null) 961 { 962 discoverAccessibleMethods(superclass, map); 963 } 964 } 965 966 private static final class MethodSignature 967 { 968 private static final MethodSignature GET_STRING_SIGNATURE = 969 new MethodSignature("get", new Class [] { STRING_CLASS }); 970 private static final MethodSignature GET_OBJECT_SIGNATURE = 971 new MethodSignature("get", new Class [] { OBJECT_CLASS }); 972 973 private final String name; 974 private final Class [] args; 975 976 private MethodSignature(String name, Class [] args) 977 { 978 this.name = name; 979 this.args = args; 980 } 981 982 MethodSignature(Method method) 983 { 984 this(method.getName(), method.getParameterTypes()); 985 } 986 987 public boolean equals(Object o) 988 { 989 if(o instanceof MethodSignature) 990 { 991 MethodSignature ms = (MethodSignature)o; 992 return ms.name.equals(name) && Arrays.equals(args, ms.args); 993 } 994 return false; 995 } 996 997 public int hashCode() 998 { 999 return name.hashCode() ^ args.length; 1000 } 1001 } 1002 1003 private static final Set createUnsafeMethodsSet() 1004 { 1005 Properties props = new Properties (); 1006 InputStream in = BeansWrapper.class.getResourceAsStream("unsafeMethods.txt"); 1007 if(in != null) 1008 { 1009 String methodSpec = null; 1010 try 1011 { 1012 try 1013 { 1014 props.load(in); 1015 } 1016 finally 1017 { 1018 in.close(); 1019 } 1020 Set set = new HashSet (props.size() * 4/3, .75f); 1021 Map primClasses = createPrimitiveClassesMap(); 1022 for (Iterator iterator = props.keySet().iterator(); iterator.hasNext();) 1023 { 1024 methodSpec = (String ) iterator.next(); 1025 try { 1026 set.add(parseMethodSpec(methodSpec, primClasses)); 1027 } 1028 catch(ClassNotFoundException e) { 1029 if(DEVELOPMENT) { 1030 throw e; 1031 } 1032 } 1033 catch(NoSuchMethodException e) { 1034 if(DEVELOPMENT) { 1035 throw e; 1036 } 1037 } 1038 } 1039 } 1040 catch(Exception e) 1041 { 1042 throw new RuntimeException ("Could not load unsafe method " + methodSpec + " " + e.getClass().getName() + " " + e.getMessage()); 1043 } 1044 } 1045 return Collections.EMPTY_SET; 1046 } 1047 1048 private static Method parseMethodSpec(String methodSpec, Map primClasses) 1049 throws 1050 ClassNotFoundException , 1051 NoSuchMethodException 1052 { 1053 int brace = methodSpec.indexOf('('); 1054 int dot = methodSpec.lastIndexOf('.', brace); 1055 Class clazz = ClassUtil.forName(methodSpec.substring(0, dot)); 1056 String methodName = methodSpec.substring(dot + 1, brace); 1057 String argSpec = methodSpec.substring(brace + 1, methodSpec.length() - 1); 1058 StringTokenizer tok = new StringTokenizer (argSpec, ","); 1059 int argcount = tok.countTokens(); 1060 Class [] argTypes = new Class [argcount]; 1061 for (int i = 0; i < argcount; i++) 1062 { 1063 String argClassName = tok.nextToken(); 1064 argTypes[i] = (Class )primClasses.get(argClassName); 1065 if(argTypes[i] == null) 1066 { 1067 argTypes[i] = ClassUtil.forName(argClassName); 1068 } 1069 } 1070 return clazz.getMethod(methodName, argTypes); 1071 } 1072 1073 private static Map createPrimitiveClassesMap() 1074 { 1075 Map map = new HashMap (); 1076 map.put("boolean", Boolean.TYPE); 1077 map.put("byte", Byte.TYPE); 1078 map.put("char", Character.TYPE); 1079 map.put("short", Short.TYPE); 1080 map.put("int", Integer.TYPE); 1081 map.put("long", Long.TYPE); 1082 map.put("float", Float.TYPE); 1083 map.put("double", Double.TYPE); 1084 return map; 1085 } 1086 1087 1088 1092 public static void coerceBigDecimals(AccessibleObject callable, Object [] args) 1093 { 1094 Class [] formalTypes = null; 1095 for(int i = 0, l = args.length; i < l; ++i) 1096 { 1097 Object arg = args[i]; 1098 if(arg instanceof BigDecimal ) 1099 { 1100 BigDecimal bd = (BigDecimal )arg; 1101 if(formalTypes == null) 1102 { 1103 if(callable instanceof Method ) { 1104 formalTypes = ((Method )callable).getParameterTypes(); 1105 } 1106 else if(callable instanceof Constructor ) { 1107 formalTypes = ((Constructor )callable).getParameterTypes(); 1108 } 1109 else { 1110 throw new Error (); 1112 } 1113 if(formalTypes.length != l) 1114 { 1115 return; 1118 } 1119 } 1120 Class formalType = formalTypes[i]; 1121 if(formalType == Integer.TYPE || formalType == Integer .class) 1123 { 1124 args[i] = new Integer (bd.intValue()); 1125 } 1126 else if(formalType == Double.TYPE || formalType == Double .class) 1127 { 1128 args[i] = new Double (bd.doubleValue()); 1129 } 1130 else if(formalType == Long.TYPE || formalType == Long .class) 1131 { 1132 args[i] = new Long (bd.longValue()); 1133 } 1134 else if(formalType == Float.TYPE || formalType == Float .class) 1135 { 1136 args[i] = new Float (bd.floatValue()); 1137 } 1138 else if(formalType == Short.TYPE || formalType == Short .class) 1139 { 1140 args[i] = new Short (bd.shortValue()); 1141 } 1142 else if(formalType == Byte.TYPE || formalType == Byte .class) 1143 { 1144 args[i] = new Byte (bd.byteValue()); 1145 } 1146 else if(BIGINTEGER_CLASS.isAssignableFrom(formalType)) 1147 { 1148 args[i] = bd.toBigInteger(); 1149 } 1150 } 1151 } 1152 } 1153} 1154 | Popular Tags |