All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.alpharogroup.lang.AnnotationExtensions Maven / Gradle / Ivy

There is a newer version: 4.21.0
Show newest version
/**
 * The MIT License
 *
 * Copyright (C) 2007 Asterios Raptis
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package de.alpharogroup.lang;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import de.alpharogroup.file.FilenameExtensions;
import de.alpharogroup.file.filter.ClassFileFilter;

/**
 * The Class {@link AnnotationExtensions}.
 *
 * @author Asterios Raptis
 */
public final class AnnotationExtensions
{

	/**
	 * Private constructor.
	 */
	private AnnotationExtensions()
	{
		super();
	}

	/**
	 * Gets all annotated classes that belongs from the given package path and the given annotation
	 * class.
	 *
	 * @param packagePath
	 *            the package path
	 * @param annotationClass
	 *            the annotation class
	 * @return the all classes
	 * @throws ClassNotFoundException
	 *             the class not found exception
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	public static Set> getAllAnnotatedClasses(final String packagePath,
		final Class annotationClass)
		throws ClassNotFoundException, IOException
	{
		final List directories = ClassExtensions.getDirectoriesFromResources(packagePath,
			true);
		final Set> classes = new HashSet<>();
		for (final File directory : directories)
		{
			classes.addAll(scanForAnnotatedClasses(directory, packagePath, annotationClass));
		}
		return classes;
	}

	/**
	 * Gets all annotated classes that belongs from the given package path and the given list with
	 * annotation classes.
	 *
	 * @param packagePath
	 *            the package path
	 * @param annotationClasses
	 *            the list with the annotation classes
	 * @return the all classes
	 * @throws ClassNotFoundException
	 *             the class not found exception
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	public static Set> getAllAnnotatedClassesFromSet(final String packagePath,
		final Set> annotationClasses)
		throws ClassNotFoundException, IOException
	{
		final List directories = ClassExtensions.getDirectoriesFromResources(packagePath,
			true);
		final Set> classes = new HashSet<>();
		for (final File directory : directories)
		{
			classes
				.addAll(scanForAnnotatedClassesFromSet(directory, packagePath, annotationClasses));
		}
		return classes;
	}

	/**
	 * Gets all the classes from the class loader that belongs to the given package path.
	 *
	 * @param packagePath
	 *            the package path
	 *
	 * @return the all classes
	 *
	 * @throws ClassNotFoundException
	 *             the class not found exception
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	public static Set> getAllClasses(final String packagePath)
		throws ClassNotFoundException, IOException
	{
		return getAllAnnotatedClasses(packagePath, null);
	}

	/**
	 * Gets all the classes from the class loader that belongs to the given package path.
	 *
	 * @param packagePath
	 *            the package path
	 * @param annotationClasses
	 *            the annotation classes
	 * @return the all classes
	 * @throws ClassNotFoundException
	 *             the class not found exception
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	public static Set> getAllClasses(final String packagePath,
		final Set> annotationClasses)
		throws ClassNotFoundException, IOException
	{
		return getAllAnnotatedClassesFromSet(packagePath, annotationClasses);
	}

	/**
	 * Search for the given annotationClass in the given componentClass and return it if search was
	 * successful.
	 *
	 * @param 
	 *            the generic type
	 * @param componentClass
	 *            the component class
	 * @param annotationClass
	 *            the annotation class
	 * @return the annotation
	 */
	public static  T getAnnotation(final Class componentClass,
		final Class annotationClass)
	{
		T annotation = componentClass.getAnnotation(annotationClass);
		if (annotation != null)
		{
			return annotation;
		}
		for (final Class ifc : componentClass.getInterfaces())
		{
			annotation = getAnnotation(ifc, annotationClass);
			if (annotation != null)
			{
				return annotation;
			}
		}
		if (!Annotation.class.isAssignableFrom(componentClass))
		{
			for (final Annotation ann : componentClass.getAnnotations())
			{
				annotation = getAnnotation(ann.annotationType(), annotationClass);
				if (annotation != null)
				{
					return annotation;
				}
			}
		}
		final Class superClass = componentClass.getSuperclass();
		if (superClass == null || superClass.equals(Object.class))
		{
			return null;
		}
		return getAnnotation(superClass, annotationClass);
	}

	/**
	 * Checks if is annotation present through making a lookup if the given annotation class is
	 * present in the given class or in one of the super classes.
	 *
	 * @param componentClass
	 *            the component class
	 * @param annotationClass
	 *            the annotation class
	 * @return true, if is annotation present
	 */
	public static boolean isAnnotationPresentInSuperClasses(final Class componentClass,
		final Class annotationClass)
	{
		if (componentClass.isAnnotationPresent(annotationClass))
		{
			return true;
		}
		Class superClass = componentClass.getSuperclass();
		while (superClass != null)
		{
			if (superClass.isAnnotationPresent(annotationClass))
			{
				return true;
			}
			superClass = superClass.getSuperclass();
		}
		return false;
	}

	/**
	 * Checks if is annotation present through making a lookup if the given annotation class is
	 * present in the given class or in one of the super classes.
	 *
	 * @param componentClass
	 *            the component class
	 * @param annotationClass
	 *            the annotation class
	 * @return true, if is annotation present
	 */
	public static boolean isAnnotationPresentInSuperClassesOrInterfaces(
		final Class componentClass, final Class annotationClass)
	{
		return getAnnotation(componentClass, annotationClass) != null;
	}

	/**
	 * Scan recursive for annotated classes in the given directory.
	 *
	 * @param directory
	 *            the directory
	 * @param packagePath
	 *            the package path
	 * @param annotationClass
	 *            the annotation class
	 * @return the list
	 * @throws ClassNotFoundException
	 *             occurs if a given class cannot be located by the specified class loader
	 */
	public static Set> scanForAnnotatedClasses(final File directory,
		final String packagePath, final Class annotationClass)
		throws ClassNotFoundException
	{
		final Set> foundClasses = new HashSet<>();
		if (!directory.exists())
		{
			return foundClasses;
		}
		// define the include filefilter for class files...
		final FileFilter includeFileFilter = new ClassFileFilter();
		final File[] files = directory.listFiles(includeFileFilter);
		for (final File file : files)
		{
			String qualifiedClassname = null;
			if (file.isDirectory())
			{
				qualifiedClassname = packagePath + "." + file.getName();
				foundClasses
					.addAll(scanForAnnotatedClasses(file, qualifiedClassname, annotationClass));
			}
			else
			{
				final String filename = FilenameExtensions.getFilenameWithoutExtension(file);
				qualifiedClassname = packagePath + '.' + filename;
				Class foundClass = null;
				try
				{
					foundClass = ClassExtensions.forName(qualifiedClassname);
					if (annotationClass != null)
					{
						if (foundClass.isAnnotationPresent(annotationClass))
						{
							foundClasses.add(foundClass);
						}
					}
					else
					{
						foundClasses.add(foundClass);
					}

				}
				catch (final Throwable throwable)
				{
					foundClass = Class.forName(qualifiedClassname, false,
						ClassExtensions.getClassLoader());
					if (annotationClass != null)
					{
						if (foundClass.isAnnotationPresent(annotationClass))
						{
							foundClasses.add(foundClass);
						}
					}
					else
					{
						foundClasses.add(foundClass);
					}
				}
			}
		}
		return foundClasses;
	}

	/**
	 * Scan recursive for annotated classes in the given directory.
	 *
	 * @param directory
	 *            the directory
	 * @param packagePath
	 *            the package path
	 * @param annotationClasses
	 *            the list with the annotation classes
	 * @return the list
	 * @throws ClassNotFoundException
	 *             the class not found exception
	 */
	public static Set> scanForAnnotatedClassesFromSet(final File directory,
		final String packagePath, final Set> annotationClasses)
		throws ClassNotFoundException
	{
		final Set> foundClasses = new HashSet<>();
		if (!directory.exists())
		{
			return foundClasses;
		}
		// define the include filefilter for class files...
		final FileFilter includeFileFilter = new ClassFileFilter();

		final File[] files = directory.listFiles(includeFileFilter);
		for (final File file : files)
		{
			String qualifiedClassname = null;
			if (file.isDirectory())
			{
				qualifiedClassname = packagePath + "." + file.getName();
				foundClasses.addAll(
					scanForAnnotatedClassesFromSet(file, qualifiedClassname, annotationClasses));
			}
			else
			{
				final String filename = FilenameExtensions.getFilenameWithoutExtension(file);
				qualifiedClassname = packagePath + '.' + filename;
				Class foundClass = null;
				try
				{
					foundClass = Class.forName(qualifiedClassname);
					if (null != annotationClasses)
					{
						for (final Class annotationClass : annotationClasses)
						{
							if (foundClass.isAnnotationPresent(annotationClass))
							{
								foundClasses.add(foundClass);
							}
						}
					}
					else
					{
						foundClasses.add(foundClass);
					}
				}
				catch (final Throwable throwable)
				{
					foundClass = Class.forName(qualifiedClassname, false,
						ClassExtensions.getClassLoader());
					if (null != annotationClasses)
					{
						for (final Class annotationClass : annotationClasses)
						{
							if (foundClass.isAnnotationPresent(annotationClass))
							{
								foundClasses.add(foundClass);
							}
						}
					}
					else
					{
						foundClasses.add(foundClass);
					}
				}
			}
		}
		return foundClasses;
	}

	/**
	 * Scan recursive for classes in the given directory.
	 *
	 * @param directory
	 *            the directory
	 * @param packagePath
	 *            the package path
	 * @return the list
	 * @throws ClassNotFoundException
	 *             the class not found exception
	 */
	public static Set> scanForClasses(final File directory, final String packagePath)
		throws ClassNotFoundException
	{
		return AnnotationExtensions.scanForAnnotatedClasses(directory, packagePath, null);
	}

	/**
	 * Sets the annotation value for the given key of the given annotation to the given new value at
	 * runtime.
	 *
	 * @param annotation
	 *            the annotation
	 * @param key
	 *            the key
	 * @param value
	 *            the value to set
	 * @return the old value or default value if not set
	 * @throws NoSuchFieldException
	 *             the no such field exception
	 * @throws SecurityException
	 *             the security exception
	 * @throws IllegalArgumentException
	 *             the illegal argument exception
	 * @throws IllegalAccessException
	 *             the illegal access exception
	 */
	@SuppressWarnings("unchecked")
	public static Object setAnnotationValue(final Annotation annotation, final String key,
		final Object value) throws NoSuchFieldException, SecurityException,
		IllegalArgumentException, IllegalAccessException
	{
		final Object invocationHandler = Proxy.getInvocationHandler(annotation);
		final Field field = invocationHandler.getClass().getDeclaredField("memberValues");
		field.setAccessible(true);
		final Map memberValues = (Map)field.get(invocationHandler);
		final Object oldValue = memberValues.get(key);
		if (oldValue == null || oldValue.getClass() != value.getClass())
		{
			throw new IllegalArgumentException();
		}
		memberValues.put(key, value);
		return oldValue;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy