You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@velocity.apache.org by Christoph Reck <Ch...@dlr.de> on 2000/11/06 14:17:51 UTC

ClassMap, MethodMap and Introspector enhancements

Hi,

doing some tests with the Introspector code of the current
velocity implementation, I saw some problems when primitive 
types show up, The Integer.TYPE is being catched already within
ClassMap.makeMethodKey(). 

This code needs to be further enhanced to catch the other
primitive types. See code within WM ...util.PropertyOperator.match()
or in the code below using reflection. 

Same applies to MethodMap.find() which
should contain a isPrimitive check (see below example for 
getConstructor).

----------------- enhancements for Introspector ------------------------
    /**
     * Enhancement of the class objects own getConstructor() which takes
     * in consideration subclassing and primitives. The params
     * parameter is an array of objects that should be matched
     * classwise to the constructors formal parameter types, in declared
     * order. If params is null, it is treated as if it were an empty
     * array.
     *
     * @param cls        the class to search for a matching constructor
     * @param params     the array of parameters that will be used to
     *                   invoke the constructor
     * @return           the Method object of the public constructor that
     *                   matches the above
     * @see              Class.getConstructor()
     **/
    public static Constructor getConstructor(Class cls, Object[] params)
    {
        Constructor[] constructors = cls.getConstructors();
        for (int i = 0; i < constructors.length; ++i )
        {
            Class[] parameterTypes = constructors[i].getParameterTypes();

            // The methods we are trying to compare must
            // the same number of arguments.
            if (parameterTypes.length == params.length)
            {
                // Make sure the given parameter is a valid
                // subclass of the method parameter in question.
                for (int j = 0; ; j++)
                {
                    if (j >= parameterTypes.length)
                        return constructors[i]; // found


                    Class c = parameterTypes[j];
                    Object p = params[j];
                    try {
                        if ( !c.isAssignableFrom(p.getClass()) )
                            break;
                        else if (  c.isPrimitive() &&
                                  (c != p.getClass().getField("TYPE").get(p)) )
                            break;
                    } catch (Exception ex) {
                        break;
                    }
                } // for all parameters
            } // if same length
        } // for all contructors

        return null;
    }
----------------- end of enhancements for Introspector -----------------
* Note that the introspector does not currently need to cache
the code to access constructors: 1rst because thy are not called
(heavily) from templates, 2nd because the amount of looping is minimal
(not many constructors per class).
* Note that this code is symmetric to the MethodMap.find() one.
* Note that the 'c != p.getClass().getField("TYPE").get(p)' could be 
made as in WMs ...util.PropertyOperator.match() cascade of equals.
* Note that one can sefely replace its '.equals(...)' with '==' (or
'!=' for the above getConstructor case, because they are static final
values).

----------------- enhancements for VelocityFormatter -------------------
----------------- or for a class context tool ----------------------
    /**
     * Instantiates a class by specifying its name (via empty constructor).
     *
     * @param className The name of the class to instantiates.
     * @return A new instance of the requested class.
     */
    public static Object newInstance(String className) throws Exception
    {
        Class cls = Class.forName(className);
        Constructor constructor = cls.getConstructor( new Class[0] );
        return constructor.newInstance( new Object[0] );
    }

    /**
     * Convenience method which instantiates a class by specifying
     * its name and one parameter.
     *
     * @param className The name of the class to instantiates.
     * @param param A single parameters used to call the constructor.
     * @return A new instance of the requested class.
     */
    public static Object newInstance(String className, Object param)
           throws Exception
    {
        return newInstance( className, new Object[] {param} );
    }

    /**
     * Instantiates a class by specifying its name and parameters.
     *
     * @param className The name of the class to instantiates.
     * @param params Array of parameters used to call the constructor.
     * @return A new instance of the requested class.
     */
    public static Object newInstance(String className, Object[] params)
           throws Exception
    {
        Class cls = Class.forName(className);
        Constructor constructor = getConstructor(cls, params);
        return constructor.newInstance(params);
    }
------------- end of  enhancements for VelocityFormatter ---------------

:) Christoph