Uploaded image for project: 'Commons OGNL (Dormant)'
  1. Commons OGNL (Dormant)
  2. OGNL-163

OgnlRuntime.findParameterTypes() is wrong

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Open
    • Major
    • Resolution: Unresolved
    • 3.0
    • None
    • Core Runtime
    • None
    • Struts 2.1.8.1 (updated to use OGNL 3.0), Java 1.6

    Description

      I have a class that has 2 parameters:

      Configure<Parent, Child>

      which has method

      setParent(Parent p)

      and a concrete implementation ConfigureProfileItems extends Configure<Profile, Item>.

      When OgnlRuntime enters the findParameterTypes() method the first time it determines that the parameter type should be

      {Profile} and caches it appropriately. The second time it enters this method it looks up the generic methods cache and compares this to the GenericTypes of the strutsAction.getGenericSuperClass() i.e. comparing {Profile}

      to

      {Profile, Item}

      . This fails and therefore has to recomputed every single time for this method.

      Furthermore I have another class that extends ConfigureProfileItems therefore type.getGenericSuperclass() == null, so it is determined that the setParent() only parameter is an Object when the only parameter should be a Profile (since it extends ConfigureProfileItems).

      Here is a suggested fix for this method that will determine the parameter types correctly and cache them correctly.

      public class OgnlRuntime {

      private static class GenericMethodParamKey {

      Class<?> actionClass;

      Method m;

      private GenericMethodParamKey(Class<?> actionClass, Method m)

      { this.actionClass = actionClass; this.m = m; }

      @Override

      public int hashCode()

      { final int prime = 31; int result = 1; result = prime * result + ((actionClass == null) ? 0 : actionClass.getName().hashCode()); result = prime * result + ((m == null) ? 0 : m.hashCode()); return result; }

      }

      private static Hashtable<Method, Class<?>[]> nonGenericMethodParams = new Hashtable<Method, Class<?>[]>();

      private static Hashtable<GenericMethodParamKey, Class<?>[]> genericMethodParams = new Hashtable<GenericMethodParamKey, Class<?>[]>();

      public static Class<?>[] findParameterTypes(Class<?> clazz, Method m) {

      // Check the non generic methods

      Class<?>[] types = nonGenericMethodParams.get(m);

      if (types != null)

      { return types; }



      // Check the generic methods

      GenericMethodParamKey key = new GenericMethodParamKey(clazz, m);

      types = genericMethodParams.get(key);

      if (types != null) { return types; }

      Type[] params = determineMethodParams(clazz, m);

      types = new Class<?>[params.length];

      boolean nonGeneric = true;

      // replace any parameters on the method with their bound types

      for (int i = 0; i < types.length; i++) {

      Type type = params[i];

      if (type instanceof Class<?>)

      { Class<?> paramClass = (Class<?>) type; types[i] = paramClass; }

      else

      { Class<?> paramClass = m.getParameterTypes()[i]; types[i] = paramClass; }

      nonGeneric = nonGeneric && types[i] == m.getParameterTypes()[i];

      }

      if (nonGeneric)

      { nonGenericMethodParams.put(m, types); }

      else

      { genericMethodParams.put(key, types); }

      return types;

      }

      /**

      • This method gets the method parameters for method m called from class clazz, replacing any generic types
      • that are class-wide parameters.
      • If the method has any parameterization of its own, these types are still present in the result
      • @param clazz
      • @param m
      • @return

      */

      private static Type[] determineMethodParams(Class<?> clazz, Method m) {

      // If this class is the methods declaring class then get the generic method parameters

      if (m.getDeclaringClass() == clazz)

      { return getMethodParameterTypes(m); }

      // Get the parameter types as defined in clazz's super class

      Class<?> superClazz = clazz.getSuperclass();

      Type[] types = determineMethodParams(superClazz, m);

      // replace the parameter types with overriding clazz's parameters

      Type superClass = clazz.getGenericSuperclass();

      if (superClass != null && ParameterizedType.class.isInstance(superClass)) {

      ParameterizedTypeImpl parameterizedType = (ParameterizedTypeImpl) superClass;

      // Compare Class2<S,T> and Class1<E,F> extends Class2<F,Integer> to replace

      // any Class2 variable S with Class1 variable F and Class2 variable T with java.lang.Integer

      Type[] actualTypes = parameterizedType.getActualTypeArguments();

      TypeVariable<?>[] classTypes = clazz.getSuperclass().getTypeParameters();

      for (int i = 0; i < types.length; i++) {

      Type type = types[i];

      for (int j = 0; j < actualTypes.length; j++) {

      TypeVariable<?> classType = classTypes[j];

      if (type.toString().equals(classType.getName()))

      { // Generic method parameter is being overridden by subclass types[i] = actualTypes[j]; }

      }

      }

      }

      return types;

      }

      /**

      • This method gets the generic parameter types of a method
      • @param method

      */

      private static Type[] getMethodParameterTypes(Method method) {

      // Get Generic Types

      Type[] types = method.getGenericParameterTypes();

      // Replace any bounds where method like public <T extends E> void doSomething(T t); where

      // E is a class parameter

      TypeVariable<?>[] vars = method.getTypeParameters();

      for (int i = 0; i < types.length; i++) {

      Type type = types[i];

      for (int j = 0; j < vars.length; j++) {

      TypeVariable<?> typeVariable = vars[j];

      if (typeVariable.getName().equals(type.toString()))

      { types[i] = typeVariable.getBounds()[0]; // Reset j incase we have a case where public <T extends E, S extends T> void doSomething(S s); j = -1; type = types[i]; }

      }

      }

      return types;

      }

      }

      Attachments

        Activity

          People

            jkuhnert Jesse Kuhnert
            ahecebs Andrew Heron
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated: