package org.itscool.commons.bean;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Iterator;

/**
 * Beanユーティリティクラス<br/>
 * JavaBeansの生成、メソッドの実行を行うクラスです。
 * @author KANO
 * @since jdk1.4.1
 * @version 1.00A 2004/11/1
 * @version 1.10A 2005/01/18 createInstance(String , String[] , Object[] ) 追加
 */
public class BeanUtil{
    /**
     * 引数classNameで指定されたクラスのgetInstanceメソッドを実行します。
     * @param className クラスの完全修飾名
     * @return getInstanceで生成されたオブジェクトを返します
     */
    public static Object getInstance(String className){
        Object obj = null;
        try{
            //クラスを取得
            Class cls = Class.forName(className);
            
            // メソッドを取得
            Method method = cls.getMethod("getInstance", null);
            
            
            // メソッドを実行
            obj = method.invoke(null, null);
        }catch( Exception e){
            String err = "[" + className + ":" + "getInstance" + "]" +
                "getProperty() failed (" + BeanUtil.class.getName() + ") (" +
                e.getMessage() + ")";
            throw new BeanUtilRuntimeException(err);
        }
        return obj;
    }
    
    /**
     * JavaBeansインスタンスの生成<BR>
     * 指定されたクラスのJavaBeansインスタンスを生成します。
     * @param className クラス名
     * @return Object 生成されたJavaBeansインスタンスを返します
     */
    public static Object createInstance(String className)
    throws BeanUtilRuntimeException{
        Object obj = null;
        
        try{
            // クラスを取得
            Class cls = Class.forName(className);
            
            //オブジェクトの生成
            obj = cls.newInstance();
        }catch( InstantiationException ie ){
            String err = "[" + className + "]" +
                "InstantiationException (" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }catch( IllegalAccessException iae){
            String err = "[" + className + "]" +
                "IllegalAccessExceptio (" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }catch( ClassNotFoundException cnfe ){
            String err = "[" + className + "]" +
                "ClassNotFoundException (" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }catch( Exception e ){
            String err = "[" + className + "]" +
                e.getClass().getName() + " (" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }
        return obj;
    }
    
//add 2005/01/18 start
    /**
     * JavaBeansインスタンスの生成<BR>
     * 指定されたクラスのJavaBeansインスタンスを引数付きの
     * コンストラクタで生成します。
     * @param className クラス名
     * @param argTypes 引数の型リスト
     * @param argValues 引数の値リスト
     * @return Object 生成されたJavaBeansインスタンスを返します
     */
    public static Object createInstance(String className, String[] argTypes, Object[] argValues)
    throws BeanUtilRuntimeException{
        Object obj = null;
        
        try{
            // クラスを取得
            Class cls = Class.forName(className);
            
            Class arg_classes[] = new Class[argTypes.length];
            for( int i=0; i<argTypes.length; i++ ){
                arg_classes[i] = Class.forName(argTypes[i]);
            }
            Constructor constructor = cls.getConstructor(arg_classes);
            
            //オブジェクトの生成
            obj = constructor.newInstance(argValues);
        }catch( InstantiationException ie ){
            String err = "[" + className + "]" +
                "InstantiationException (" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }catch( ClassNotFoundException cnfe ){
            String err = "[" + className + "]" +
                "ClassNotFoundException (" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }catch( IllegalAccessException iae){
            String err = "[" + className + "]" +
                "IllegalAccessExceptio (" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }catch( NoSuchMethodException e){
            String err = "[" + className + "]" +
                "NoSuchMethodException (" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }catch( InvocationTargetException e){
            String err = "[" + className + "]" +
                "InvocationTargetException (" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }catch( Exception e ){
            String err = "[" + className + "]" +
                e.getClass().getName() + " (" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }
        return obj;
    }
//add 2005/01/18 end
    
    /**
     * getメソッドを実行し結果をint型で返します。<BR>
     * @param obj getメソッドを提供するインスタンス
     * @param propertyName プロパティ名
     * @return 実行結果をint型で返します。
     */
    public static int getIntValue(Object obj, String propertyName)
    throws BeanUtilRuntimeException{
        int value = ((Integer)getProperty(obj, propertyName)).intValue();
        return value;
    }
    
    /**
     * getメソッドを実行し結果をlong型で返します。<BR>
     * @param obj getメソッドを提供するインスタンス
     * @param propertyName プロパティ名
     * @return 実行結果をlong型で返します。
     */
    public static long getLongValue(Object obj, String propertyName)
    throws BeanUtilRuntimeException{
        long value = ((Long)getProperty(obj, propertyName)).longValue();
        return value;
    }
    
    /**
     * getメソッドを実行し結果をdouble型で返します。<BR>
     * @param obj getメソッドを提供するインスタンス
     * @param propertyName プロパティ名
     * @return 実行結果をdouble型で返します。
     */
    public static double getDoubleValue(Object obj, String propertyName)
    throws BeanUtilRuntimeException{
        double value = ((Double)getProperty(obj, propertyName)).doubleValue();
        return value;
    }
    
    /**
     * getメソッドを実行し結果をfloat型で返します。<BR>
     * @param obj getメソッドを提供するインスタンス
     * @param propertyName プロパティ名
     * @return 実行結果をfloat型で返します。
     */
    public static float getFloatValue(Object obj, String propertyName)
    throws BeanUtilRuntimeException{
        float value = ((Float)getProperty(obj, propertyName)).floatValue();
        return value;
    }
    
    /**
     * getメソッドを実行し結果をshort型で返します。<BR>
     * @param obj getメソッドを提供するインスタンス
     * @param propertyName プロパティ名
     * @return 実行結果をshort型で返します。
     */
    public static short getShortValue(Object obj, String propertyName)
    throws BeanUtilRuntimeException{
        short value = ((Short)getProperty(obj, propertyName)).shortValue();
        return value;
    }
    
    /**
     * getメソッドを実行し結果をboolean型で返します。<BR>
     * @param obj getメソッドを提供するインスタンス
     * @param propertyName プロパティ名
     * @return 実行結果をboolean型で返します。
     * @throws BeanUtilRuntimeException BeanUtilRuntimeException
     */
    public static boolean getBooleanValue(Object obj, String propertyName)
    throws BeanUtilRuntimeException{
        boolean value = ((Boolean)getProperty(obj, propertyName)).
            booleanValue();
        return value;
    }
    
    /**
     * getメソッドを実行します。<BR>
     * プリミティブ型のgetメソッドを実行した場合は、そのラッパクラスのインスタンス
     * を戻り値として返します。
     * @param obj getメソッドを提供するインスタンス
     * @param propertyName プロパティ名
     * @return 実行結果をObjectで返します。
     */
    public static Object getProperty(Object obj, String propertyName)
    throws BeanUtilRuntimeException{
        Object property = null;
        
        String getterName = getGetterName(propertyName);
        if( getterName == null ){
            return null;
        }
        
        try{
            // メソッドを取得
            Method method = obj.getClass().getMethod(getterName, null);
            
            
            //メソッドの戻り値が配列の場合
            if( method.getReturnType().isArray() ){
                //この Class オブジェクトが表すクラスまたはインタフェースが、指定された Class 
                //パラメータが表すクラスまたはインタフェースと等しいかどうか、
                //あるいはそのスーパークラスあるいはスーパーインタフェースであるかどうかを判定します。
                if( method.getReturnType().isAssignableFrom(Object[].class)){
                    Object[] collection = (Object[])method.invoke(obj,null);
//modify 2007/03/26 kano start
//                    Iterator iterator = Arrays.asList(collection).iterator();
//                    property = iterator;
                    property = collection;
//modify 2007/03/26 kano end
                }else if( method.getReturnType().isAssignableFrom(Byte[].class)){
                    Byte[] collection = (Byte[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(byte[].class)){
                    byte[] collection = (byte[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(Integer[].class)){
                    Integer[] collection = (Integer[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(int[].class)){
                    int[] collection = (int[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(Short[].class)){
                    Short[] collection = (Short[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(short[].class)){
                    short[] collection = (short[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(Long[].class)){
                    Long[] collection = (Long[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(long[].class)){
                    long[] collection = (long[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(Double[].class)){
                    Double[] collection = (Double[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(double[].class)){
                    double[] collection = (double[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(Float[].class)){
                    Float[] collection = (Float[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(float[].class)){
                    float[] collection = (float[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(Boolean[].class)){
                    Boolean[] collection = (Boolean[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(boolean[].class)){
                    boolean[] collection = (boolean[])method.invoke(obj,null);
                    property = collection;
                }else if( method.getReturnType().isAssignableFrom(String[].class)){
                    String[] collection = (String[])method.invoke(obj,null);
                    property = collection;
                }else{
                    Object[] collection = (Object[])method.invoke(obj,null);
//modify 2007/03/26 kano start
//                    Iterator iterator = Arrays.asList(collection).iterator();
//                    property = iterator;
                    property = collection;
//modify 2007/03/26 kano end
                }
            }else{
                // メソッドを実行
                property = method.invoke(obj,null);
            }
        }catch( Exception e){
            String err = "[" + obj.getClass().getName() + ":" + propertyName + "]" +
                "getProperty() failed (" + BeanUtil.class.getName() + ") (" +
                e.getMessage() + ")";
            throw new BeanUtilRuntimeException(err);
        }
        return property;
    }
    
    /**
     * setメソッドを実行します。<br>
     * setメソッドはJavaBeansのコーディング規約に基づき、単一の引数を持つ
     * アクセッサメソッドです。<BR>
     * setメソッドの引数の型は、対になるgetメソッドの戻り値の型から判定します。<BR>
     * プリミティブ型のプロパティをsetメソッドの引数に渡す場合は、propertyの型
     * はString型であるべきです。<BR>
     * setPropertyメソッドはgetメソッドの戻り値に基づき、String型のproperty
     * をプリミティブ型クラスのラッパクラスのpropertyインスタンスを再作成し、
     * このpropertyインスタンスがsetメソッドに引数に割り当てます。
     *
     * @param obj setメソッドを実行するインスタンスを指定してください
     * @param propertyName setメソッドの対象となるプロパティ名を指定してください。
     * @param property setメソッドの引数に渡すインスタンスを指定してください。
     * @return Object setメソッドに戻り値があるばあいは実行結果を返します
     */
    public static Object setProperty(Object obj, String propertyName, Object property) {
        Class[] propertyTypes = new Class[1];
        
        //プリミティブ側の判定
        //getterメソッドの戻り値の型がsetterメソッドの型となる。
        /*
        Method chkMethod = getMethod(obj, propertyName);
        if(chkMethod.getReturnType().equals(int.class)){
            propertyTypes[0] = int.class;
        }else if(chkMethod.getReturnType().equals(long.class)){
            propertyTypes[0] = long.class;
        }else if(chkMethod.getReturnType().equals(double.class)){
            propertyTypes[0] = double.class;
        }else if(chkMethod.getReturnType().equals(float.class)){
            propertyTypes[0] = float.class;
        }else if(chkMethod.getReturnType().equals(short.class)){
            propertyTypes[0] = short.class;
        }else{
            propertyTypes[0] = property.getClass();
        }
         */
        Method chkMethod = getMethod(obj, propertyName);
        if( chkMethod == null ){
            String err = "[" + obj.getClass().getName() + ":" + propertyName + "　no getterMethod]" +
                "setProperty() failed(" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }
        propertyTypes[0] = chkMethod.getReturnType();
        String setterName = getSetterName(propertyName);
        if( setterName == null ){
            String err = "[" + obj.getClass().getName() + ":" + propertyName + "　no setterMethod]" +
                "setProperty() failed(" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }
        
        try{
            // メソッドを取得
            Method method = obj.getClass().getMethod(setterName, propertyTypes);
            //setメソッドの引数の型をチェック
            //プリミティブ型の場合は、そのラッパークラスのインスタンスを引数
            //にセットしてやる必要がある。
            Object[] properties = null;
            property = getNullData(property, chkMethod.getReturnType().getName());
            if( property == null ){
                return property;
            }
            if(chkMethod.getReturnType().equals(int.class) ||
                chkMethod.getReturnType().equals(Integer.class)){
                properties = new Integer[1];
                if( property == null || property.toString().length() == 0 ){
                    properties[0] = new Integer(0);
                }else{
                    //properties[0] = Integer.valueOf((String)property);
                    try{
                        properties[0] = Integer.valueOf(property.toString());
                    }catch(NumberFormatException e){
                        //小数点つきの数値を整数型に変換できるか試してみる
                        double chkDbl = Double.parseDouble(property.toString());
                        int chkInt = (int)chkDbl;
                        properties[0] = new Integer(chkInt);
                    }
                }
            }else if(chkMethod.getReturnType().equals(long.class)||
                chkMethod.getReturnType().equals(Long.class)){
                properties = new Long[1];
                if( property == null || property.toString().length() == 0 ){
                    properties[0] = new Long(0);
                }else{
                    try{
                        //properties[0] = Long.valueOf((String)property);
                        properties[0] = Long.valueOf(property.toString());
                    }catch(NumberFormatException e){
                        //小数点つきの数値を整数型に変換できるか試してみる
                        double chkDbl = Double.parseDouble(property.toString());
                        long chkInt = (long)chkDbl;
                        properties[0] = new Long(chkInt);
                    }
                }
            }else if(chkMethod.getReturnType().equals(double.class)||
                chkMethod.getReturnType().equals(Double.class)){
                properties = new Double[1];
                if( property == null || property.toString().length() == 0 ){
                    properties[0] = new Double(0);
                }else{
                    //properties[0] = Double.valueOf((String)property);
                    properties[0] = Double.valueOf(property.toString());
                }
            }else if(chkMethod.getReturnType().equals(float.class)||
                chkMethod.getReturnType().equals(Float.class)){
                properties = new Float[1];
                if( property == null || property.toString().length() == 0 ){
                    properties[0] = new Float(0);
                }else{
                    //properties[0] = Float.valueOf((String)property);
                    properties[0] = Float.valueOf(property.toString());
                }
            }else if(chkMethod.getReturnType().equals(short.class)||
                chkMethod.getReturnType().equals(Short.class)){
                properties = new Short[1];
                if( property == null || property.toString().length() == 0 ){
                    properties[0] = new Short("0");
                }else{
                    try{
                        //properties[0] = Short.valueOf((String)property);
                        properties[0] = Short.valueOf(property.toString());
                    }catch(NumberFormatException e){
                        //小数点つきの数値を整数型に変換できるか試してみる
                        double chkDbl = Double.parseDouble(property.toString());
                        short chkInt = (short)chkDbl;
                        properties[0] = new Short(chkInt);
                    }
                }
            }else if(chkMethod.getReturnType().equals(boolean.class)||
                chkMethod.getReturnType().equals(Boolean.class)){
                properties = new Boolean[1];
                if( property == null || property.toString().length() == 0 ){
                    properties[0] = new Boolean(false);
                }else if( property.equals("on")){
                    properties[0] = new Boolean(true);
                }else{
                    //properties[0] = Boolean.valueOf((String)property);
                    properties[0] = Boolean.valueOf(property.toString());
                }
            }else{
                properties = new Object[1];
                properties[0] = property;
            }
            
            //メソッドを実行
            method.invoke(obj, properties);
        }catch( NoSuchMethodException e){
            String err = "[" + obj.getClass().getName() + ":" + propertyName + "]" +
                "setProperty() failed(" + BeanUtil.class.getName() + ") (" +
                e.getMessage() + ")";
            throw new BeanUtilRuntimeException(err);
        }catch( IllegalAccessException e){
            String err = "[" + obj.getClass().getName() + ":" + propertyName + "]" +
                "setProperty() failed(" + BeanUtil.class.getName() + ") (" +
                e.getMessage() + ") value = " + property;
            throw new BeanUtilRuntimeException(err);
        }catch( InvocationTargetException e){
            String err = "[" + obj.getClass().getName() + ":" + propertyName + "]" +
                "setProperty() failed(" + BeanUtil.class.getName() + ") (" +
                e.getMessage() + ") value = " + property;
            throw new BeanUtilRuntimeException(err);
        }catch( Exception e ){
            String err = "[" + obj.getClass().getName() + ":" + propertyName + "]" +
                e.getClass().getName() + " (" + BeanUtil.class.getName() + ") value = " + property;
            throw new BeanUtilRuntimeException(err);
        }
        return property;
    }
    
    public static Class getReturnType(Object obj, String propertyName)
    throws BeanUtilRuntimeException{
        Class[] propertyTypes = new Class[1];
        Method chkMethod = getMethod(obj, propertyName);
        if( chkMethod == null ){
            String err = "[" + obj.getClass().getName() + ":" + propertyName + "　no getterMethod]" +
                "setProperty() failed(" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }
        propertyTypes[0] = chkMethod.getReturnType();
        String setterName = getSetterName(propertyName);
        if( setterName == null ){
            String err = "[" + obj.getClass().getName() + ":" + propertyName + "　no setterMethod]" +
                "setProperty() failed(" + BeanUtil.class.getName() + ")";
            throw new BeanUtilRuntimeException(err);
        }
        
        try{
            return chkMethod.getReturnType();
        }catch( Exception e){
            String err = "[" + obj.getClass().getName() + ":" + propertyName + "]" +
                "setProperty() failed(" + BeanUtil.class.getName() + ") (" +
                e.getMessage() + ")";
            throw new BeanUtilRuntimeException(err);
        }
    }
    
    /**
     * プロパティの値を検査します。
     * プロパティの値がNULLの場合はclazzTypeに指定された型によるデフォルト
     * 値が作成されます。
     */
    private static Object getNullData(Object property, String clazzType){
        Object ret;
        if( property != null){
            return property;
        }
        if( clazzType.equals(int.class.getName()) ||
            clazzType.equals(long.class.getName()) ||
            clazzType.equals(double.class.getName()) ||
            clazzType.equals(float.class.getName()) ){
            ret = new Integer("0");
        }else if(clazzType.equals(boolean.class.getName())){
            ret = new Boolean("false");
        }else if(clazzType.equals(String.class.getName())){
            ret = new String("");
        }else{
            return null;
        }
        return ret.toString();
    }
    
    /**
     * propertyNameからgetMethod名を取得します。<BR>
     * <BR>
     * （使用例)<BR>
     * getterName = getGetterName("address");<BR>
     * <BR>
     * getterNameにはgetAddressが帰ります。<BR>
     *
     * @param propertyName プロパティ名
     * @return getメソッド名
     */
    public static String getGetterName(String propertyName){
        String methodName =
            propertyName.substring(0,1).toUpperCase() +
            propertyName.substring(1, propertyName.length());
        
        methodName = "get" + methodName;
        
        return methodName;
    }
    
    /**
     * propertyNameからsetMethod名を取得します。<BR>
     * <BR>
     * （使用例)<BR>
     * setterName = setGetterName("address");<BR>
     * <BR>
     * setterNameにはsetAddressが帰ります。<BR>
     *
     * @param propertyName プロパティ名
     * @return setメソッド名
     */
    public static String getSetterName(String propertyName){
        String methodName =
            propertyName.substring(0,1).toUpperCase() +
            propertyName.substring(1, propertyName.length());
        
        methodName = "set" + methodName;
        
        return methodName;
    }
    
    /**
     * getMethodを取得します。
     * @param obj
     * @param propertyName
     * @return
     */
    private static Method getMethod(Object obj, String propertyName)
    throws BeanUtilRuntimeException{
        Method method = null;
        String getterName = getGetterName(propertyName);
        if( getterName == null ){
            return null;
        }
        
        try{
            // メソッドを取得
            method = obj.getClass().getMethod(getterName, null);
            
        }catch( Exception e){
            String err = "[" +obj.getClass().getName() + ":" +  propertyName + "]" +
                "getMethod() failed (" + BeanUtil.class.getName() + ") (" +
                e.getMessage() + ")";
            throw new BeanUtilRuntimeException(err);
        }
        return method;
    }
    
    /**
     * 型の異なるオブジェクトのコピーを作成します。
     * 引数srcClassNameで指定したクラスタイプのインスタンスを作成します
     * srcClassNameにセットされるプロパティは引数dstで指定したオブジェクト
     * が持っているプロパティのコピーがセットされます。
     * srcClassNameに指定されたプロパティがdstに無い場合は、デフォルト値が
     * セットされます
     *
     * @param dst コピー元オブジェクト
     * @param srcClassName コピー先オブジェクトのクラス名
     * @return コピー先オブジェクトを返します
     */
    public static Object copyInstance( Object dst, String srcClassName){
        Object src = BeanUtil.createInstance(srcClassName);
        Field[] fields = src.getClass().getDeclaredFields();
        for( int i=0; i<fields.length; i++){
            Field field = fields[i];
            //System.out.println( field.getType());
            int modifier = field.getModifiers();
            if( Modifier.PRIVATE == modifier ||
                Modifier.PROTECTED == modifier){
                String propertyName = field.getName();
                
                Field chkField = null;
                chkField = getField( dst.getClass(), propertyName);
                
                if( chkField == null ){
                    continue;
                }
                
                Object property = BeanUtil.getProperty(dst, propertyName);
                BeanUtil.setProperty(src, propertyName, property);
            }
        }
        return src;
    }
    
    /**
     * 引数clazzで指定されたクラス、propertyNameで指定されたメンバ情報を
     * 取得します
     * @param clazz クラス情報
     * @param propertyName プロパティ名
     * @return Field型のメンバ情報を返します
     */
    public static Field getField( Class clazz, String propertyName) {
        Field chkField = null;
        try{
            chkField = clazz.getDeclaredField(propertyName);
        }catch( NoSuchFieldException nsfe ){
        }
        if( chkField == null ){
            Class superClazz = clazz.getSuperclass();
            if( superClazz == null ){
                return null;
            }
            chkField = getField(superClazz, propertyName);
        }
        return chkField;
    }
    
    /**
     * 指定された条件のメソッドを実行します
     * @param className クラス名
     * @param funcName メソッド名
     * @param args 引数リスト
     * @return メソッドの実行結果を返します
     */
    public static Object invoke(String className, String funcName, Object[] args){
        try{
            //クラスを取得
            Class cls = Class.forName(className);
            Object obj = cls.newInstance();
            
            //メソッドを取得
            Method method = BeanUtil.findMethod(cls, funcName, args);
            //メソッドを実行
            Object result = method.invoke(obj, args);
            return result;
        }catch(Exception r){
            throw new BeanUtilRuntimeException("Failed invoke class:"+className+", funcName:"+funcName+", err:"+r.getMessage());
        }
    }
    
    /**
     * 指定された条件のメソッドを取得します
     * @param clazz クラス名
     * @param funcName メソッド名
     * @param args 引数リスト
     * @return メソッドを取得します。該当するメソッドが存在しない場合はnullを返します
     */
    public static Method findMethod(Class clazz, String funcName, Object[] args) throws Exception{
        Method[] methods = clazz.getMethods();
        int size = methods.length;
        for(int i=0; i<size; i++){
            Method method = methods[i];
            if( !method.getName().equals(funcName) ){
                continue;
            }
            Class[] types = method.getParameterTypes();
            if( types.length != args.length ){
                continue;
            }
            int typeSize = types.length;
            boolean ret = true;
            for(int j=0; j<typeSize; j++){
                Class type = types[j];
                Object arg = args[j];
                if( type.isPrimitive() ){
                    if(type.equals(int.class)){
                        try{
                            Integer value = new Integer(arg.toString());
                            args[j] = value;
                        }catch(Exception e){
                            ret = false;
                            break;
                        }
                    }else if(type.equals(long.class)){
                        try{
                            Long value = new Long(arg.toString());
                            args[j] = value;
                        }catch(Exception e){
                            ret = false;
                            break;
                        }
                    }else if(type.equals(double.class)){
                        try{
                            Double value = new Double(arg.toString());
                            args[j] = value;
                        }catch(Exception e){
                            ret = false;
                            break;
                        }
                    }else if(type.equals(float.class)){
                        try{
                            Float value = new Float(arg.toString());
                            args[j] = value;
                        }catch(Exception e){
                            ret = false;
                            break;
                        }
                    }else if(type.equals(short.class)){
                        try{
                            Short value = new Short(arg.toString());
                            args[j] = value;
                        }catch(Exception e){
                            ret = false;
                            break;
                        }
                    }else if(type.equals(byte.class)){
                        try{
                            Byte value = new Byte(arg.toString());
                            args[j] = value;
                        }catch(Exception e){
                            ret = false;
                            break;
                        }
                    }else if(type.equals(boolean.class)){
                        try{
                            Boolean value = new Boolean(arg.toString());
                            args[j] = value;
                        }catch(Exception e){
                            ret = false;
                            break;
                        }
                    }
                }else if( arg != null && !type.isInstance(arg) ){
                    ret = false;
                    break;
                }
            }
            if( !ret ){
                continue;
            }
            return method;
        }
        return null;
    }
    
    /**
     * 指定された文字列から"（もしくは'）を除去します
     */
    public static String supressQuate(String str){
        if( str.indexOf("\"") == 0 && str.lastIndexOf("\"") == (str.length()-1)){
            return str.substring(1, str.length()-1);
        }else if( str.indexOf("'") == 0 && str.lastIndexOf("'") == (str.length()-1)){
            return str.substring(1, str.length()-1);
        }else{
            return str;
        }
    }
    
    /**
     * 引数に指定したクラスがJavaタイプかどうかを判定します
     * @param type 対象クラス
     * @return 対象クラスがJavaタイプの場合はtrueを返します
     */
    public static boolean isJavaType(Class type){
        String name = type.getName();
        if( name.equals("byte")){
            return true;
        }else if( name.equals("short")){
            return true;
        }else if( name.equals("boolean")){
            return true;
        }else if( name.equals("int")){
            return true;
        }else if( name.equals("long")){
            return true;
        }else if( name.equals("double")){
            return true;
        }else if( name.equals("float")){
            return true;
        }else if( name.equals("char")){
            return true;
        }else if( name.equals("java.lang.Byte")){
            return true;
        }else if( name.equals("java.lang.Short")){
            return true;
        }else if( name.equals("java.lang.Boolean")){
            return true;
        }else if( name.equals("java.lang.Double")){
            return true;
        }else if( name.equals("java.lang.Float")){
            return true;
        }else if( name.equals("java.lang.Character")){
            return true;
        }else if( name.equals("java.lang.String")){
            return true;
        }else if( name.equals("java.lang.Integer")){
            return true;
        }else if( name.equals("java.lang.Long")){
            return true;
        }else if( name.equals("java.util.Date")){
            return true;
        }else{
            return false;
        }
    }
    
    public static boolean isPrimitive(String value){
        boolean ret = false;
        if( value == null ) return ret;
        try{
            Long.parseLong(value);
            return true;
        }catch(Exception e){}
        
        try{
            Double.parseDouble(value);
            return true;
        }catch(Exception e){}
        
        try{
            if( value.equals("true") || value.equals("false") ){
                return true;
            }
        }catch(Exception e){}
        
        return ret;
    }
}
