Package org.moyrax.util

Source Code of org.moyrax.util.ClassUtils

package org.moyrax.util;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.Validate;
import org.moyrax.reflect.ClassResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;

/**
* Miscellaneous class utility methods. This provides a set of methods to
* help classes instrospection.
*
* @author Matias Mirabelli <lumen.night@gmail.com>
* @since 1.2
*/
public class ClassUtils {
  /**
   * Searches for all classes in the given package. It just returns the classes
   * which are visible for current {@link ClassLoader}.
   *
   * @param packagePattern A regular expression pattern which contains the path
   *    to list the classes. It cannot be null or empty.
   *
   * @return If the pattern contains classes it returns a list of those classes,
   *    otherwise returns an empty {@link List}.
   */
  public static ArrayList<Class<?>> lookup(final String packagePattern) {
    Validate.notEmpty(packagePattern, "The package cannot be null or empty.");

    return lookup(packagePattern,
        Thread.currentThread().getContextClassLoader());
  }

  /**
   * Searches for all classes in the given package and apply the a filter to
   * the result. It uses the specified {@link ClassLoader} to lookup the
   * classes.
   *
   * @param packagePattern A regular expression pattern which contains the path
   *    to list the classes. It cannot be null or empty.
   * @param filter Object used to filter the results. It cannot be null.
   *
   * @return If the pattern contains classes it returns a list of those classes,
   *    otherwise returns an empty {@link List}.
   */
  public static ArrayList<Class<?>> lookup(final String packagePattern,
      final Predicate filter) {

    Validate.notNull(filter, "The filter cannot be null");

    return lookup(packagePattern, filter,
        Thread.currentThread().getContextClassLoader());
  }

  /**
   * Searches for all classes in the given package and apply the a filter to
   * the result. It uses the specified {@link ClassLoader} to lookup the
   * classes.
   *
   * @param packagePattern A regular expression pattern which contains the path
   *    to list the classes. It cannot be null or empty.
   * @param filter Object used to filter the results. It cannot be null.
   * @param classLoader ClassLoader that contains the classes. It cannot be
   *    null.
   *
   * @return If the pattern contains classes it returns a list of those classes,
   *    otherwise returns an empty {@link List}.
   */
  public static ArrayList<Class<?>> lookup(final String packagePattern,
      final Predicate filter, final ClassLoader classLoader) {

    Validate.notNull(filter, "The filter cannot be null");
    Validate.notNull(classLoader, "The ClassLoader cannot be null");

    ArrayList<Class<?>> classes = lookup(packagePattern, classLoader);

    CollectionUtils.filter(classes, filter);

    return classes;
  }

  /**
   * Searches for all classes in the given package. It just returns the classes
   * which are visible for the specified {@link ClassLoader}.
   *
   * @param packagePattern A regular expression pattern which contains the path
   *    to list the classes. It cannot be null or empty.
   * @param classLoader ClassLoader that contains the classes. It cannot be
   *    null.
   *
   * @return If the pattern contains classes it returns a list of those classes,
   *    otherwise returns an empty {@link List}.
   */
  public static ArrayList<Class<?>> lookup(final String packagePattern,
      final ClassLoader classLoader) {

    // TODO(mmirabelli): There's a bug with some patterns because the used
    // ResourcePatternResolver matches the whole file names (including the
    // .class extension) of the classes. It implies that if the pattern does
    // not ends with *, the classes won't be discovered. Find a way to solve it.
    Validate.notEmpty(packagePattern, "The package cannot be null or empty.");
    Validate.notNull(classLoader, "The class loader cannot be null.");

    ArrayList<Class<?>> classes = new ArrayList<Class<?>>();

    try {
      final PathMatchingResourcePatternResolver resolver =
          new PathMatchingResourcePatternResolver(classLoader);

      final Resource[] resources = resolver.getResources(packagePattern);

      for (Resource resource : resources) {
        Class<?> clazz = getClassFromResource(resource, resolver, classLoader);

        if (clazz != null) {
          classes.add(clazz);
        }
      }
    } catch (IOException ex) {
      throw new IllegalArgumentException("Cannot list classes in the given "
          + "package: " + packagePattern, ex);
    }

    return classes;
  }

  /**
   * Returns a {@link MetadataReader} for the specified {@link Resource}.
   *
   * @param resource Resource related to class to search for. It cannot be null.
   *
   * @return If the resource represents a valid class, returns the {@link Class}
   *    object that it represents, otherwise returns <code>null</code>.
   */
  public static Class<?> getClassFromResource(final Resource resource) {

    PathMatchingResourcePatternResolver resolver =
      new PathMatchingResourcePatternResolver();

    Validate.notNull(resource, "The resource cannot be null.");

    return getClassFromResource(resource, resolver,
        Thread.currentThread().getContextClassLoader());
  }

  /**
   * Returns a {@link MetadataReader} for the specified {@link Resource}.
   *
   * @param resource Resource related to class to search for. It cannot be null.
   * @param resolver Resolver used to lookup the resource. It cannot be null.
   *
   * @return If the resource represents a valid class, returns the {@link Class}
   *    object that it represents, otherwise returns <code>null</code>.
   */
  public static Class<?> getClassFromResource(final Resource resource,
      final ResourcePatternResolver resolver, final ClassLoader classLoader) {

    Validate.notNull(resource, "The resource cannot be null.");
    Validate.notNull(resolver, "The resolver cannot be null.");

    if (!resource.isReadable() ||
        !resource.getFilename().endsWith(".class")) {
      return null;
    }

    Class<?> clazz = null;
    MetadataReader reader = null;

    try {
      final MetadataReaderFactory metadataReaderFactory =
          new CachingMetadataReaderFactory(classLoader);

      reader = metadataReaderFactory.getMetadataReader(resource);

      clazz = classLoader.loadClass(reader.getClassMetadata().getClassName());

    } catch (IOException ex) {
      // We don't need to check this exception since it means that probably the
      // given resource is not a valid class.
    } catch (ClassNotFoundException ex) {
      throw new IllegalArgumentException("The class related to the given "
          + "resource cannot be loaded using the current ClassLoader.", ex);
    }

    return clazz;
  }

  /**
   * Determines if a class contains the specified annotation. The class is
   * loaded as a resource instead of put it in memory as a JVM class.
   *
   * @param className Class's name to read from the classpath. It cannot be null
   *    or empty.
   * @param annotationClass Name of the annotation's class to check. It cannot
   *    be null or empty.
   *
   * @return Returns <code>true</code> if the given class contains the the
   *    annotation, <code>false</code> otherwise.
   *
   * @throws ClassNotFoundException If the class with the specified name does
   *    not exists.
   */
  public static boolean hasAnnotation(final String className,
      final String annotationClass) throws ClassNotFoundException {
    return hasAnnotation(className, annotationClass,
        Thread.currentThread().getContextClassLoader());
  }

  /**
   * Determines if a class contains the specified annotation. The class is
   * loaded as a resource instead of put it in memory as a JVM class.
   *
   * @param className Class's name to read from the classpath. It cannot be null
   *    or empty.
   * @param annotationClass Name of the annotation's class to check. It cannot
   *    be null or empty.
   * @param classLoader Class loader used to locate the resources. It cannot
   *    be null.
   *
   * @return Returns <code>true</code> if the given class contains the the
   *    annotation, <code>false</code> otherwise.
   *
   * @throws ClassNotFoundException If the class with the specified name does
   *    not exists.
   */
  public static boolean hasAnnotation(final String className,
      final String annotationClass, final ClassLoader classLoader)
        throws ClassNotFoundException {

    Validate.notEmpty(className, "The class's name cannot be null or empty.");
    Validate.notEmpty(annotationClass, "The annotation class cannot be null or"
        + " empty.");
    Validate.notNull(classLoader, "The class loader cannot be null.");

    try {
      ClassResource klass = new ClassResource(className, classLoader);

      return klass.isAnnotationPresent(annotationClass);
    } catch (IOException ex) {
      throw new ClassNotFoundException("The class " + className + " is not"
          + " found in the current classpath.", ex);
    }
  }
}
TOP

Related Classes of org.moyrax.util.ClassUtils

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.