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}