001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.reflection; 020 021import java.lang.reflect.Constructor; 022import java.lang.reflect.Field; 023import java.lang.reflect.InvocationTargetException; 024import java.lang.reflect.Member; 025import java.lang.reflect.Method; 026import java.lang.reflect.Modifier; 027import java.util.ArrayList; 028import java.util.Calendar; 029import java.util.Date; 030import java.util.HashSet; 031import java.util.Hashtable; 032import java.util.Iterator; 033import java.util.List; 034import java.util.Locale; 035import java.util.Map; 036import java.util.Map.Entry; 037import java.util.Set; 038import java.util.TimeZone; 039import java.util.Vector; 040 041import lucee.commons.io.res.Resource; 042import lucee.commons.lang.ExceptionUtil; 043import lucee.commons.lang.StringUtil; 044import lucee.commons.lang.types.RefInteger; 045import lucee.commons.lang.types.RefIntegerImpl; 046import lucee.runtime.Component; 047import lucee.runtime.engine.ThreadLocalPageContext; 048import lucee.runtime.exp.ApplicationException; 049import lucee.runtime.exp.ExpressionException; 050import lucee.runtime.exp.NativeException; 051import lucee.runtime.exp.PageException; 052import lucee.runtime.exp.PageRuntimeException; 053import lucee.runtime.exp.SecurityException; 054import lucee.runtime.java.JavaObject; 055import lucee.runtime.net.rpc.AxisCaster; 056import lucee.runtime.net.rpc.Pojo; 057import lucee.runtime.op.Caster; 058import lucee.runtime.op.Decision; 059import lucee.runtime.op.Duplicator; 060import lucee.runtime.op.Operator; 061import lucee.runtime.reflection.pairs.ConstructorInstance; 062import lucee.runtime.reflection.pairs.MethodInstance; 063import lucee.runtime.reflection.storage.SoftMethodStorage; 064import lucee.runtime.reflection.storage.WeakConstructorStorage; 065import lucee.runtime.reflection.storage.WeakFieldStorage; 066import lucee.runtime.type.Array; 067import lucee.runtime.type.Collection; 068import lucee.runtime.type.Collection.Key; 069import lucee.runtime.type.KeyImpl; 070import lucee.runtime.type.ObjectWrap; 071import lucee.runtime.type.Query; 072import lucee.runtime.type.Struct; 073import lucee.runtime.type.util.ArrayUtil; 074import lucee.runtime.type.util.Type; 075 076/** 077 * Class to reflect on Objects and classes 078 */ 079public final class Reflector { 080 081 082 private static final Object NULL = new Object(); 083 084 085 private static final Collection.Key SET_ACCESSIBLE = KeyImpl.intern("setAccessible"); 086 private static final Collection.Key EXIT = KeyImpl.intern("exit"); 087 088 089 private static WeakConstructorStorage cStorage=new WeakConstructorStorage(); 090 private static WeakFieldStorage fStorage=new WeakFieldStorage(); 091 private static SoftMethodStorage mStorage=new SoftMethodStorage(); 092 093 /** 094 * check if Class is instanceof a a other Class 095 * @param srcClassName Class name to check 096 * @param trg is Class of? 097 * @return is Class Class of... 098 */ 099 public static boolean isInstaneOf(String srcClassName,Class trg) { 100 try { 101 return isInstaneOf(Class.forName(srcClassName),trg); 102 } 103 catch (ClassNotFoundException e) { 104 return false; 105 } 106 } 107 108 /** 109 * check if Class is instanceof a a other Class 110 * @param srcClassName Class name to check 111 * @param trgClassName is Class of? 112 * @return is Class Class of... 113 */ 114 public static boolean isInstaneOf(String srcClassName,String trgClassName) { 115 try { 116 return isInstaneOf(Class.forName(srcClassName),trgClassName); 117 } 118 catch (ClassNotFoundException e) { 119 return false; 120 } 121 } 122 123 /** 124 * check if Class is instanceof a a other Class 125 * @param src is Class of? 126 * @param trgClassName Class name to check 127 * @return is Class Class of... 128 */ 129 public static boolean isInstaneOf(Class src, String trgClassName) { 130 try { 131 return isInstaneOf(src,Class.forName(trgClassName)); 132 } 133 catch (ClassNotFoundException e) { 134 return false; 135 } 136 } 137 138 139 public static boolean isInstaneOfIgnoreCase(Class src ,String trg) { 140 if(src.isArray()) { 141 return isInstaneOfIgnoreCase(src.getComponentType() ,trg); 142 } 143 144 if(src.getName().equalsIgnoreCase(trg))return true; 145 146 // Interface 147 if(_checkInterfaces(src,trg)) { 148 return true; 149 } 150 // Extends 151 src=src.getSuperclass(); 152 if(src!=null) return isInstaneOfIgnoreCase(src, trg); 153 return false; 154 } 155 156 157 /** 158 * check if Class is instanceof a a other Class 159 * @param src Class to check 160 * @param trg is Class of? 161 * @return is Class Class of... 162 */ 163 public static boolean isInstaneOf(Class src ,Class trg) { 164 if(src.isArray() && trg.isArray()) { 165 return isInstaneOf(src.getComponentType() ,trg.getComponentType()); 166 } 167 168 if(src==trg)return true; 169 170 // Interface 171 if(trg.isInterface()) { 172 return _checkInterfaces(src,trg); 173 } 174 // Extends 175 176 while(src!=null) { 177 if(src==trg) return true; 178 src=src.getSuperclass(); 179 } 180 return trg==Object.class; 181 } 182 183 private static boolean _checkInterfaces(Class src, String trg) { 184 Class[] interfaces = src.getInterfaces(); 185 if(interfaces==null) return false; 186 for(int i=0;i<interfaces.length;i++) { 187 if(interfaces[i].getName().equalsIgnoreCase(trg))return true; 188 if(_checkInterfaces(interfaces[i],trg)) return true; 189 } 190 return false; 191 } 192 193 private static boolean _checkInterfaces(Class src, Class trg) { 194 Class[] interfaces = src.getInterfaces(); 195 if(interfaces==null) return false; 196 for(int i=0;i<interfaces.length;i++) { 197 if(interfaces[i]==trg)return true; 198 if(_checkInterfaces(interfaces[i],trg)) return true; 199 } 200 src=src.getSuperclass(); 201 if(src!=null) return _checkInterfaces(src,trg); 202 return false; 203 } 204 205 /** 206 * get all Classes from a Object Array 207 * @param objs Objects to get 208 * @return classes from Objects 209 */ 210 public static Class[] getClasses(Object[] objs) { 211 Class[] cls=new Class[objs.length]; 212 for(int i=0;i<objs.length;i++) { 213 if(objs[i]==null)cls[i]=Object.class; 214 else cls[i]=objs[i].getClass(); 215 } 216 return cls; 217 } 218 219 /** 220 * convert a primitive class Type to a Reference Type (Example: int -> java.lang.Integer) 221 * @param c Class to convert 222 * @return converted Class (if primitive) 223 */ 224 public static Class toReferenceClass(Class c) { 225 if(c.isPrimitive()) { 226 if(c==boolean.class) return Boolean.class; 227 if(c==byte.class) return Byte.class; 228 if(c==short.class) return Short.class; 229 if(c==char.class) return Character.class; 230 if(c==int.class) return Integer.class; 231 if(c==long.class) return Long.class; 232 if(c==float.class) return Float.class; 233 if(c==double.class) return Double.class; 234 } 235 return c; 236 } 237 238 /** 239 * creates a string list with class arguments in a displable form 240 * @param clazzArgs arguments to display 241 * @return list 242 */ 243 public static String getDspMethods(Class... clazzArgs) { 244 StringBuffer sb=new StringBuffer(); 245 for(int i=0;i<clazzArgs.length;i++) { 246 if(i>0)sb.append(", "); 247 sb.append(Caster.toTypeName(clazzArgs[i])); 248 } 249 return sb.toString(); 250 } 251 252 /** 253 * checks if src Class is "like" trg class 254 * @param src Source Class 255 * @param trg Target Class 256 * @return is similar 257 */ 258 public static boolean like(Class src, Class trg) { 259 if(src==trg) return true; 260 return isInstaneOf(src,trg); 261 } 262 263 /** 264 * convert Object from src to trg Type, if possible 265 * @param src Object to convert 266 * @param srcClass Source Class 267 * @param trgClass Target Class 268 * @return converted Object 269 * @throws PageException 270 */ 271 public static Object convert(Object src, Class trgClass, RefInteger rating) throws PageException { 272 if(rating!=null) { 273 Object trg = _convert(src, trgClass); 274 if(src==trg) { 275 rating.plus(10); 276 return trg; 277 } 278 if(src==null || trg==null) { 279 rating.plus(0); 280 return trg; 281 } 282 if(isInstaneOf(src.getClass(), trg.getClass())) { 283 rating.plus(9); 284 return trg; 285 } 286 if(src.equals(trg)) { 287 rating.plus(8); 288 return trg; 289 } 290 291 // different number 292 boolean bothNumbers=src instanceof Number && trg instanceof Number; 293 if(bothNumbers && ((Number)src).doubleValue()==((Number)trg).doubleValue()) { 294 rating.plus(7); 295 return trg; 296 } 297 298 299 300 String sSrc=Caster.toString(src,null); 301 String sTrg=Caster.toString(trg,null); 302 if(sSrc!=null && sTrg!=null) { 303 304 // different number types 305 if(src instanceof Number && trg instanceof Number && sSrc.equals(sTrg)) { 306 rating.plus(6); 307 return trg; 308 } 309 310 // looks the same 311 if(sSrc.equals(sTrg)) { 312 rating.plus(5); 313 return trg; 314 } 315 if(sSrc.equalsIgnoreCase(sTrg)) { 316 rating.plus(4); 317 return trg; 318 } 319 } 320 321 // CF Equal 322 try { 323 if(Operator.equals(src, trg, false, true)) { 324 rating.plus(3); 325 return trg; 326 } 327 } catch (Throwable t) { 328 ExceptionUtil.rethrowIfNecessary(t); 329 } 330 331 332 return trg; 333 } 334 return _convert(src, trgClass); 335 } 336 337 public static Object _convert(Object src, Class trgClass) throws PageException { 338 if(src==null) { 339 if(trgClass.isPrimitive()) 340 throw new ApplicationException("can't convert [null] to ["+trgClass.getName()+"]"); 341 return null; 342 } 343 if(like(src.getClass(), trgClass)) return src; 344 String className=trgClass.getName(); 345 346 347 if(src instanceof ObjectWrap) { 348 src = ((ObjectWrap) src).getEmbededObject(); 349 return _convert(src, trgClass); 350 } 351 if(className.startsWith("java.lang.")){ 352 if(trgClass==Boolean.class) return Caster.toBoolean(src); 353 if(trgClass==Integer.class) return Caster.toInteger(src); 354 if(trgClass==String.class) return Caster.toString(src); 355 if(trgClass==Byte.class) return Caster.toByte(src); 356 if(trgClass==Short.class) return Caster.toShort(src); 357 if(trgClass==Long.class) return Caster.toLong(src); 358 if(trgClass==Float.class) return Caster.toFloat(src); 359 if(trgClass==Double.class) return Caster.toDouble(src); 360 if(trgClass==Character.class) { 361 String str=Caster.toString(src,null); 362 if(str!=null && str.length()==1) return new Character(str.charAt(0)); 363 } 364 } 365 366 if(Decision.isArray(src)) { 367 if(trgClass.isArray()) { 368 return toNativeArray(trgClass,src); 369 } 370 else if(isInstaneOf(trgClass, List.class)) { 371 return Caster.toList(src); 372 } 373 else if(isInstaneOf(trgClass, Array.class)) { 374 return Caster.toArray(src); 375 } 376 } 377 378 if(trgClass==Calendar.class && Decision.isDate(src, true)) { 379 TimeZone tz = ThreadLocalPageContext.getTimeZone(); 380 return Caster.toCalendar(Caster.toDate(src, tz),tz,Locale.US); 381 } 382 383 if(trgClass==Date.class) return Caster.toDate(src,true,null); 384 else if(trgClass==Query.class) return Caster.toQuery(src); 385 else if(trgClass==Map.class) return Caster.toMap(src); 386 else if(trgClass==Struct.class) return Caster.toStruct(src); 387 else if(trgClass==Resource.class) return Caster.toResource(ThreadLocalPageContext.get(),src,false); 388 // this 2 method are used to support conversion that match neo src types 389 else if(trgClass==Hashtable.class) return Caster.toHashtable(src); 390 else if(trgClass==Vector.class) return Caster.toVetor(src); 391 else if(trgClass==java.util.Collection.class) return Caster.toJavaCollection(src); 392 else if(trgClass==TimeZone.class && Decision.isString(src)) return Caster.toTimeZone(Caster.toString(src)); 393 else if(trgClass==Collection.Key.class) return KeyImpl.toKey(src); 394 else if(trgClass==Locale.class && Decision.isString(src)) return Caster.toLocale(Caster.toString(src)); 395 else if(Reflector.isInstaneOf(trgClass, Pojo.class) && src instanceof Map) { 396 Struct sct=Caster.toStruct(src); 397 try{ 398 Pojo pojo=(Pojo) trgClass.newInstance(); 399 if(sct instanceof Component) 400 return AxisCaster.toPojo(pojo, null, null, null, (Component)sct, new HashSet<Object>()); 401 return AxisCaster.toPojo(pojo, null, null, null,sct, new HashSet<Object>()); 402 } 403 catch(Throwable t){ 404 ExceptionUtil.rethrowIfNecessary(t); 405 } 406 } 407 if(trgClass.isPrimitive()) { 408 //return convert(src,srcClass,toReferenceClass(trgClass)); 409 return _convert(src,toReferenceClass(trgClass)); 410 } 411 throw new ApplicationException("can't convert ["+Caster.toClassName(src)+"] to ["+Caster.toClassName(trgClass)+"]"); 412 } 413 414 /** 415 * gets Constructor Instance matching given parameter 416 * @param clazz Clazz to Invoke 417 * @param args Matching args 418 * @return Matching ConstructorInstance 419 * @throws NoSuchMethodException 420 * @throws PageException 421 */ 422 423 public static ConstructorInstance getConstructorInstance(Class clazz, Object[] args) throws NoSuchMethodException { 424 ConstructorInstance ci=getConstructorInstance(clazz, args,null); 425 if(ci!=null) return ci; 426 throw new NoSuchMethodException("No matching Constructor for "+clazz.getName()+"("+getDspMethods(getClasses(args))+") found"); 427 } 428 429 public static ConstructorInstance getConstructorInstance(Class clazz, Object[] args, ConstructorInstance defaultValue) { 430 args=cleanArgs(args); 431 Constructor[] constructors=cStorage.getConstructors(clazz,args.length);//getConstructors(clazz); 432 if(constructors!=null) { 433 Class[] clazzArgs = getClasses(args); 434 // exact comparsion 435 outer:for(int i=0;i<constructors.length;i++) { 436 if(constructors[i]!=null) { 437 438 Class[] parameterTypes = constructors[i].getParameterTypes(); 439 for(int y=0;y<parameterTypes.length;y++) { 440 if(toReferenceClass(parameterTypes[y])!=clazzArgs[y]) continue outer; 441 } 442 return new ConstructorInstance(constructors[i],args); 443 } 444 } 445 // like comparsion 446 outer:for(int i=0;i<constructors.length;i++) { 447 if(constructors[i]!=null) { 448 Class[] parameterTypes = constructors[i].getParameterTypes(); 449 for(int y=0;y<parameterTypes.length;y++) { 450 if(!like(clazzArgs[y],toReferenceClass(parameterTypes[y]))) continue outer; 451 } 452 return new ConstructorInstance(constructors[i],args); 453 } 454 } 455 // convert comparsion 456 ConstructorInstance ci=null; 457 int _rating=0; 458 outer:for(int i=0;i<constructors.length;i++) { 459 if(constructors[i]!=null) { 460 RefInteger rating=(constructors.length>1)?new RefIntegerImpl(0):null; 461 Class[] parameterTypes = constructors[i].getParameterTypes(); 462 Object[] newArgs = new Object[args.length]; 463 for(int y=0;y<parameterTypes.length;y++) { 464 try { 465 newArgs[y]=convert(args[y],toReferenceClass(parameterTypes[y]),rating); 466 } catch (PageException e) { 467 continue outer; 468 } 469 } 470 if(ci==null || rating.toInt()>_rating) { 471 if(rating!=null)_rating=rating.toInt(); 472 ci=new ConstructorInstance(constructors[i],newArgs); 473 } 474 //return new ConstructorInstance(constructors[i],newArgs); 475 } 476 } 477 return ci; 478 } 479 return defaultValue; 480 //throw new NoSuchMethodException("No matching Constructor for "+clazz.getName()+"("+getDspMethods(getClasses(args))+") found"); 481 } 482 483 /** 484 * gets the MethodInstance matching given Parameter 485 * @param objMaybeNull maybe null 486 * @param clazz Class Of the Method to get 487 * @param methodName Name of the Method to get 488 * @param args Arguments of the Method to get 489 * @return return Matching Method 490 * @throws 491 */ 492 public static MethodInstance getMethodInstanceEL(Object objMaybeNull,Class clazz, Collection.Key methodName, Object[] args) { 493 checkAccessibility(objMaybeNull,clazz, methodName); 494 args=cleanArgs(args); 495 496 Method[] methods = mStorage.getMethods(clazz,methodName,args.length);//getDeclaredMethods(clazz); 497 498 if(methods!=null) { 499 Class[] clazzArgs = getClasses(args); 500 // exact comparsion 501 //print.e("exact:"+methodName); 502 outer:for(int i=0;i<methods.length;i++) { 503 if(methods[i]!=null) { 504 Class[] parameterTypes = methods[i].getParameterTypes(); 505 for(int y=0;y<parameterTypes.length;y++) { 506 if(toReferenceClass(parameterTypes[y])!=clazzArgs[y]) continue outer; 507 } 508 return new MethodInstance(methods[i],args); 509 } 510 } 511 // like comparsion 512 //MethodInstance mi=null; 513 // print.e("like:"+methodName); 514 outer:for(int i=0;i<methods.length;i++) { 515 if(methods[i]!=null) { 516 Class[] parameterTypes = methods[i].getParameterTypes(); 517 for(int y=0;y<parameterTypes.length;y++) { 518 if(!like(clazzArgs[y],toReferenceClass(parameterTypes[y]))) continue outer; 519 } 520 return new MethodInstance(methods[i],args); 521 } 522 } 523 524 525 // convert comparsion 526 // print.e("convert:"+methodName); 527 MethodInstance mi=null; 528 int _rating=0; 529 outer:for(int i=0;i<methods.length;i++) { 530 if(methods[i]!=null) { 531 RefInteger rating=(methods.length>1)?new RefIntegerImpl(0):null; 532 Class[] parameterTypes = methods[i].getParameterTypes(); 533 Object[] newArgs = new Object[args.length]; 534 for(int y=0;y<parameterTypes.length;y++) { 535 try { 536 newArgs[y]=convert(args[y],toReferenceClass(parameterTypes[y]),rating); 537 } catch (PageException e) { 538 continue outer; 539 } 540 } 541 if(mi==null || rating.toInt()>_rating) { 542 if(rating!=null)_rating=rating.toInt(); 543 mi=new MethodInstance(methods[i],newArgs); 544 } 545 //return new MethodInstance(methods[i],newArgs); 546 } 547 }return mi; 548 } 549 return null; 550 } 551 552 553 private static Object[] cleanArgs(Object[] args) { 554 Set<Object> done=new HashSet<Object>(); 555 if(args==null) return args; 556 557 for(int i=0;i<args.length;i++){ 558 args[i]=_clean(done,args[i]); 559 } 560 return args; 561 } 562 563 564 private static Object _clean(Set<Object> done,Object obj) { 565 if(done.contains(obj)) return obj; 566 done.add(obj); 567 try { 568 if(obj instanceof ObjectWrap) { 569 try { 570 return ((ObjectWrap)obj).getEmbededObject(); 571 } catch (PageException e) { 572 return obj; 573 } 574 } 575 if(obj instanceof Collection) return _clean(done,(Collection)obj); 576 if(obj instanceof Map) return _clean(done,(Map)obj); 577 if(obj instanceof List) return _clean(done,(List)obj); 578 if(obj instanceof Object[]) return _clean(done,(Object[])obj); 579 } 580 finally { 581 done.remove(obj); 582 } 583 return obj; 584 } 585 586 private static Object _clean(Set<Object> done,Collection coll) { 587 Iterator<Object> vit = coll.valueIterator(); 588 Object v; 589 boolean change=false; 590 while(vit.hasNext()){ 591 v=vit.next(); 592 if(v!=_clean(done,v)) { 593 change=true; 594 break; 595 } 596 } 597 if(!change) return coll; 598 599 coll=coll.duplicate(false); 600 Iterator<Entry<Key, Object>> eit = coll.entryIterator(); 601 Entry<Key, Object> e; 602 while(eit.hasNext()){ 603 e=eit.next(); 604 coll.setEL(e.getKey(), _clean(done,e.getValue())); 605 } 606 607 return coll; 608 } 609 610 private static Object _clean(Set<Object> done,Map map) { 611 Iterator vit = map.values().iterator(); 612 Object v; 613 boolean change=false; 614 while(vit.hasNext()){ 615 v=vit.next(); 616 if(v!=_clean(done,v)) { 617 change=true; 618 break; 619 } 620 } 621 if(!change) return map; 622 623 map=Duplicator.duplicateMap(map, false); 624 Iterator<Entry> eit = map.entrySet().iterator(); 625 Entry e; 626 while(eit.hasNext()){ 627 e=eit.next(); 628 map.put(e.getKey(), _clean(done,e.getValue())); 629 } 630 631 return map; 632 } 633 634 private static Object _clean(Set<Object> done,List list) { 635 Iterator it = list.iterator(); 636 Object v; 637 boolean change=false; 638 while(it.hasNext()){ 639 v=it.next(); 640 if(v!=_clean(done,v)) { 641 change=true; 642 break; 643 } 644 } 645 if(!change) return list; 646 647 list=Duplicator.duplicateList(list, false); 648 it = list.iterator(); 649 while(it.hasNext()){ 650 list.add(_clean(done,it.next())); 651 } 652 653 return list; 654 } 655 656 private static Object _clean(Set<Object> done,Object[] src) { 657 boolean change=false; 658 for(int i=0;i<src.length;i++){ 659 if(src[i]!=_clean(done,src[i])) { 660 change=true; 661 break; 662 } 663 } 664 if(!change) return src; 665 666 Object[] trg=new Object[src.length]; 667 for(int i=0;i<trg.length;i++) { 668 trg[i]=_clean(done,src[i]); 669 } 670 671 return trg; 672 } 673 674 /** 675 * gets the MethodInstance matching given Parameter 676 * @param clazz Class Of the Method to get 677 * @param methodName Name of the Method to get 678 * @param args Arguments of the Method to get 679 * @return return Matching Method 680 * @throws NoSuchMethodException 681 * @throws PageException 682 */ 683 public static MethodInstance getMethodInstance(Object obj,Class clazz, String methodName, Object[] args) 684 throws NoSuchMethodException { 685 MethodInstance mi=getMethodInstanceEL(obj,clazz, KeyImpl.getInstance(methodName), args); 686 if(mi!=null) return mi; 687 688 Class[] classes = getClasses(args); 689 //StringBuilder sb=null; 690 JavaObject jo; 691 Class c; 692 ConstructorInstance ci; 693 for(int i=0;i<classes.length;i++){ 694 if(args[i] instanceof JavaObject) { 695 jo=(JavaObject) args[i]; 696 c=jo.getClazz(); 697 ci = Reflector.getConstructorInstance(c, new Object[0], null); 698 if(ci==null) { 699 700 throw new NoSuchMethodException("The "+pos(i+1)+" parameter of "+methodName+"("+getDspMethods(classes)+") ia a object created " + 701 "by the createObject function (JavaObject/JavaProxy). This object has not been instantiated because it does not have a constructor " + 702 "that takes zero arguments. Lucee cannot instantiate it for you, please use the .init(...) method to instantiate it with the correct parameters first"); 703 704 705 } 706 } 707 } 708 /* 709 the argument list contains objects created by createObject, 710 that are no instantiated (first,third,10th) and because this object have no constructor taking no arguments, Lucee cannot instantiate them. 711 you need first to instantiate this objects. 712 */ 713 throw new NoSuchMethodException("No matching Method for "+methodName+"("+getDspMethods(classes)+") found for "+ 714 Caster.toTypeName(clazz)); 715 } 716 717 private static String pos(int index) { 718 if(index==1) return "first"; 719 if(index==2) return "second"; 720 if(index==3) return "third"; 721 722 return index+"th"; 723 } 724 725 /** 726 * same like method getField from Class but ignore case from field name 727 * @param clazz class to search the field 728 * @param name name to search 729 * @return Matching Field 730 * @throws NoSuchFieldException 731 732 */ 733 public static Field[] getFieldsIgnoreCase(Class clazz, String name) throws NoSuchFieldException { 734 Field[] fields=fStorage.getFields(clazz,name); 735 if(fields!=null) return fields; 736 throw new NoSuchFieldException("there is no field with name "+name+" in object ["+Type.getName(clazz)+"]"); 737 } 738 739 public static Field[] getFieldsIgnoreCase(Class clazz, String name, Field[] defaultValue) { 740 Field[] fields=fStorage.getFields(clazz,name); 741 if(fields!=null) return fields; 742 return defaultValue; 743 744 745 } 746 747 public static String[] getPropertyKeys(Class clazz) { 748 Set keys=new HashSet(); 749 Field[] fields = clazz.getFields(); 750 Field field; 751 Method[] methods = clazz.getMethods(); 752 Method method; 753 String name; 754 755 for(int i=0;i<fields.length;i++) { 756 field=fields[i]; 757 if(Modifier.isPublic(field.getModifiers()) )keys.add(field.getName()); 758 } 759 760 for(int i=0;i<methods.length;i++) { 761 method=methods[i]; 762 if(Modifier.isPublic(method.getModifiers()) ) { 763 if(isGetter(method)) { 764 name=method.getName(); 765 if(name.startsWith("get"))keys.add(method.getName().substring(3)); 766 else keys.add(method.getName().substring(2)); 767 } 768 else if(isSetter(method)) keys.add(method.getName().substring(3)); 769 } 770 } 771 772 return (String[]) keys.toArray(new String[keys.size()]); 773 } 774 775 public static boolean hasPropertyIgnoreCase(Class clazz, String name) { 776 if(hasFieldIgnoreCase(clazz, name)) return true; 777 778 Method[] methods = clazz.getMethods(); 779 Method method; 780 String n; 781 for(int i=0;i<methods.length;i++) { 782 method=methods[i]; 783 if(Modifier.isPublic(method.getModifiers()) && StringUtil.endsWithIgnoreCase(method.getName(),name)) { 784 n=null; 785 if(isGetter(method)) { 786 n=method.getName(); 787 if(n.startsWith("get"))n=method.getName().substring(3); 788 else n=method.getName().substring(2); 789 } 790 else if(isSetter(method)) n=method.getName().substring(3); 791 if(n!=null && n.equalsIgnoreCase(name)) return true; 792 } 793 } 794 return false; 795 } 796 797 798 public static boolean hasFieldIgnoreCase(Class clazz, String name) { 799 return !ArrayUtil.isEmpty(getFieldsIgnoreCase(clazz, name, null)); 800 //getFieldIgnoreCaseEL(clazz, name)!=null; 801 } 802 803 804 /** 805 * call constructor of a class with matching arguments 806 * @param clazz Class to get Instance 807 * @param args Arguments for the Class 808 * @return invoked Instance 809 * @throws PageException 810 */ 811 public static Object callConstructor(Class clazz, Object[] args) throws PageException { 812 args=cleanArgs(args); 813 try { 814 return getConstructorInstance(clazz,args).invoke(); 815 } 816 catch (InvocationTargetException e) { 817 Throwable target = e.getTargetException(); 818 if(target instanceof PageException) throw (PageException)target; 819 throw Caster.toPageException(e.getTargetException()); 820 } 821 catch (Exception e) { 822 throw Caster.toPageException(e); 823 } 824 } 825 826 public static Object callConstructor(Class clazz, Object[] args, Object defaultValue) { 827 args=cleanArgs(args); 828 try { 829 ConstructorInstance ci = getConstructorInstance(clazz,args,null); 830 if(ci==null) return defaultValue; 831 return ci.invoke(); 832 } 833 catch (Throwable t) { 834 ExceptionUtil.rethrowIfNecessary(t); 835 return defaultValue; 836 } 837 } 838 839 /** 840 * calls a Method of a Objct 841 * @param obj Object to call Method on it 842 * @param methodName Name of the Method to get 843 * @param args Arguments of the Method to get 844 * @return return return value of the called Method 845 * @throws PageException 846 */ 847 public static Object callMethod(Object obj, String methodName, Object[] args) throws PageException { 848 return callMethod(obj, KeyImpl.getInstance(methodName), args); 849 } 850 851 public static Object callMethod(Object obj, Collection.Key methodName, Object[] args) throws PageException { 852 if(obj==null) { 853 throw new ExpressionException("can't call method ["+methodName+"] on object, object is null"); 854 } 855 856 //checkAccesibility(obj,methodName); 857 858 859 MethodInstance mi=getMethodInstanceEL(obj,obj.getClass(), methodName, args); 860 if(mi==null) 861 throw throwCall(obj,methodName,args); 862 try { 863 return mi.invoke(obj); 864 } 865 catch (InvocationTargetException e) { 866 Throwable target = e.getTargetException(); 867 if(target instanceof PageException) throw (PageException)target; 868 throw new NativeException(e.getTargetException()); 869 } 870 catch (Exception e) { 871 throw new NativeException(e); 872 } 873 } 874 875 private static void checkAccessibility(Object objMaybeNull,Class clazz, Key methodName) { 876 // do not allow java.lang.System.exit() 877 if(methodName.equals(EXIT) && (clazz==System.class || clazz==Runtime.class)) { // TODO better implementation 878 throw new PageRuntimeException(new SecurityException("Calling the exit method is not allowed")); 879 } 880 // change the accessibility of Lucee methods is not allowed 881 else if(methodName.equals(SET_ACCESSIBLE)) { 882 if(objMaybeNull instanceof JavaObject) 883 objMaybeNull=((JavaObject)objMaybeNull).getEmbededObject(null); 884 if(objMaybeNull instanceof Member) { 885 Member member=(Member) objMaybeNull; 886 Class<?> cls = member.getDeclaringClass(); 887 if(cls!=null) { 888 String name=cls.getName(); 889 if(name!=null && name.startsWith("lucee.")) { 890 throw new PageRuntimeException(new SecurityException("Changing the accessibility of an object's members in the lucee.* package is not allowed")); 891 } 892 } 893 894 } 895 } 896 } 897 898 /*private static void checkAccesibilityx(Object obj, Key methodName) { 899 if(methodName.equals(SET_ACCESSIBLE) && obj instanceof Member) { 900 if(true) return; 901 Member member=(Member) obj; 902 Class<?> cls = member.getDeclaringClass(); 903 if(cls.getPackage().getName().startsWith("lucee.")) { 904 throw new PageRuntimeException(new SecurityException("Changing the accesibility of an object's members in the lucee.* package is not allowed")); 905 } 906 } 907 }*/ 908 909 public static Object callMethod(Object obj, Collection.Key methodName, Object[] args, Object defaultValue) { 910 if(obj==null) { 911 return defaultValue; 912 } 913 //checkAccesibility(obj,methodName); 914 915 MethodInstance mi=getMethodInstanceEL(obj,obj.getClass(), methodName, args); 916 if(mi==null) 917 return defaultValue; 918 try { 919 return mi.invoke(obj); 920 } 921 catch (Throwable t) { 922 ExceptionUtil.rethrowIfNecessary(t); 923 return defaultValue; 924 } 925 } 926 927 public static ExpressionException throwCall(Object obj,String methodName, Object[] args) { 928 return new ExpressionException("No matching Method/Function for "+Type.getName(obj)+"."+methodName+"("+getDspMethods(getClasses(args))+") found"); 929 } 930 public static ExpressionException throwCall(Object obj,Collection.Key methodName, Object[] args) { 931 return new ExpressionException("No matching Method/Function for "+Type.getName(obj)+"."+methodName+"("+getDspMethods(getClasses(args))+") found"); 932 } 933 934 /** 935 * calls a Static Method on the given CLass 936 * @param clazz Class to call Method on it 937 * @param methodName Name of the Method to get 938 * @param args Arguments of the Method to get 939 * @return return return value of the called Method 940 * @throws PageException 941 */ 942 public static Object callStaticMethod(Class clazz, String methodName, Object[] args) throws PageException { 943 try { 944 return getMethodInstance(null,clazz,methodName,args).invoke(null); 945 } 946 catch (InvocationTargetException e) { 947 Throwable target = e.getTargetException(); 948 if(target instanceof PageException) throw (PageException)target; 949 throw Caster.toPageException(e.getTargetException()); 950 } 951 catch (Exception e) { 952 throw Caster.toPageException(e); 953 } 954 } 955 956 /** 957 * to get a Getter Method of a Object 958 * @param clazz Class to invoke method from 959 * @param prop Name of the Method without get 960 * @return return Value of the getter Method 961 * @throws NoSuchMethodException 962 * @throws PageException 963 */ 964 public static MethodInstance getGetter(Class clazz, String prop) throws PageException, NoSuchMethodException { 965 String getterName = "get"+StringUtil.ucFirst(prop); 966 MethodInstance mi = getMethodInstanceEL(null,clazz,KeyImpl.getInstance(getterName),ArrayUtil.OBJECT_EMPTY); 967 968 if(mi==null){ 969 String isName = "is"+StringUtil.ucFirst(prop); 970 mi = getMethodInstanceEL(null,clazz,KeyImpl.getInstance(isName),ArrayUtil.OBJECT_EMPTY); 971 if(mi!=null){ 972 Method m = mi.getMethod(); 973 Class rtn = m.getReturnType(); 974 if(rtn!=Boolean.class && rtn!=boolean.class) mi=null; 975 } 976 } 977 978 979 if(mi==null) 980 throw new ExpressionException("No matching property ["+prop+"] found in ["+Caster.toTypeName(clazz)+"]"); 981 Method m=mi.getMethod(); 982 983 if(m.getReturnType()==void.class) 984 throw new NoSuchMethodException("invalid return Type, method ["+m.getName()+"] for Property ["+getterName+"] must have return type not void"); 985 986 return mi; 987 } 988 989 /** 990 * to get a Getter Method of a Object 991 * @param clazz Class to invoke method from 992 * @param prop Name of the Method without get 993 * @return return Value of the getter Method 994 */ 995 public static MethodInstance getGetterEL(Class clazz, String prop) { 996 prop="get"+StringUtil.ucFirst(prop); 997 MethodInstance mi = getMethodInstanceEL(null,clazz,KeyImpl.getInstance(prop),ArrayUtil.OBJECT_EMPTY); 998 if(mi==null) return null; 999 if(mi.getMethod().getReturnType()==void.class) return null; 1000 return mi; 1001 } 1002 1003 /** 1004 * to invoke a getter Method of a Object 1005 * @param obj Object to invoke method from 1006 * @param prop Name of the Method without get 1007 * @return return Value of the getter Method 1008 * @throws PageException 1009 */ 1010 public static Object callGetter(Object obj, String prop) throws PageException { 1011 try { 1012 return getGetter(obj.getClass(), prop).invoke(obj); 1013 } 1014 catch (InvocationTargetException e) { 1015 Throwable target = e.getTargetException(); 1016 if(target instanceof PageException) throw (PageException)target; 1017 throw Caster.toPageException(e.getTargetException()); 1018 } 1019 catch (Exception e) { 1020 throw Caster.toPageException(e); 1021 } 1022 } 1023 1024 /** 1025 * to invoke a setter Method of a Object 1026 * @param obj Object to invoke method from 1027 * @param prop Name of the Method without get 1028 * @param value Value to set to the Method 1029 * @return MethodInstance 1030 * @throws NoSuchMethodException 1031 * @throws PageException 1032 */ 1033 public static MethodInstance getSetter(Object obj, String prop,Object value) throws NoSuchMethodException { 1034 prop="set"+StringUtil.ucFirst(prop); 1035 MethodInstance mi = getMethodInstance(obj,obj.getClass(),prop,new Object[]{value}); 1036 Method m=mi.getMethod(); 1037 1038 if(m.getReturnType()!=void.class) 1039 throw new NoSuchMethodException("invalid return Type, method ["+m.getName()+"] must have return type void, now ["+m.getReturnType().getName()+"]"); 1040 return mi; 1041 } 1042 1043 1044 1045 1046 /* 1047 * to invoke a setter Method of a Object 1048 * @param obj Object to invoke method from 1049 * @param prop Name of the Method without get 1050 * @param value Value to set to the Method 1051 * @return MethodInstance 1052 * @deprecated use instead <code>getSetter(Object obj, String prop,Object value, MethodInstance defaultValue)</code> 1053 1054 public static MethodInstance getSetterEL(Object obj, String prop,Object value) { 1055 prop="set"+StringUtil.ucFirst(prop); 1056 MethodInstance mi = getMethodInstanceEL(obj.getClass(),KeyImpl.getInstance(prop),new Object[]{value}); 1057 if(mi==null) return null; 1058 Method m=mi.getMethod(); 1059 1060 if(m.getReturnType()!=void.class) return null; 1061 return mi; 1062 }*/ 1063 1064 /** 1065 * to invoke a setter Method of a Object 1066 * @param obj Object to invoke method from 1067 * @param prop Name of the Method without get 1068 * @param value Value to set to the Method 1069 * @return MethodInstance 1070 */ 1071 public static MethodInstance getSetter(Object obj, String prop,Object value, MethodInstance defaultValue) { 1072 prop="set"+StringUtil.ucFirst(prop); 1073 MethodInstance mi = getMethodInstanceEL(obj,obj.getClass(),KeyImpl.getInstance(prop),new Object[]{value}); 1074 if(mi==null) return defaultValue; 1075 Method m=mi.getMethod(); 1076 1077 if(m.getReturnType()!=void.class) return defaultValue; 1078 return mi; 1079 } 1080 1081 /** 1082 * to invoke a setter Method of a Object 1083 * @param obj Object to invoke method from 1084 * @param prop Name of the Method without get 1085 * @param value Value to set to the Method 1086 * @throws PageException 1087 */ 1088 public static void callSetter(Object obj, String prop,Object value) throws PageException { 1089 try { 1090 getSetter(obj, prop, value).invoke(obj); 1091 } 1092 catch (InvocationTargetException e) { 1093 Throwable target = e.getTargetException(); 1094 if(target instanceof PageException) throw (PageException)target; 1095 throw Caster.toPageException(e.getTargetException()); 1096 } 1097 catch (Exception e) { 1098 throw Caster.toPageException(e); 1099 } 1100 } 1101 1102 /** 1103 * do nothing when not exist 1104 * @param obj 1105 * @param prop 1106 * @param value 1107 * @throws PageException 1108 */ 1109 public static void callSetterEL(Object obj, String prop,Object value) throws PageException { 1110 try { 1111 MethodInstance setter = getSetter(obj, prop, value,null); 1112 if(setter!=null)setter.invoke(obj); 1113 } 1114 catch (InvocationTargetException e) { 1115 Throwable target = e.getTargetException(); 1116 if(target instanceof PageException) throw (PageException)target; 1117 throw Caster.toPageException(e.getTargetException()); 1118 } 1119 catch (Exception e) { 1120 throw Caster.toPageException(e); 1121 } 1122 } 1123 1124 /** 1125 * to get a visible Field of a object 1126 * @param obj Object to invoke 1127 * @param prop property to call 1128 * @return property value 1129 * @throws PageException 1130 */ 1131 public static Object getField(Object obj, String prop) throws PageException { 1132 try { 1133 return getFieldsIgnoreCase(obj.getClass(),prop)[0].get(obj); 1134 } 1135 catch (Throwable e) { 1136 throw Caster.toPageException(e); 1137 } 1138 } 1139 1140 public static Object getField(Object obj, String prop, Object defaultValue) { 1141 if(obj==null) return defaultValue; 1142 Field[] fields = getFieldsIgnoreCase(obj.getClass(),prop,null); 1143 if(ArrayUtil.isEmpty(fields)) return defaultValue; 1144 1145 try { 1146 return fields[0].get(obj); 1147 } catch (Throwable t) { 1148 ExceptionUtil.rethrowIfNecessary(t); 1149 return defaultValue; 1150 } 1151 } 1152 1153 /** 1154 * assign a value to a visible Field of a object 1155 * @param obj Object to assign value to his property 1156 * @param prop name of property 1157 * @param value Value to assign 1158 * @throws PageException 1159 */ 1160 public static boolean setField(Object obj, String prop,Object value) throws PageException { 1161 Class clazz=value.getClass(); 1162 try { 1163 Field[] fields = getFieldsIgnoreCase(obj.getClass(),prop); 1164 // exact comparsion 1165 for(int i=0;i<fields.length;i++) { 1166 if(toReferenceClass(fields[i].getType())==clazz){ 1167 fields[i].set(obj,value); 1168 return true; 1169 } 1170 } 1171 // like comparsion 1172 for(int i=0;i<fields.length;i++) { 1173 if(like(fields[i].getType(),clazz)) { 1174 fields[i].set(obj,value); 1175 return true; 1176 } 1177 } 1178 // convert comparsion 1179 for(int i=0;i<fields.length;i++) { 1180 try { 1181 fields[i].set(obj,convert(value,toReferenceClass(fields[i].getType()),null)); 1182 return true; 1183 } catch (PageException e) {} 1184 } 1185 } 1186 catch (Exception e) { 1187 throw Caster.toPageException(e); 1188 } 1189 return false; 1190 } 1191 1192 /** 1193 * to get a visible Propety (Field or Getter) of a object 1194 * @param obj Object to invoke 1195 * @param prop property to call 1196 * @return property value 1197 * @throws PageException 1198 */ 1199 public static Object getProperty(Object obj, String prop) throws PageException { 1200 Object rtn=getField(obj,prop,NULL);// NULL is used because the field can contain null as well 1201 if(rtn!=NULL) return rtn; 1202 1203 char first=prop.charAt(0); 1204 if(first>='0' && first<='9') throw new ApplicationException("there is no property with name ["+prop+"] found in ["+Caster.toTypeName(obj)+"]"); 1205 return callGetter(obj,prop); 1206 1207 } 1208 1209 /** 1210 * to get a visible Propety (Field or Getter) of a object 1211 * @param obj Object to invoke 1212 * @param prop property to call 1213 * @return property value 1214 */ 1215 public static Object getProperty(Object obj, String prop, Object defaultValue) { 1216 1217 // first try field 1218 Field[] fields = getFieldsIgnoreCase(obj.getClass(),prop,null); 1219 if(!ArrayUtil.isEmpty(fields)) { 1220 try { 1221 return fields[0].get(obj); 1222 } catch (Throwable t) { 1223 ExceptionUtil.rethrowIfNecessary(t); 1224 } 1225 } 1226 1227 // then getter 1228 try { 1229 char first=prop.charAt(0); 1230 if(first>='0' && first<='9') return defaultValue; 1231 return getGetter(obj.getClass(), prop).invoke(obj); 1232 } catch (Throwable e1) { 1233 ExceptionUtil.rethrowIfNecessary(e1); 1234 return defaultValue; 1235 } 1236 } 1237 1238 /** 1239 * assign a value to a visible Property (Field or Setter) of a object 1240 * @param obj Object to assign value to his property 1241 * @param prop name of property 1242 * @param value Value to assign 1243 * @throws PageException 1244 */ 1245 public static void setProperty(Object obj, String prop,Object value) throws PageException{ 1246 boolean done=false; 1247 try { 1248 if(setField(obj,prop,value))done=true; 1249 } 1250 catch (Throwable t) { 1251 ExceptionUtil.rethrowIfNecessary(t); 1252 1253 } 1254 if(!done)callSetter(obj,prop,value); 1255 } 1256 1257 /** 1258 * assign a value to a visible Property (Field or Setter) of a object 1259 * @param obj Object to assign value to his property 1260 * @param prop name of property 1261 * @param value Value to assign 1262 */ 1263 public static void setPropertyEL(Object obj, String prop,Object value) { 1264 1265 // first check for field 1266 Field[] fields = getFieldsIgnoreCase(obj.getClass(),prop,null); 1267 if(!ArrayUtil.isEmpty(fields)){ 1268 try { 1269 fields[0].set(obj,value); 1270 return; 1271 } catch (Throwable t) { 1272 ExceptionUtil.rethrowIfNecessary(t); 1273 } 1274 } 1275 1276 // then check for setter 1277 try { 1278 getSetter(obj, prop, value).invoke(obj); 1279 } 1280 catch (Throwable t) { 1281 ExceptionUtil.rethrowIfNecessary(t); 1282 } 1283 1284 } 1285 1286 1287 1288 private static Object toNativeArray(Class clazz, Object obj) throws PageException { 1289 //if(obj.getClass()==clazz) return obj; 1290 Object[] objs=null; 1291 if(obj instanceof Array) objs=toRefArray((Array)obj); 1292 else if(obj instanceof List) objs=toRefArray((List)obj); 1293 else if(Decision.isNativeArray(obj)) { 1294 if(obj.getClass()==boolean[].class) objs=toRefArray((boolean[])obj); 1295 else if(obj.getClass()==byte[].class) objs=toRefArray((byte[])obj); 1296 else if(obj.getClass()==char[].class) objs=toRefArray((char[])obj); 1297 else if(obj.getClass()==short[].class) objs=toRefArray((short[])obj); 1298 else if(obj.getClass()==int[].class) objs=toRefArray((int[])obj); 1299 else if(obj.getClass()==long[].class) objs=toRefArray((long[])obj); 1300 else if(obj.getClass()==float[].class) objs=toRefArray((float[])obj); 1301 else if(obj.getClass()==double[].class) objs=toRefArray((double[])obj); 1302 else objs=(Object[])obj;//toRefArray((Object[])obj); 1303 1304 } 1305 if(clazz==objs.getClass()) { 1306 return objs; 1307 } 1308 1309 //if(objs==null) return defaultValue; 1310 //Class srcClass = objs.getClass().getComponentType(); 1311 Class compClass = clazz.getComponentType(); 1312 Object rtn = java.lang.reflect.Array.newInstance(compClass, objs.length); 1313 //try{ 1314 for(int i=0;i<objs.length;i++) { 1315 java.lang.reflect.Array.set(rtn, i, convert(objs[i], compClass,null)); 1316 } 1317 1318 return rtn; 1319 } 1320 1321 1322 private static Object[] toRefArray(boolean[] src) { 1323 Boolean[] trg=new Boolean[src.length]; 1324 for(int i=0;i<trg.length;i++) { 1325 trg[i]=src[i]?Boolean.TRUE:Boolean.FALSE; 1326 } 1327 return trg; 1328 } 1329 1330 private static Byte[] toRefArray(byte[] src) { 1331 Byte[] trg=new Byte[src.length]; 1332 for(int i=0;i<trg.length;i++) { 1333 trg[i]=new Byte(src[i]); 1334 } 1335 return trg; 1336 } 1337 1338 private static Character[] toRefArray(char[] src) { 1339 Character[] trg=new Character[src.length]; 1340 for(int i=0;i<trg.length;i++) { 1341 trg[i]=new Character(src[i]); 1342 } 1343 return trg; 1344 } 1345 1346 private static Short[] toRefArray(short[] src) { 1347 Short[] trg=new Short[src.length]; 1348 for(int i=0;i<trg.length;i++) { 1349 trg[i]=Short.valueOf(src[i]); 1350 } 1351 return trg; 1352 } 1353 1354 private static Integer[] toRefArray(int[] src) { 1355 Integer[] trg=new Integer[src.length]; 1356 for(int i=0;i<trg.length;i++) { 1357 trg[i]=Integer.valueOf(src[i]); 1358 } 1359 return trg; 1360 } 1361 1362 private static Long[] toRefArray(long[] src) { 1363 Long[] trg=new Long[src.length]; 1364 for(int i=0;i<trg.length;i++) { 1365 trg[i]=Long.valueOf(src[i]); 1366 } 1367 return trg; 1368 } 1369 1370 private static Float[] toRefArray(float[] src) { 1371 Float[] trg=new Float[src.length]; 1372 for(int i=0;i<trg.length;i++) { 1373 trg[i]=new Float(src[i]); 1374 } 1375 return trg; 1376 } 1377 1378 private static Double[] toRefArray(double[] src) { 1379 Double[] trg=new Double[src.length]; 1380 for(int i=0;i<trg.length;i++) { 1381 trg[i]=new Double(src[i]); 1382 } 1383 return trg; 1384 } 1385 1386 private static Object[] toRefArray(Array array) throws PageException { 1387 Object[] objs=new Object[array.size()]; 1388 for(int i=0;i<objs.length;i++) { 1389 objs[i]=array.getE(i+1); 1390 } 1391 return objs; 1392 } 1393 1394 private static Object[] toRefArray(List list) { 1395 Object[] objs=new Object[list.size()]; 1396 for(int i=0;i<objs.length;i++) { 1397 objs[i]=list.get(i); 1398 } 1399 return objs; 1400 } 1401 1402 public static boolean isGetter(Method method) { 1403 if(method.getParameterTypes().length>0) return false; 1404 if(method.getReturnType()==void.class) return false; 1405 if(!method.getName().startsWith("get") && !method.getName().startsWith("is")) return false; 1406 if(method.getDeclaringClass()==Object.class) return false; 1407 return true; 1408 } 1409 1410 public static boolean isSetter(Method method) { 1411 if(method.getParameterTypes().length!=1) return false; 1412 if(method.getReturnType()!=void.class) return false; 1413 if(!method.getName().startsWith("set")) return false; 1414 if(method.getDeclaringClass()==Object.class) return false; 1415 return true; 1416 } 1417 1418 /** 1419 * return all methods that are defined by the class itself (not extended) 1420 * @param clazz 1421 * @return 1422 */ 1423 public static Method[] getDeclaredMethods(Class clazz) { 1424 Method[] methods = clazz.getMethods(); 1425 ArrayList list=new ArrayList(); 1426 for(int i=0;i<methods.length;i++) { 1427 if(methods[i].getDeclaringClass()==clazz) list.add(methods[i]); 1428 } 1429 if(list.size()==0) return new Method[0]; 1430 return (Method[]) list.toArray(new Method[list.size()]); 1431 } 1432 1433 public static Method[] getSetters(Class clazz) { 1434 Method[] methods = clazz.getMethods(); 1435 ArrayList list=new ArrayList(); 1436 for(int i=0;i<methods.length;i++) { 1437 if(isSetter(methods[i])) list.add(methods[i]); 1438 } 1439 if(list.size()==0) return new Method[0]; 1440 return (Method[]) list.toArray(new Method[list.size()]); 1441 } 1442 1443 public static Method[] getGetters(Class clazz) { 1444 Method[] methods = clazz.getMethods(); 1445 ArrayList list=new ArrayList(); 1446 for(int i=0;i<methods.length;i++) { 1447 if(isGetter(methods[i])) list.add(methods[i]); 1448 } 1449 if(list.size()==0) return new Method[0]; 1450 return (Method[]) list.toArray(new Method[list.size()]); 1451 } 1452 1453 /** 1454 * check if given class "from" can be converted to class "to" without explicit casting 1455 * @param from source class 1456 * @param to target class 1457 * @return is it possible to convert from "from" to "to" 1458 */ 1459 public static boolean canConvert(Class from, Class to) { 1460 // Identity Conversions 1461 if(from==to) return true; 1462 1463 // Widening Primitive Conversion 1464 if(from==byte.class) { 1465 return to==short.class || to==int.class || to==long.class || to==float.class || to==double.class ; 1466 } 1467 if(from==short.class) { 1468 return to==int.class || to==long.class || to==float.class || to==double.class ; 1469 } 1470 if(from==char.class) { 1471 return to==int.class || to==long.class || to==float.class || to==double.class ; 1472 } 1473 if(from==int.class) { 1474 return to==long.class || to==float.class || to==double.class ; 1475 } 1476 if(from==long.class) { 1477 return to==float.class || to==double.class ; 1478 } 1479 if(from==float.class) { 1480 return to==double.class ; 1481 } 1482 return false; 1483 } 1484 1485 public static String removeGetterPrefix(String name) { 1486 if(name.startsWith("get")) return name.substring(3); 1487 if(name.startsWith("is")) return name.substring(2); 1488 return name; 1489 } 1490 1491 1492 1493 1494}