Coverage Report - org.webslinger.ext.bsf.javaclass.ClassTypeUtil
 
Classes in this File Line Coverage Branch Coverage Complexity
ClassTypeUtil
0%
0/56
0%
0/31
0
 
 1  
 package org.webslinger.ext.bsf.javaclass;
 2  
 
 3  
 import java.lang.reflect.Method;
 4  
 import java.util.ArrayList;
 5  
 import java.util.Arrays;
 6  
 import java.util.HashSet;
 7  
 import java.util.Set;
 8  
 
 9  
 import org.apache.bsf.BSFException;
 10  
 
 11  0
 public final class ClassTypeUtil {
 12  
     public static Method findMostApplicableMethod(Class type, String name, Class[] types) throws NoSuchMethodException {
 13  0
         Method[] methods = type.getMethods();
 14  0
         ArrayList<Method> applicable = new ArrayList<Method>(methods.length);
 15  
 NEXT_METHOD:
 16  0
         for (Method method: methods) {
 17  0
             if (!name.equals(method.getName())) continue;
 18  0
             Class[] methodParameterTypes = method.getParameterTypes();
 19  0
             if (methodParameterTypes.length != types.length) continue;
 20  0
             for (int j = 0; j < types.length; j++) {
 21  0
                 if (!isMethodInvocationConvertible(types[j], methodParameterTypes[j])) continue NEXT_METHOD;
 22  
             }
 23  0
             applicable.add(method);
 24  
         }
 25  0
         if (applicable.isEmpty()) throw new NoSuchMethodException(name + "(" + Arrays.asList(types) + ")");
 26  0
         if (applicable.size() == 1) return (Method) applicable.get(0);
 27  0
         ArrayList<Method> maxApplicable = new ArrayList<Method>(applicable.size());
 28  0
         for (int i = 0; i < applicable.size(); i++) {
 29  0
             Method applicableMethod = (Method) applicable.get(i);
 30  0
             int more = 0, less = 0;
 31  0
             for (int j = 0; j < maxApplicable.size(); j++) {
 32  0
                 Method maxMethod = maxApplicable.get(j);
 33  0
                 if (isMoreSpecificThan(applicableMethod, maxMethod)) {
 34  0
                     more++;
 35  0
                 } else if (isLessSpecificThan(applicableMethod, maxMethod)) {
 36  0
                     less--;
 37  
                 }
 38  
             }
 39  0
             if (more == maxApplicable.size()) {
 40  0
                 maxApplicable.clear();
 41  0
                 maxApplicable.add(applicableMethod);
 42  0
             } else if (less < maxApplicable.size()) {
 43  0
                 maxApplicable.add(applicableMethod);
 44  
             }
 45  
         }
 46  0
         if (maxApplicable.size() == 1) return maxApplicable.get(0);
 47  0
         return null;
 48  
     }
 49  
 
 50  
     public static boolean isMethodInvocationConvertible(Class sourceType, Class targetType) {
 51  0
         if (sourceType == targetType) return true;
 52  0
         if (isWideningPrimitiveConvertible(sourceType, targetType)) return true;
 53  0
         if (isWideningReferenceConvertible(sourceType, targetType)) return true;
 54  0
         return false;
 55  
     }
 56  
 
 57  
     public static boolean isWideningPrimitiveConvertible(Class<?> sourceType, Class<?> targetType) {
 58  0
         return PRIMITIVE_WIDENING_CONVERSIONS.contains(getDescriptor(sourceType) + getDescriptor(targetType));
 59  
     }
 60  
 
 61  
     public static boolean isWideningReferenceConvertible(Class<?> sourceType, Class<?> targetType) {
 62  0
         if (targetType.isPrimitive() || sourceType == targetType) return false;
 63  0
         return targetType.isAssignableFrom(sourceType);
 64  
     }
 65  
 
 66  
     public static boolean isMoreSpecificThan(Method me, Method that) {
 67  0
         if (that.getDeclaringClass().isAssignableFrom(me.getDeclaringClass())) return false;
 68  0
         Class<?>[] meParameterTypes = me.getParameterTypes();
 69  0
         Class<?>[] thatParameterTypes = that.getParameterTypes();
 70  0
         for (int i = 0; i < meParameterTypes.length; i++) {
 71  0
             if (!thatParameterTypes[i].isAssignableFrom(meParameterTypes[i])) return false;
 72  
         }
 73  0
         return true;
 74  
     }
 75  
 
 76  
     public static boolean isLessSpecificThan(Method me, Method that) {
 77  0
         return isMoreSpecificThan(that, me);
 78  
     }
 79  
 
 80  
     public final static String VOID                 = "V";
 81  
     public final static String BYTE                 = "B";
 82  
     public final static String CHAR                 = "C";
 83  
     public final static String DOUBLE               = "D";
 84  
     public final static String FLOAT                = "F";
 85  
     public final static String INT                  = "I";
 86  
     public final static String LONG                 = "J";
 87  
     public final static String SHORT                = "S";
 88  
     public final static String BOOLEAN              = "Z";
 89  
     public final static String OBJECT               = "Ljava/lang/Object;";
 90  
     public final static String STRING               = "Ljava/lang/String;";
 91  
     public final static String CLASS                = "Ljava/lang/Class;";
 92  
     public final static String THROWABLE            = "Ljava/lang/Throwable;";
 93  
     public final static String RUNTIME_EXCEPTION    = "Ljava/lang/RuntimeException;";
 94  
     public final static String ERROR                = "Ljava/lang/Error;";
 95  
     public final static String CLONEABLE            = "Ljava/lang/Cloneable;";
 96  
     public final static String SERIALIZABLE         = "Ljava/io/Serializable;";
 97  
 
 98  0
     public static final Set<String> PRIMITIVE_WIDENING_CONVERSIONS = new HashSet<String>(
 99  
         Arrays.asList(
 100  
             new String[] {
 101  
                 BYTE  + SHORT,
 102  
 
 103  
                 BYTE  + INT,
 104  
                 SHORT + INT,
 105  
                 CHAR  + INT,
 106  
 
 107  
                 BYTE  + LONG,
 108  
                 SHORT + LONG,
 109  
                 CHAR  + LONG,
 110  
                 INT   + LONG,
 111  
 
 112  
                 BYTE  + FLOAT,
 113  
                 SHORT + FLOAT,
 114  
                 CHAR  + FLOAT,
 115  
                 INT   + FLOAT,
 116  
 
 117  
                 LONG  + FLOAT,
 118  
 
 119  
                 BYTE  + DOUBLE,
 120  
                 SHORT + DOUBLE,
 121  
                 CHAR  + DOUBLE,
 122  
                 INT   + DOUBLE,
 123  
 
 124  
                 LONG  + DOUBLE,
 125  
 
 126  
                 FLOAT + DOUBLE,
 127  
             }
 128  
         )
 129  
     );
 130  
 
 131  
     public static String getDescriptor(Class type) {
 132  0
         String className = type.getName();
 133  0
         if (className.equals("void"   )) return VOID;
 134  0
         if (className.equals("byte"   )) return BYTE;
 135  0
         if (className.equals("char"   )) return CHAR;
 136  0
         if (className.equals("double" )) return DOUBLE;
 137  0
         if (className.equals("float"  )) return FLOAT;
 138  0
         if (className.equals("int"    )) return INT;
 139  0
         if (className.equals("long"   )) return LONG;
 140  0
         if (className.equals("short"  )) return SHORT;
 141  0
         if (className.equals("boolean")) return BOOLEAN;
 142  0
         if (className.startsWith("[")) return className.replace('.', '/');
 143  0
         return 'L' + className.replace('.', '/') + ';';
 144  
     }
 145  
 }