/**
* Copyright 2010 Marko Lavikainen
*
* 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 net.contextfw.web.application.internal.util;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.contextfw.web.application.WebApplicationException;
import net.contextfw.web.application.component.Component;
import net.contextfw.web.application.remote.Remoted;
public class ClassScanner extends AbstractScanner {
private static final int POSTFIX = "class.".length();
public static List<Class<?>> getClasses(String... packageNames) {
ArrayList<String> list = new ArrayList<String>(packageNames.length);
Collections.addAll(list, packageNames);
return getClasses(list);
}
/**
* Scans all classes accessible from the context class loader which belong
* to the given package and subpackages.
*
* @param packageName
* The base package
* @return The classes
* @throws ClassNotFoundException
* @throws IOException
*/
public static List<Class<?>> getClasses(Iterable<String> packageNames) {
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
try {
for (String packageName : packageNames) {
List<String> resourcePaths = new ArrayList<String>();
resourcePaths.add(packageName);
List<ResourceEntry> entries = findResourceEntries(resourcePaths);
for (ResourceEntry entry : entries) {
String fileName = entry.getPath();
if (fileName.endsWith(".class") && !fileName.contains("$")) {
Class<?> klass;
String className = toClassName(fileName);
try {
klass = Class.forName(className);
} catch (ExceptionInInitializerError e) {
// happen, for example, in classes, which depend on
// Spring to inject some beans, and which fail,
// if dependency is not fulfilled
klass = Class.forName(className,
false, Thread.currentThread().getContextClassLoader());
}
classes.add(klass);
}
}
}
} catch (ClassNotFoundException e) {
throw new WebApplicationException(e);
}
return classes;
}
private static String toClassName(String fileName) {
return fileName.substring(0, fileName.length() - POSTFIX).replaceAll("/", "\\.");
}
public static List<Class<?>> getParamTypes(Class<?> declaringClass, Method method) {
Map<String, Class<?>> typeVariables = new HashMap<String, Class<?>>();
Object parametrizedType = declaringClass.getGenericSuperclass();
if (parametrizedType instanceof ParameterizedType) {
TypeVariable<?>[] tv = method.getDeclaringClass().getTypeParameters();
Type[] paramTypes = ((ParameterizedType) parametrizedType).getActualTypeArguments();
for (int i = 0; i < tv.length; i++) {
typeVariables.put(tv[i].getName(), (Class<?>) paramTypes[i]);
}
}
Type[] types = method.getGenericParameterTypes();
if (types.length == 0) {
return Collections.emptyList();
}
List<Class<?>> rv = new ArrayList<Class<?>>(types.length);
for (int i = 0; i < types.length; i++) {
if (types[i] instanceof TypeVariable) {
rv.add(typeVariables.get(((TypeVariable<?>) types[i]).getName()));
} else {
rv.add((Class<?>) types[i]);
}
}
return rv;
}
public static Method findMethodForName(final Class<? extends Component> cls, String methodName) {
Class<?> current = cls;
Method foundMethod = null;
while (Component.class.isAssignableFrom(current)) {
for (Method method : current.getDeclaredMethods()) {
if (foundMethod == null && method.getAnnotation(Remoted.class) == null
&& method.getName().equals(methodName)) {
foundMethod = method;
} else if (method.getAnnotation(Remoted.class) != null
&& method.getName().equals(methodName)) {
return foundMethod == null ? method : foundMethod;
}
}
current = current.getSuperclass();
}
return null;
}
}