package water.util; import water.H2O; import water.Iced; import java.lang.reflect.*; public class ReflectionUtils { /** * Reflection helper which returns the actual class for a type parameter, even if itself is parameterized. */ public static <T> Class<T> findActualClassParameter(Class clz, int parm) { Class parm_class = null; if (clz.getGenericSuperclass() instanceof ParameterizedType) { Type[] handler_type_parms = ((ParameterizedType) (clz.getGenericSuperclass())).getActualTypeArguments(); if (handler_type_parms[parm] instanceof Class) { // The handler's Iced class is not parameterized (the normal case): parm_class = (Class) handler_type_parms[parm]; // E.g., for a Schema [0] is the impl (Iced) type; [1] is the Schema type } else if (handler_type_parms[parm] instanceof TypeVariable) { // The handler's Iced class is parameterized, e.g. to handle multiple layers of Schema classes as in ModelsHandler: TypeVariable v = (TypeVariable) (handler_type_parms[parm]); Type t = v.getBounds()[0]; // [0] or [parm] ? if (t instanceof Class) parm_class = (Class) t; else if (t instanceof ParameterizedType) parm_class = (Class) ((ParameterizedType) t).getRawType(); } else if (handler_type_parms[parm] instanceof ParameterizedType) { // The handler's Iced class is parameterized, e.g. to handle multiple layers of Schema classes as in ModelsHandler: parm_class = (Class) ((ParameterizedType) (handler_type_parms[parm])).getRawType(); // For a Key<Frame> this returns Key.class; see also getActualTypeArguments() } else { String msg = "Iced parameter for handler: " + clz + " uses a type parameterization scheme that we don't yet handle: " + handler_type_parms[parm]; Log.warn(msg); throw H2O.fail(msg); } } else { // Superclass is not a ParameterizedType, so we just have Iced. parm_class = Iced.class; // If the handler isn't parameterized on the Iced class then this has to be Iced. } return (Class<T>) parm_class; } /** * Reflection helper which returns the actual class for a method's parameter. */ public static Class findMethodParameterClass(Method method, int parm) { Class[] clzes = method.getParameterTypes(); if (clzes.length <= parm) throw H2O.fail("Asked for the class of parameter number: " + parm + " of method: " + method + ", which only has: " + clzes.length + " parameters."); return clzes[parm]; } /** * Reflection helper which returns the actual class for a method's parameter. */ public static Class findMethodOutputClass(Method method) { return method.getReturnType(); } /** * Reflection helper which returns the actual class for a field which has a parameterized type. * E.g., DeepLearningV2's "parameters" class is in parent ModelBuilderSchema, and is parameterized * by type parameter P. */ public static Class findActualFieldClass(Class clz, Field f) { // schema.getClass().getGenericSuperclass() instanceof ParameterizedType Type generic_type = f.getGenericType(); if (! (generic_type instanceof TypeVariable)) return f.getType(); // field is a parameterized type // ((TypeVariable)schema.getClass().getField("parameters").getGenericType()) TypeVariable[] tvs = clz.getSuperclass().getTypeParameters(); TypeVariable tv = (TypeVariable)generic_type; String type_param_name = tv.getName(); int which_tv = -1; for(int i = 0; i < tvs.length; i++) if (type_param_name.equals(tvs[i].getName())) which_tv = i; if (-1 == which_tv) { // We topped out in the type heirarchy, so just use the type from f. // E.g., this happens when getting the metadata for the parameters field of ModelSchemaV3. // It has no generic parent, so we need to use the base class. return f.getType(); } ParameterizedType generic_super = (ParameterizedType)clz.getGenericSuperclass(); if (generic_super.getActualTypeArguments()[which_tv] instanceof Class) return (Class)generic_super.getActualTypeArguments()[which_tv]; return findActualFieldClass(clz.getSuperclass(), f); } // Best effort conversion from an Object to a double public static double asDouble( Object o ) { if( o == null ) return Double.NaN; if( o instanceof Integer ) return ((Integer)o); if( o instanceof Long ) return ((Long)o); if( o instanceof Float ) return ((Float)o); if( o instanceof Double ) return ((Double)o); if( o instanceof Enum ) return ((Enum)o).ordinal(); System.out.println("Do not know how to convert a "+o.getClass()+" to a double"); throw H2O.fail(); } /** * Return the Field for the specified name. * <p> * Java reflection will either give you all the public fields all the way up the class hierarchy (getField()), * or will give you all the private/protected/public only in the single class (getDeclaredField()). * This method uses the latter but walks up the class hierarchy. */ public static Field findNamedField(Object o, String field_name) { Class clz = o.getClass(); Field f = null; do { try { f = clz.getDeclaredField(field_name); f.setAccessible(true); return f; } catch (NoSuchFieldException e) { // fall through and try our parent } clz = clz.getSuperclass(); } while (clz != Object.class); return null; } }