/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* 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.jboss.weld.util.bytecode;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import org.jboss.classfilewriter.ClassFile;
/**
* Utility class for loading a ClassFile into a classloader. This borrows
* heavily from javassist
*
* @author Stuart Douglas
*/
public class ClassFileUtils {
private static java.lang.reflect.Method defineClass1, defineClass2;
private ClassFileUtils() {
}
static {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
Class<?> cl = Class.forName("java.lang.ClassLoader");
final String name = "defineClass";
defineClass1 = cl.getDeclaredMethod(name, new Class[]{String.class, byte[].class, int.class, int.class});
defineClass1.setAccessible(true);
defineClass2 = cl.getDeclaredMethod(name, new Class[]{String.class, byte[].class, int.class, int.class, ProtectionDomain.class});
defineClass2.setAccessible(true);
return null;
}
});
} catch (PrivilegedActionException pae) {
throw new RuntimeException("cannot initialize ClassPool", pae.getException());
}
}
/**
* Converts the class to a <code>java.lang.Class</code> object. Once this
* method is called, further modifications are not allowed any more.
* <p/>
* <p/>
* The class file represented by the given <code>CtClass</code> is loaded by
* the given class loader to construct a <code>java.lang.Class</code> object.
* Since a private method on the class loader is invoked through the
* reflection API, the caller must have permissions to do that.
* <p/>
* <p/>
* An easy way to obtain <code>ProtectionDomain</code> object is to call
* <code>getProtectionDomain()</code> in <code>java.lang.Class</code>. It
* returns the domain that the class belongs to.
* <p/>
* <p/>
* This method is provided for convenience. If you need more complex
* functionality, you should write your own class loader.
*
* @param loader the class loader used to load this class. For example, the
* loader returned by <code>getClassLoader()</code> can be used for
* this parameter.
* @param domain the protection domain for the class. If it is null, the
* default domain created by <code>java.lang.ClassLoader</code> is
*/
public static Class<?> toClass(ClassFile ct, ClassLoader loader, ProtectionDomain domain) {
try {
byte[] b = ct.toBytecode();
java.lang.reflect.Method method;
Object[] args;
if (domain == null) {
method = defineClass1;
args = new Object[]{ct.getName(), b, 0, b.length};
} else {
method = defineClass2;
args = new Object[]{ct.getName(), b, 0, b.length, domain};
}
return toClass2(method, loader, args);
} catch (RuntimeException e) {
throw e;
} catch (java.lang.reflect.InvocationTargetException e) {
throw new RuntimeException(e.getTargetException());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static synchronized Class<?> toClass2(Method method, ClassLoader loader, Object[] args) throws Exception {
Class<?> clazz = Class.class.cast(method.invoke(loader, args));
return clazz;
}
}