alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Groovy example source code file (ParameterTypes.java)

This example Groovy source code file (ParameterTypes.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Groovy tags/keywords

cachedclass, cachedclass, class, class, classnotfoundexception, groovybugerror, noclassdeffounderror, object, object, parametertypes, parametertypes, reflection, wrapper

The Groovy ParameterTypes.java source code

/*
 * Copyright 2003-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.codehaus.groovy.reflection;

import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.runtime.MetaClassHelper;
import org.codehaus.groovy.runtime.wrappers.Wrapper;

import java.lang.reflect.Array;

public class ParameterTypes
{
  protected volatile Class [] nativeParamTypes;
  protected volatile CachedClass [] parameterTypes;

  protected boolean isVargsMethod;

    public ParameterTypes () {
    }

    public ParameterTypes(Class pt []) {
        nativeParamTypes = pt;
    }

    public ParameterTypes(String pt[]) {
        nativeParamTypes = new Class[pt.length];
        for (int i = 0; i != pt.length; ++i) {
            try {
              nativeParamTypes[i] = Class.forName(pt[i]);
            }
            catch (ClassNotFoundException e){
                NoClassDefFoundError err = new NoClassDefFoundError();
                err.initCause(e);
                throw err;
            }
        }
    }

    public ParameterTypes(CachedClass[] parameterTypes) {
        setParametersTypes(parameterTypes);
    }

    protected final void setParametersTypes(CachedClass[] pt) {
        this.parameterTypes = pt;
        isVargsMethod = pt.length > 0 && pt [pt.length-1].isArray;
    }

    public CachedClass[] getParameterTypes() {
      if (parameterTypes == null) {
          getParametersTypes0();
      }

      return parameterTypes;
  }

    private synchronized void getParametersTypes0() {
      if (parameterTypes != null)
          return;

      Class [] npt = nativeParamTypes == null ? getPT() : nativeParamTypes;

      CachedClass[] pt = new CachedClass [npt.length];
      for (int i = 0; i != npt.length; ++i)
        pt[i] = ReflectionCache.getCachedClass(npt[i]);

      nativeParamTypes = npt;
      setParametersTypes(pt);
    }

    public Class[] getNativeParameterTypes() {
        if (nativeParamTypes == null) {
            getNativeParameterTypes0();
        }
        return nativeParamTypes;
    }

    private synchronized void getNativeParameterTypes0() {
      if (nativeParamTypes != null)
          return;

      Class [] npt;
      if (parameterTypes != null) {
          npt = new Class [parameterTypes.length];
          for (int i = 0; i != parameterTypes.length; ++i) {
              npt[i] = parameterTypes[i].getTheClass();
          }
      }
      else
        npt = getPT ();
      nativeParamTypes = npt;
    }

    protected Class[] getPT() { throw new UnsupportedOperationException(getClass().getName()); }

    public boolean isVargsMethod(Object[] arguments) {
        // Uncomment if at some point this method can be called before parameterTypes initialized
        // getParameterTypes();
        if(!isVargsMethod)
          return false;

        final int lenMinus1 = parameterTypes.length - 1;
        // -1 because the varg part is optional
        if (lenMinus1 == arguments.length) return true;
        if (lenMinus1 > arguments.length) return false;
        if (arguments.length > parameterTypes.length) return true;

        // only case left is arguments.length == parameterTypes.length
        Object last = arguments[arguments.length - 1];
        if (last == null) return true;
        Class clazz = last.getClass();
        return !clazz.equals(parameterTypes[lenMinus1].getTheClass());

    }

    public final Object[] coerceArgumentsToClasses(Object[] argumentArray) {
        // Uncomment if at some point this method can be called before parameterTypes initialized
        // getParameterTypes();
        argumentArray = correctArguments(argumentArray);

        final CachedClass[] pt = parameterTypes;
        final int len = argumentArray.length;
        for (int i = 0; i < len; i++) {
            final Object argument = argumentArray[i];
            if (argument != null) {
                argumentArray[i] = pt[i].coerceArgument(argument);
            }
        }
        return argumentArray;
    }

    public Object[] correctArguments(Object[] argumentArray) {
        // correct argumentArray's length
        if (argumentArray == null) {
            return MetaClassHelper.EMPTY_ARRAY;
        }

        final CachedClass[] pt = getParameterTypes();
        if (pt.length == 1 && argumentArray.length == 0) {
            if (isVargsMethod)
                return new Object[]{Array.newInstance(pt[0].getTheClass().getComponentType(), 0)};
            else
                return MetaClassHelper.ARRAY_WITH_NULL;
        }

        if (isVargsMethod && isVargsMethod(argumentArray)) {
            return fitToVargs(argumentArray, pt);
        }

        return argumentArray;
    }

    /**
     * this method is called when the number of arguments to a method is greater than 1
     * and if the method is a vargs method. This method will then transform the given
     * arguments to make the method callable
     *
     * @param argumentArray the arguments used to call the method
     * @param paramTypes    the types of the parameters the method takes
     */
    private static Object[] fitToVargs(Object[] argumentArray, CachedClass[] paramTypes) {
        Class vargsClass = ReflectionCache.autoboxType(paramTypes[paramTypes.length - 1].getTheClass().getComponentType());

        if (argumentArray.length == paramTypes.length - 1) {
            // the vargs argument is missing, so fill it with an empty array
            Object[] newArgs = new Object[paramTypes.length];
            System.arraycopy(argumentArray, 0, newArgs, 0, argumentArray.length);
            Object vargs = MetaClassHelper.makeArray(null, vargsClass, 0);
            newArgs[newArgs.length - 1] = vargs;
            return newArgs;
        } else if (argumentArray.length == paramTypes.length) {
            // the number of arguments is correct, but if the last argument
            // is no array we have to wrap it in a array. If the last argument
            // is null, then we don't have to do anything
            Object lastArgument = argumentArray[argumentArray.length - 1];
            if (lastArgument != null && !lastArgument.getClass().isArray()) {
                // no array so wrap it
                Object wrapped = MetaClassHelper.makeArray(lastArgument, vargsClass, 1);
                System.arraycopy(argumentArray, argumentArray.length - 1, wrapped, 0, 1);
                Object[] newArgs = new Object[paramTypes.length];
                System.arraycopy(argumentArray, 0, newArgs, 0, paramTypes.length - 1);
                newArgs[newArgs.length - 1] = wrapped;
                return newArgs;
            } else {
                // we may have to box the argument!
                return argumentArray;
            }
        } else if (argumentArray.length > paramTypes.length) {
            // the number of arguments is too big, wrap all exceeding elements
            // in an array, but keep the old elements that are no vargs
            Object[] newArgs = new Object[paramTypes.length];
            // copy arguments that are not a varg
            System.arraycopy(argumentArray, 0, newArgs, 0, paramTypes.length - 1);
            // create a new array for the vargs and copy them
            int numberOfVargs = argumentArray.length - paramTypes.length;
            Object vargs = MetaClassHelper.makeCommonArray(argumentArray, paramTypes.length - 1, vargsClass);
            newArgs[newArgs.length - 1] = vargs;
            return newArgs;
        } else {
            throw new GroovyBugError("trying to call a vargs method without enough arguments");
        }
    }

    public boolean isValidMethod(Class[] arguments) {
        if (arguments == null) return true;

        final int size = arguments.length;
        CachedClass[] pt = getParameterTypes();
        final int paramMinus1 = pt.length-1;

        if (isVargsMethod && size >= paramMinus1)
            return isValidVarargsMethod(arguments, size, pt, paramMinus1);
        else
            if (pt.length == size)
                return isValidExactMethod(arguments, pt);
            else
                if (pt.length == 1 && size == 0 && !pt[0].isPrimitive)
                    return true;
        return false;
    }

    private boolean isValidExactMethod(Class[] arguments, CachedClass[] pt) {
        // lets check the parameter types match
        int size = pt.length;
        for (int i = 0; i < size; i++) {
            if (!pt[i].isAssignableFrom(arguments[i])) {
                return false;
            }
        }
        return true;
    }

    public boolean isValidExactMethod(Object [] args) {
        // lets check the parameter types match
        getParametersTypes0();
        int size = args.length;
        if (size != parameterTypes.length)
          return false;
        
        for (int i = 0; i < size; i++) {
            if (args[i] != null && !parameterTypes[i].isAssignableFrom(args[i].getClass())) {
                return false;
            }
        }
        return true;
    }

    public boolean isValidExactMethod(Class [] args) {
        // lets check the parameter types match
        getParametersTypes0();
        int size = args.length;
        if (size != parameterTypes.length)
          return false;

        for (int i = 0; i < size; i++) {
            if (args[i] != null && !parameterTypes[i].isAssignableFrom(args[i])) {
                return false;
            }
        }
        return true;
    }

    private static boolean testComponentAssignable(Class toTestAgainst, Class toTest) {
        Class component = toTest.getComponentType();
        if (component==null) return false;
        return MetaClassHelper.isAssignableFrom(toTestAgainst, component);
    }

    private boolean isValidVarargsMethod(Class[] arguments, int size, CachedClass[] pt, int paramMinus1) {
        // first check normal number of parameters
        for (int i = 0; i < paramMinus1; i++) {
            if (pt[i].isAssignableFrom(arguments[i])) continue;
            return false;
        }

        // check direct match
        CachedClass varg = pt[paramMinus1];
        Class clazz = varg.getTheClass().getComponentType();
        if ( size==pt.length &&
             (varg.isAssignableFrom(arguments[paramMinus1]) ||
              testComponentAssignable(clazz, arguments[paramMinus1])))
        {
            return true;
        }

        // check varged
        for (int i = paramMinus1; i < size; i++) {
            if (MetaClassHelper.isAssignableFrom(clazz, arguments[i])) continue;
            return false;
        }
        return true;
    }

    public boolean isValidMethod(Object[] arguments) {
        if (arguments == null) return true;

        final int size = arguments.length;
        CachedClass[] paramTypes = getParameterTypes();
        final int paramMinus1 = paramTypes.length-1;

        if ( size >= paramMinus1 && paramTypes.length > 0 &&
             paramTypes[(paramMinus1)].isArray) 
        {
            // first check normal number of parameters
            for (int i = 0; i < paramMinus1; i++) {
                if (paramTypes[i].isAssignableFrom(getArgClass(arguments[i]))) continue;
                return false;
            }
            
            
            // check direct match
            CachedClass varg = paramTypes[paramMinus1];
            Class clazz = varg.getTheClass().getComponentType();
            if ( size==paramTypes.length && 
                 (varg.isAssignableFrom(getArgClass(arguments[paramMinus1])) ||
                  testComponentAssignable(clazz, getArgClass(arguments[paramMinus1])))) 
            {
                return true;
            }
            

            // check varged
            for (int i = paramMinus1; i < size; i++) {
                if (MetaClassHelper.isAssignableFrom(clazz, getArgClass(arguments[i]))) continue;
                return false;
            }
            return true;
        } else if (paramTypes.length == size) {
            // lets check the parameter types match
            for (int i = 0; i < size; i++) {
                if (paramTypes[i].isAssignableFrom(getArgClass(arguments[i]))) continue;
                return false;
            }
            return true;
        } else if (paramTypes.length == 1 && size == 0 && !paramTypes[0].isPrimitive) {
            return true;
        }
        return false;
    }

    private Class getArgClass(Object arg) {
        Class cls;
        if (arg == null) {
            cls = null;
        } else {
            if (arg instanceof Wrapper) {
                cls = ((Wrapper)arg).getType();
            }
            else
                cls = arg.getClass();
        }
        return cls;
    }
}

Other Groovy examples (source code examples)

Here is a short list of links related to this Groovy ParameterTypes.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.