
com.lafaspot.common.util.AnnotationClassScanner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of common.core Show documentation
Show all versions of common.core Show documentation
common component ${project.name}
/*
* Copyright [yyyy] [name of copyright owner]
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package com.lafaspot.common.util;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.InvalidPathException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import com.lafaspot.logfast.logging.LogContext;
import com.lafaspot.logfast.logging.LogManager;
import com.lafaspot.logfast.logging.Logger;
/**
* Annotation class scanner which scans for all annotations based on the
* annotation class passed in.
*
*
* @param
* Annotation Class
*/
public class AnnotationClassScanner {
/**
* Class to be annotated.
*/
private final Class annotationClazz;
/**
* Filtering out classes not needed.
*/
private final Set excludeFilter;
/**
* Specifying filters to be included.
*/
private final Set allowFilter = new HashSet();
/**
* Set of all the resource paths which will be scanned. This set is build as
* and will block scanning the same path again which avoids recursion.
*/
private final Set dirLookupSet = new HashSet();
/**
* Logger class.
*/
private final Logger logger;
/**
* Private annotationClassScanner constructor.
*
* @param annotationClazz
* Annotated class
* @param logManager
* LogManager
*/
private AnnotationClassScanner(final Class annotationClazz, final LogManager logManager) {
if (annotationClazz == null) {
throw new IllegalArgumentException("Annotation class can't be null");
}
this.annotationClazz = annotationClazz;
final String[] packageToExclude = { "java.", "javax.", "org.ietf.jgss", "org.omg.", "org.w3c.dom.",
"org.xml.sax.", "sun.tools.", "sun.jvmstat.", "com.sun.", "org.junit.", "org.testng.", "bsh.",
"org.relaxng.", "mockit.", "com.beust.", "org.apache.log4j.", "ch.qos.logback.", "org.slf4j.",
"org.apache.commons.logging." };
excludeFilter = new HashSet(Arrays.asList(packageToExclude));
LogContext context = new AnnotationScannerContext("AnnotationClassScanner:" + annotationClazz.getName());
logger = logManager.getLogger(context);
}
/**
* AnnotationClassScanner constructor.
*
* @param annotationClazz
* Annotated class
* @param allowFilter
* Filter to be included
* @param logManager
* LogManager
*/
public AnnotationClassScanner(final Class annotationClazz, final List allowFilter,
final LogManager logManager) {
this(annotationClazz, logManager);
if (allowFilter == null) {
throw new IllegalArgumentException("Include filter can't be null");
}
this.allowFilter.addAll(allowFilter);
}
/**
* Scanning the annotated classes.
*
* @return Set of annotated classes
*/
public Set> scanAnnotatedClasses() {
final Set> clazzez = new HashSet>();
clazzez.addAll(scanPackagesAnnotatedClasses());
clazzez.addAll(scanURLClassLoaderAnnotatedClasses());
return clazzez;
}
/**
* Scanning packages annotated classes.
*
* @return Set of annotated classes
*/
private Set> scanPackagesAnnotatedClasses() {
final Set> clazzez = new HashSet>();
final Package[] packages = Package.getPackages();
for (final Package sPackage : packages) {
try {
clazzez.addAll(scanPackageAnnotatedClasses(sPackage));
} catch (final IOException e) {
logger.warn("AnnotationClassScanner failed for package: " + sPackage.getName(), e);
}
}
return clazzez;
}
/**
* Scanning url classloader annotated classes.
*
* @return Set of annotated classes.
*/
private Set> scanURLClassLoaderAnnotatedClasses() {
final ClassLoader classLoader = this.getClass().getClassLoader();
if (!(classLoader instanceof URLClassLoader)) {
throw new IllegalArgumentException("Classloader is not a URL classloader");
}
final URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
final URL[] urls = urlClassLoader.getURLs();
final Set> clazzez = new HashSet>();
for (final URL url : urls) {
try {
clazzez.addAll(scanURLAnnotatedClasses(url, ""));
} catch (final IOException e) {
// ignore and continue to loop.
}
}
return clazzez;
}
/**
* Scanning package annotated classes.
*
* @param sPackage
* Java package
* @return Set of annotated classes
* @throws IOException
* Exceptions during operation.
*/
private Set> scanPackageAnnotatedClasses(final Package sPackage) throws IOException {
final String packagePath = sPackage.getName().replace('.', '/');
final Enumeration packageResources = Thread.currentThread().getContextClassLoader()
.getResources(packagePath);
final Set> clazzez = new HashSet>();
while (packageResources.hasMoreElements()) {
clazzez.addAll(scanURLAnnotatedClasses(packageResources.nextElement(), sPackage.getName()));
}
return clazzez;
}
/**
* Scanning URL annotated classes.
*
* @param url
* URL
* @param packageName
* Name of the package
* @return Set of annotated classes
* @throws IOException
* Exception during operation
*/
private Set> scanURLAnnotatedClasses(final URL url, final String packageName) throws IOException {
final Set> clazzez = new HashSet>();
String urlPath = url.toExternalForm();
if (urlPath.contains("!") && urlPath.startsWith("jar:file:")) {
String[] split = urlPath.split("!");
split = split[0].split(":");
clazzez.addAll(scanJarAnnotatedClasses(new JarFile(split[2])));
return clazzez;
} else if (urlPath.startsWith("file:")) {
urlPath = urlPath.substring(5);
final File directory = new File(urlPath);
if (!directory.exists()) {
return clazzez;
}
if (directory.isFile() && directory.getPath().endsWith(".jar")) {
clazzez.addAll(scanJarAnnotatedClasses(directory));
return clazzez;
}
final File[] files = directory.listFiles();
if (files == null) {
return clazzez;
}
for (final File file : files) {
if (file.isDirectory()) {
if (!dirLookupSet.contains(file.getCanonicalPath())) {
dirLookupSet.add(file.getCanonicalPath());
String prefix = packageName + ".";
if (packageName.isEmpty()) {
prefix = "";
}
clazzez.addAll(scanURLAnnotatedClasses(new URL("file:" + file.getAbsolutePath()),
prefix + file.getName()));
}
} else if (file.getName().endsWith(".class")) {
final String className = packageName + '.' + file.getName();
final Class> clazz = applyFilter(className.substring(0, className.length() - 6));
if (clazz != null) {
clazzez.add(clazz);
}
}
}
return clazzez;
} else {
throw new InvalidPathException(urlPath, "The path is not found");
}
}
/**
* Scanning jar annotated classes.
*
* @param path
* Jar file path
* @return Set of annotated classes
* @throws IOException
* Exception during operation
*/
public Set> scanJarAnnotatedClasses(final File path) throws IOException {
return scanJarAnnotatedClasses(new JarFile(path));
}
/**
* Scanning jar annotated classes.
*
* @param jar
* Jar file
* @return Set of annotated classes
* @throws IOException
* Exception during operation
*/
public Set> scanJarAnnotatedClasses(final JarFile jar) throws IOException {
final Set> clazzez = new HashSet>();
final Enumeration it = jar.entries();
while (it.hasMoreElements()) {
final JarEntry jarEntry = it.nextElement();
if (jarEntry.getName().endsWith(".class")) {
final String className = jarEntry.getName().replaceAll("/", "\\.");
final Class> clazz = applyFilter(className.substring(0, className.length() - 6));
if (clazz != null) {
clazzez.add(clazz);
}
}
}
return clazzez;
}
/**
* Helper function to apply the filter.
*
* @param clazzName
* Class name
* @return Annotated class
*/
private Class> applyFilter(final String clazzName) {
if (isAllowed(clazzName)) {
try {
final Class> clazz = Class.forName(clazzName, false, this.getClass().getClassLoader());
final T annotation = clazz.getAnnotation(annotationClazz);
if (annotation != null) {
return clazz;
}
} catch (final ClassNotFoundException | NoClassDefFoundError | UnsatisfiedLinkError
| UnsupportedClassVersionError e) {
if (logger.isDebug()) {
logger.debug("Unable to search classes for annotations: " + clazzName, e);
}
}
}
return null;
}
/**
* Helper function to verify whether clazzName is in allowFilter or not.
*
* @param clazzName
* Name of the class
* @return true if clazzName is in the allowFilter
*/
private boolean isAllowed(final String clazzName) {
if (!allowFilter.isEmpty()) {
for (final String allowPrefix : allowFilter) {
if (clazzName.startsWith(allowPrefix)) {
return true;
}
}
return false;
}
final String[] tokens = clazzName.split("\\.");
String path = "";
for (final String token : tokens) {
path += token + ".";
if (excludeFilter.contains(path)) {
return false;
}
}
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy