Package winterwell.utils

Source Code of winterwell.utils.ReflectionUtils

package winterwell.utils;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import winterwell.utils.io.FileUtils;

/**
* Reflection-related utility functions
*
* @testedby {@link ReflectionUtilsTest}
*/
public final class ReflectionUtils {

  /**
   *
   * MAY BE VERY SLOW - may attempt to load every damn class!
   *
   * @param implementMe
   * @param packageIndicator
   *            The search will start from here. It recursively explores all
   *            sub-packages.
   * @return classes implementing implementMe
   * @testedby {@link ReflectionUtilsTest#testFindClasses()}
   */
  public static List<Class> findClasses(Class implementMe,
      Class packageIndicator) {
    Package p = packageIndicator.getPackage();
    URL r = packageIndicator.getResource("");
    String dir = r.getFile();
    return findClasses(implementMe, new File(dir), p.getName());
  }

  public static List<Class> findClasses(Class implementMe, File dir,
      String packageName) {
    List<Class> found = new ArrayList<Class>();
    List<File> classFiles = FileUtils.find(dir, ".*\\.class");
    // // sort? -- age (the useful sort order) of class file is irrelevant
    // if (sortFiles!=null) {
    // Collections.sort(classFiles, sortFiles);
    // }
    for (File file : classFiles) {
      // try to load class
      String cName = FileUtils.getBasename(file);
      if (cName.contains("$")) {
        continue;
      }
      cName = packageName + "." + cName;
      try {
        Class c = Class.forName(cName);
        // ignore interfaces
        if (c.isInterface()) {
          continue;
        }
        if (isa(c, implementMe)) {
          found.add(c);
        }
      } catch (Exception e) {
        // oh well
      }
    }
    return found;
  }

  /**
   * @param clazz
   * @return Instance fields - public and private - which can be accessed from
   *         this class. Excludes: static fields and fields which cannot be
   *         accessed due to JVM security.<br>
   *         Includes: non-static final fields
   */
  public static List<Field> getAllFields(Class clazz) {
    ArrayList<Field> list = new ArrayList<Field>();
    ReflectionUtils.getAllFields2(clazz, list);
    return list;
  }

  private static void getAllFields2(Class clazz, ArrayList<Field> list) {
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
      // exclude static
      int m = field.getModifiers();
      if (Modifier.isStatic(m)) {
        continue;
      }
      if (!field.isAccessible()) {
        try {
          field.setAccessible(true);
        } catch (SecurityException e) {
          // skip over this field
          continue;
        }
      }
      list.add(field);
    }
    // recurse
    Class superClass = clazz.getSuperclass();
    if (superClass == null)
      return;
    getAllFields2(superClass, list);
  }

  /**
   * @param object
   * @param annotation
   * @param incPrivate
   *            If true, will return private and protected fields (provided
   *            they can be set accessible).
   * @return (All fields / accessible public fields) in object which are
   *         annotated with annotation
   */
  public static List<Field> getAnnotatedFields(Object object,
      Class<? extends Annotation> annotation, boolean incPrivate) {
    List<Field> allFields = incPrivate ? getAllFields(object.getClass())
        : Arrays.asList(object.getClass().getFields());
    List<Field> fields = new ArrayList<Field>();
    for (Field f : allFields) {
      if (f.isAnnotationPresent(annotation)) {
        fields.add(f);
      }
    }
    return fields;
  }

  /**
   * Recurse to get a private field which may be declared in a super-class.
   * Note: {@link Class#getField(String)} will only retrieve public fields.
   *
   * @param klass
   * @param fieldName
   * @return Field or null
   */
  public static Field getField(Class klass, String fieldName) {
    try {
      Field f = klass.getDeclaredField(fieldName);
      return f;
    } catch (NoSuchFieldException e) {
      klass = klass.getSuperclass();
      if (klass == null)
        return null;
    }
    return getField(klass, fieldName);
  }

  /**
   * @param obj
   * @param clazz
   * @param includeStatic
   *            if true, include static fields too
   * @return all <i>public</i> field values of type clazz in obj
   */
  public static <X> List<X> getFieldValues(Object obj, Class<X> clazz,
      boolean includeStatic) {
    try {
      Field[] fields = obj.getClass().getFields();
      List<X> values = new ArrayList<X>();
      for (Field field : fields) {
        if (!includeStatic && Modifier.isStatic(field.getModifiers())) {
          continue;
        }
        Object val = field.get(obj);
        if (val == null) {
          continue;
        }
        if (clazz.isAssignableFrom(val.getClass())) {
          values.add((X) val);
        }
      }
      return values;
    } catch (Exception e) {
      throw Utils.runtime(e);
    }
  }

  /**
   * Where is this class from?
   *
   * @param klass
   * @return
   */
  public static File getFile(Class klass) {
    try {
      URL rs = klass.getResource(klass.getSimpleName() + ".class");
      return new File(rs.toURI());
    } catch (Exception e) {
      throw Utils.runtime(e);
    }
  }

  /**
   *
   * @param clazz
   * @param methodName
   * @return method or null if it isn't there
   */
  static Method getMethod(Class<?> clazz, String methodName) {
    for (Method m : clazz.getMethods()) {
      if (m.getName().equals(methodName))
        return m;
    }
    return null;
  }

  public static <X> X getPrivateField(Object obj, String fieldName) {
    Field f = ReflectionUtils.getField(obj.getClass(), fieldName);
    f.setAccessible(true);
    try {
      return (X) f.get(obj);
    } catch (Exception e) {
      throw Utils.runtime(e);
    }
  }

  /**
   *
   * @param obj
   * @param property
   *            i.e. "name" maps to the method getName()
   * @return null if the property is not present (so this is ambiguous)
   */
  public static Object getProperty(Object obj, String property) {
    try {
      String mName = "get" + StrUtils.toTitleCase(property);
      Method m = obj.getClass().getMethod(mName);
      if (!m.isAccessible()) {
        m.setAccessible(true);
      }
      try {
        return m.invoke(obj);
      } catch (Exception e) {
        throw Utils.runtime(e);
      }
    } catch (NoSuchMethodException e) {
      return null;
    }
  }

  public static boolean hasField(Class klass, String field) {
    return getField(klass, field) != null;
  }

  public static boolean hasMethod(Class klass, String methodName) {
    for (Method m : klass.getMethods()) {
      if (m.getName().equals(methodName))
        return true;
    }
    return false;
  }

  public static Object invoke(Object obj, String methodName, Object... args) {
    Method m = getMethod(obj.getClass(), methodName);
    if (m == null)
      throw Utils.runtime(new NoSuchMethodException(obj.getClass() + "."
          + methodName));
    try {
      return m.invoke(obj, args);
    } catch (Exception e) {
      throw Utils.runtime(e);
    }
  }

  /**
   * The equivalent of instanceof, but for Class objects. 'cos I always forget
   * how to do this.
   *
   * @param possSubType
   * @param superType
   * @return true if possSubType <i>is</i> a subType of superType
   */
  public static boolean isa(Class possSubType, Class superType) {
    return superType.isAssignableFrom(possSubType);
  }

  /**
   * Output manifest info on jar files
   *
   * @param args
   *            jar filenames
   */
  public static void main(String[] args) {
    assert args.length != 0;
    for (String string : args) {
      System.out.println("Info on jar " + string);
      try {
        JarFile jar = new JarFile(new File(string));
        Manifest manifest = jar.getManifest();
        Map<String, Attributes> entries = manifest.getEntries();
        Attributes v = manifest.getMainAttributes();
        for (Object k : v.keySet()) {
          System.out.println(k + ": " + v.get(k));
        }
        for (String a : entries.keySet()) {
          v = entries.get(a);
          for (Object k : v.keySet()) {
            System.out.println(a + k + ": " + v.get(k));
          }
        }
      } catch (IOException e) {
        System.out.println(e.getMessage());
      }
    }
  }

  /**
   * Set a field, which can be private. Throws exceptions if the field does
   * not exist or if you cannot do this.
   *
   * @param obj
   * @param fieldName
   * @param value
   */
  public static void setPrivateField(Object obj, String fieldName,
      Object value) {
    Field f = ReflectionUtils.getField(obj.getClass(), fieldName);
    f.setAccessible(true);
    try {
      f.set(obj, value);
    } catch (Exception e) {
      throw Utils.runtime(e);
    }
  }

  /**
   * FIXME: Is this actually used anywhere?
   *
   * @deprecated
   */
  @Deprecated
  public static void setProperty(Object target, String propName, Object value) {
    Class tClass = target.getClass();
    // Is there a setXXX method?
    try {
      Method method = tClass.getMethod(
          "set" + StrUtils.toTitleCase(propName), value.getClass());
      method.invoke(target, value);
    } catch (Exception e) {
      // oh well
    }
    // Set field
    setPrivateField(target, propName, value);
  }

  /**
   * @return total memory used, in bytes.
   * Runs garbage collection to try and give a better measure
   * of what's currently in play.
   * Warning: this is a bit of a slow call.
   */
  public static long getUsedMemory() {
    Runtime rt = Runtime.getRuntime();
    rt.runFinalization();
    rt.gc();
    // The methods above shouldn't need it, but add in a pause anyway
    Utils.sleep(100);
    return rt.totalMemory() - rt.freeMemory();   
  }

}
TOP

Related Classes of winterwell.utils.ReflectionUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.