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

org.jadira.reflection.access.classloader.AccessClassLoader Maven / Gradle / Ivy

There is a newer version: 7.0.0.CR1
Show newest version
/*
 *  Copyright 2013 Christopher Pheby
 *
 *  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 org.jadira.reflection.access.classloader;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * A ClassLoader which can be used to load classes from arbitrary byte arrays.
 * Jadira uses this to load classes generated using ASM.
 */
public class AccessClassLoader extends ClassLoader {

	private static final Method DEFINE_METHOD;
	
	static {
		Method defineMethod = null;
		try {
			defineMethod = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class, int.class });
			defineMethod.setAccessible(true);
		} catch (NoSuchMethodException e) {
		} catch (SecurityException e) {
		}
		DEFINE_METHOD = defineMethod;
	}
	 
	private static final ConcurrentHashMap ASM_CLASS_LOADERS = new ConcurrentHashMap();

	private static final Map registeredClasses = new HashMap();
	
	/**
	 * Creates a new instance using a suitable ClassLoader for the specified class
	 * @param typeToBeExtended The class to use to obtain a ClassLoader
	 * @return A new instance, or an existing instance if one already exists.
	 */
	public static final AccessClassLoader get(Class typeToBeExtended) {

		ClassLoader loader = typeToBeExtended.getClassLoader();
		return get(loader == null ? ClassLoader.getSystemClassLoader() : loader);
	}
	
	/**
	 * Creates an AccessClassLoader for the given parent
	 * @param parent The parent ClassLoader for this instance
	 * @return A new instance, or an existing instance if one already exists.
	 */
	public synchronized static final AccessClassLoader get(ClassLoader parent) {
		AccessClassLoader loader = (AccessClassLoader) ASM_CLASS_LOADERS.get(parent);
		if (loader == null) {
			loader = new AccessClassLoader(parent);
			ASM_CLASS_LOADERS.put(parent, loader);
		}
		return loader;
	}

	private AccessClassLoader(ClassLoader parentClassLoader) {
		super(parentClassLoader);
	}

	@Override
	public Class loadClass(String name) throws ClassNotFoundException {

		Class loadedClass = findLoadedClass(name);

		if (loadedClass == null) {
			
			try {
				loadedClass = findClass(name);
			} catch (ClassNotFoundException e) {
				// Ignore
			}
			
			if (loadedClass == null) {
				loadedClass = super.loadClass(name);
			}
		}

		return loadedClass;
	}
	
	/**
	 * Registers a class by its name
	 * @param name The name of the class to be registered
	 * @param bytes An array of bytes containing the class
	 */
	public void registerClass(String name, byte[] bytes) {
	    
		if (registeredClasses.containsKey(name)) {
			throw new IllegalStateException("Attempted to register a class that has been registered already: " + name);
		}
		registeredClasses.put(name, bytes);
	}
	
	@Override
    public Class findClass(String name) throws ClassNotFoundException {
	    
		byte[] bytes = registeredClasses.get(name);
		if (bytes != null) {
			registeredClasses.remove(name);
			try {
				return (Class) DEFINE_METHOD.invoke(getParent(), new Object[] { name, bytes, Integer.valueOf(0), Integer.valueOf(bytes.length) });
			} catch (Exception ignored) {
			}
			return defineClass(name, bytes, 0, bytes.length);
		}
		throw new ClassNotFoundException("Cannot find class: " + name);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy