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

org.walkmod.util.ClassLoaderUtil Maven / Gradle / Ivy

There is a newer version: 3.0.5
Show newest version
/* 
  Copyright (C) 2013 Raquel Pau and Albert Coroleu.
 
 Walkmod is free software: you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 Walkmod is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License
 along with Walkmod.  If not, see .*/
package org.walkmod.util;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

public class ClassLoaderUtil {

	private static Map> primitiveClasses = new HashMap>();

	private static Map wrapperClasses = new HashMap();

	private static Map matrixTypePosition;

	private static boolean[][] compatibilityMatrix;

	private static Set langPackageContent;

	static {
		primitiveClasses.put("boolean", boolean.class);
		primitiveClasses.put("int", int.class);
		primitiveClasses.put("long", long.class);
		primitiveClasses.put("double", double.class);
		primitiveClasses.put("char", char.class);
		primitiveClasses.put("float", float.class);
		primitiveClasses.put("short", short.class);
		primitiveClasses.put("byte", byte.class);
		matrixTypePosition = new HashMap();
		matrixTypePosition.put("byte", 0);
		matrixTypePosition.put("java.lang.Byte", 0);
		matrixTypePosition.put("short", 1);
		matrixTypePosition.put("char", 2);
		matrixTypePosition.put("java.lang.Character", 2);
		matrixTypePosition.put("int", 3);
		matrixTypePosition.put("java.lang.Integer", 3);
		matrixTypePosition.put("long", 4);
		matrixTypePosition.put("java.lang.Long", 4);
		matrixTypePosition.put("float", 5);
		matrixTypePosition.put("java.lang.Float", 5);
		matrixTypePosition.put("double", 6);
		matrixTypePosition.put("java.lang.Double", 6);
		matrixTypePosition.put("boolean", 7);
		matrixTypePosition.put("java.lang.Boolean", 7);
		matrixTypePosition.put("String", 8);
		matrixTypePosition.put("java.lang.String", 8);
		matrixTypePosition.put("java.lang.Object", 9);
		wrapperClasses.put("java.lang.Byte", "byte");
		wrapperClasses.put("java.lang.Character", "char");
		wrapperClasses.put("java.lang.Integer", "int");
		wrapperClasses.put("java.lang.Long", "long");
		wrapperClasses.put("java.lang.Float", "float");
		wrapperClasses.put("java.lang.Double", "double");
		wrapperClasses.put("java.lang.Boolean", "boolean");
		compatibilityMatrix = new boolean[][] { { true, true, true, true, true, true, true, false, false, true },
				{ false, true, false, true, true, true, true, false, false, true },
				{ false, false, true, true, true, true, true, false, false, true },
				{ false, false, false, true, true, true, true, false, false, true },
				{ false, false, false, false, true, true, true, false, false, true },
				{ false, false, false, false, false, true, true, false, false, true },
				{ false, false, false, false, false, false, true, false, false, true },
				{ false, false, false, false, false, false, false, true, false, true },
				{ false, false, false, false, false, false, false, false, true, true },
				{ false, false, false, false, false, false, false, false, false, true } };
		langPackageContent = new HashSet();
		langPackageContent.add("Appendable");
		langPackageContent.add("CharSequence");
		langPackageContent.add("Cloneable");
		langPackageContent.add("Comparable");
		langPackageContent.add("Iterable");
		langPackageContent.add("Readable");
		langPackageContent.add("Runnable");
		langPackageContent.add("Thread$UncaughtExceptionHandler");
		langPackageContent.add("Boolean");
		langPackageContent.add("Byte");
		langPackageContent.add("Character");
		langPackageContent.add("Character$Subset");
		langPackageContent.add("Character$UnicodeBlock");
		langPackageContent.add("Class");
		langPackageContent.add("ClassLoader");
		langPackageContent.add("Compiler");
		langPackageContent.add("Double");
		langPackageContent.add("Enum");
		langPackageContent.add("Float");
		langPackageContent.add("InheritableThreadLocal");
		langPackageContent.add("Integer");
		langPackageContent.add("Long");
		langPackageContent.add("Math");
		langPackageContent.add("Number");
		langPackageContent.add("Object");
		langPackageContent.add("Package");
		langPackageContent.add("Process");
		langPackageContent.add("ProcessBuilder");
		langPackageContent.add("Runtime");
		langPackageContent.add("RuntimePermission");
		langPackageContent.add("SecurityManager");
		langPackageContent.add("Short");
		langPackageContent.add("StackTraceElement");
		langPackageContent.add("StrictMath");
		langPackageContent.add("String");
		langPackageContent.add("StringBuffer");
		langPackageContent.add("StringBuilder");
		langPackageContent.add("System");
		langPackageContent.add("Thread");
		langPackageContent.add("ThreadGroup");
		langPackageContent.add("ThreadLocal");
		langPackageContent.add("Throwable");
		langPackageContent.add("Void");
		langPackageContent.add("Thread$State");
		langPackageContent.add("ArithmeticException");
		langPackageContent.add("ArrayIndexOutOfBoundsException");
		langPackageContent.add("ArrayStoreException");
		langPackageContent.add("ClassCastException");
		langPackageContent.add("ClassNotFoundException");
		langPackageContent.add("CloneNotSupportedException");
		langPackageContent.add("EnumConstantNotPresentException");
		langPackageContent.add("Exception");
		langPackageContent.add("IllegalAccessException");
		langPackageContent.add("IllegalArgumentException");
		langPackageContent.add("IllegalMonitorStateException");
		langPackageContent.add("IllegalStateException");
		langPackageContent.add("IllegalThreadStateException");
		langPackageContent.add("IndexOutOfBoundsException");
		langPackageContent.add("InstantiationException");
		langPackageContent.add("InterruptedException");
		langPackageContent.add("NegativeArraySizeException");
		langPackageContent.add("NoSuchFieldException");
		langPackageContent.add("NoSuchMethodException");
		langPackageContent.add("NullPointerException");
		langPackageContent.add("NumberFormatException");
		langPackageContent.add("RuntimeException");
		langPackageContent.add("SecurityException");
		langPackageContent.add("StringIndexOutOfBoundsException");
		langPackageContent.add("TypeNotPresentException");
		langPackageContent.add("UnsupportedOperationException");
		langPackageContent.add("AbstractMethodError");
		langPackageContent.add("AssertionError");
		langPackageContent.add("ClassCircularityError");
		langPackageContent.add("ClassFormatError");
		langPackageContent.add("Error");
		langPackageContent.add("ExceptionInInitializerError");
		langPackageContent.add("IllegalAccessError");
		langPackageContent.add("IncompatibleClassChangeError");
		langPackageContent.add("InstatiationError");
		langPackageContent.add("InternalError");
		langPackageContent.add("LinkageError");
		langPackageContent.add("NoClassDefFoundError");
		langPackageContent.add("NoSuchFieldError");
		langPackageContent.add("NoSuchMethodError");
		langPackageContent.add("OutOfMemoryError");
		langPackageContent.add("StackOverflowError");
		langPackageContent.add("ThreadDeath");
		langPackageContent.add("UnknownError");
		langPackageContent.add("UnsatistiedLinkError");
		langPackageContent.add("UnsupportedClassVersionError");
		langPackageContent.add("VerifyError");
		langPackageContent.add("VirtualMachineError");
		langPackageContent.add("Deprecated");
		langPackageContent.add("Override");
		langPackageContent.add("SuppressWarnings");
	}

	public static boolean belongsToLangPackage(String clazz) {
		return langPackageContent.contains(clazz);
	}

	public static boolean isCompatible(Class fromClass, Class toClass) {
		if (fromClass == null || toClass == null) {
			return true;
		}
		if (matrixTypePosition.containsKey(fromClass.getName()) && matrixTypePosition.containsKey(toClass.getName())) {
			return compatibilityMatrix[matrixTypePosition.get(fromClass.getName())][matrixTypePosition.get(toClass
					.getName())];
		} else {
			return toClass.isAssignableFrom(fromClass);
		}
	}

	public static boolean isPrimitiveWrapperClass(Class clazz) {
		return wrapperClasses.containsKey(clazz.getName());
	}

	public static Class getPrimitiveClass(Class wrapperClazz) {
		if (isPrimitiveWrapperClass(wrapperClazz)) {
			return getPrimitiveClass(wrapperClasses.get(wrapperClazz.getName()));
		}
		return null;
	}

	public static Class getPrimitiveClass(String name) {
		return primitiveClasses.get(name);
	}

	public static boolean isCompatible(Class[] fromClasses, Class[] toClasses) {
		if (fromClasses.length == toClasses.length) {
			boolean assignable = true;
			for (int i = 0; i < fromClasses.length && assignable; i++) {
				assignable = isCompatible(fromClasses[i], toClasses[i]);
			}
			return assignable;
		}
		return false;
	}

	/**
	 * This method returns a method(public, protected or private) which appears
	 * in the selected class or any of its parent (interface or superclass) or
	 * container classes (when the selected class is an inner class) which
	 * matches with the name and whose parameters are compatible with the
	 * selected typeArgs.
	 * 
	 * @param clazz
	 *            Class to scan
	 * @param methodName
	 *            Method name
	 * @param typeArgs
	 *            Method arguments
	 * @return Method instance
	 */
	public Method getMethod(Class clazz, String methodName, Class... typeArgs) {
		int numParams = typeArgs == null ? 0 : typeArgs.length;
		Method[] classMethods = clazz.getMethods();
		for (Method method : classMethods) {
			if (method.getName().equals(methodName)) {
				if (method.getParameterTypes().length == numParams) {
					boolean isCompatible = true;
					Class[] methodParameterTypes = method.getParameterTypes();
					for (int i = 0; i < methodParameterTypes.length; i++) {
						isCompatible = isCompatible(typeArgs[i], methodParameterTypes[i]);
						if (!isCompatible)
							break;
					}
					if (isCompatible) {
						return method;
					}
				}
			}
		}
		classMethods = clazz.getDeclaredMethods();
		for (Method method : classMethods) {
			if (method.getName().equals(methodName)) {
				if (method.getParameterTypes().length == numParams) {
					boolean isCompatible = true;
					Class[] methodParameterTypes = method.getParameterTypes();
					for (int i = 0; i < methodParameterTypes.length; i++) {
						isCompatible = isCompatible(typeArgs[i], methodParameterTypes[i]);
						if (!isCompatible)
							break;
					}
					if (isCompatible) {
						return method;
					}
				}
			}
		}
		Method result = null;
		if (clazz.isMemberClass()) {
			result = getMethod(clazz.getEnclosingClass(), methodName, typeArgs);
		}
		if (result == null && clazz.getSuperclass() != null) {
			return getMethod(clazz.getSuperclass(), methodName, typeArgs);
		}
		return result;
	}

	/**
	 * Load all resources with a given name, potentially aggregating all results
	 * from the searched classloaders. If no results are found, the resource
	 * name is prepended by '/' and tried again.
	 *
	 * This method will try to load the resources using the following methods
	 * (in order):
	 * 
    *
  • From Thread.currentThread().getContextClassLoader() *
  • From ClassLoaderUtil.class.getClassLoader() *
  • callingClass.getClassLoader() *
* * @param resourceName * The name of the resources to load * @param callingClass * The Class object of the calling object * @param aggregate * true to aggregate resources from all classloaders * @return Iterator of matching resources * @throws IOException * If I/O errors occur */ public static Iterator getResources(String resourceName, Class callingClass, boolean aggregate) throws IOException { AggregateIterator iterator = new AggregateIterator(); iterator.addEnumeration(Thread.currentThread().getContextClassLoader().getResources(resourceName)); if (!iterator.hasNext() || aggregate) { iterator.addEnumeration(ClassLoaderUtil.class.getClassLoader().getResources(resourceName)); } if (!iterator.hasNext() || aggregate) { ClassLoader cl = callingClass.getClassLoader(); if (cl != null) { iterator.addEnumeration(cl.getResources(resourceName)); } } if (!iterator.hasNext() && (resourceName != null) && ((resourceName.length() == 0) || (resourceName.charAt(0) != '/'))) { return getResources('/' + resourceName, callingClass, aggregate); } return iterator; } /** * Load a given resource. * * This method will try to load the resource using the following methods (in * order): *
    *
  • From Thread.currentThread().getContextClassLoader() *
  • From ClassLoaderUtil.class.getClassLoader() *
  • callingClass.getClassLoader() *
* * @param resourceName * The name IllegalStateException("Unable to call ")of the * resource to load * @param callingClass * The Class object of the calling object * @return Matching resouce or null if not found */ public static URL getResource(String resourceName, Class callingClass) { URL url = Thread.currentThread().getContextClassLoader().getResource(resourceName); if (url == null) { url = ClassLoaderUtil.class.getClassLoader().getResource(resourceName); } if (url == null) { ClassLoader cl = callingClass.getClassLoader(); if (cl != null) { url = cl.getResource(resourceName); } } if ((url == null) && (resourceName != null) && ((resourceName.length() == 0) || (resourceName.charAt(0) != '/'))) { return getResource('/' + resourceName, callingClass); } return url; } /** * This is a convenience method to load a resource as a stream. * * The algorithm used to find the resource is given in getResource() * * @param resourceName * The name of the resource to load * @param callingClass * The Class object of the calling object * @return Matching resouce or null if not found */ public static InputStream getResourceAsStream(String resourceName, Class callingClass) { URL url = getResource(resourceName, callingClass); try { return (url != null) ? url.openStream() : null; } catch (IOException e) { return null; } } /** * Load a class with a given name. * * It will try to load the class in the following order: *
    *
  • From Thread.currentThread().getContextClassLoader() *
  • Using the basic Class.forName() *
  • From ClassLoaderUtil.class.getClassLoader() *
  • From the callingClass.getClassLoader() *
* * @param className * The name of the class to load * @param callingClass * The Class object of the calling object * @return Class definition * @throws ClassNotFoundException * If the class cannot be found anywhere. */ public static Class loadClass(String className, Class callingClass) throws ClassNotFoundException { try { return Thread.currentThread().getContextClassLoader().loadClass(className); } catch (ClassNotFoundException e) { try { return Class.forName(className); } catch (ClassNotFoundException ex) { try { return ClassLoaderUtil.class.getClassLoader().loadClass(className); } catch (ClassNotFoundException exc) { return callingClass.getClassLoader().loadClass(className); } } } } /** * Aggregates Enumeration instances into one iterator and filters out * duplicates. Always keeps one ahead of the enumerator to protect against * returning duplicates. */ protected static class AggregateIterator implements Iterator { LinkedList> enums = new LinkedList>(); Enumeration cur = null; E next = null; Set loaded = new HashSet(); public AggregateIterator addEnumeration(Enumeration e) { if (e.hasMoreElements()) { if (cur == null) { cur = e; next = e.nextElement(); loaded.add(next); } else { enums.add(e); } } return this; } public boolean hasNext() { return (next != null); } public E next() { if (next != null) { E prev = next; next = loadNext(); return prev; } else { throw new NoSuchElementException(); } } private Enumeration determineCurrentEnumeration() { if (cur != null && !cur.hasMoreElements()) { if (enums.size() > 0) { cur = enums.removeLast(); } else { cur = null; } } return cur; } private E loadNext() { if (determineCurrentEnumeration() != null) { E tmp = cur.nextElement(); while (loaded.contains(tmp)) { tmp = loadNext(); if (tmp == null) { break; } } if (tmp != null) { loaded.add(tmp); } return tmp; } return null; } public void remove() { throw new UnsupportedOperationException(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy