/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. Alternatively, the contents of this file may be used under
* the terms of the GNU Lesser General Public License Version 2.1 or later,
* or the Apache License Version 2.0.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*/
package javassist.util.proxy;
import java.lang.reflect.
Method;
import java.io.
BufferedOutputStream;
import java.io.
ByteArrayOutputStream;
import java.io.
DataOutputStream;
import java.io.
File;
import java.io.
FileOutputStream;
import java.io.
IOException;
import java.security.
ProtectionDomain;
import javassist.
CannotCompileException;
import javassist.bytecode.
ClassFile;
/**
* A helper class for implementing <code>ProxyFactory</code>.
* The users of <code>ProxyFactory</code> do not have to see this class.
*
* @see ProxyFactory
*/
public class
FactoryHelper {
private static java.lang.reflect.
Method defineClass1,
defineClass2;
static {
try {
Class cl =
Class.
forName("java.lang.ClassLoader");
defineClass1 =
SecurityActions.
getDeclaredMethod(
cl,
"defineClass",
new
Class[] {
String.class, byte[].class,
int.class, int.class });
defineClass2 =
SecurityActions.
getDeclaredMethod(
cl,
"defineClass",
new
Class[] {
String.class, byte[].class,
int.class, int.class,
ProtectionDomain.class });
}
catch (
Exception e) {
throw new
RuntimeException("cannot initialize");
}
}
/**
* Returns an index for accessing arrays in this class.
*
* @throws RuntimeException if a given type is not a primitive type.
*/
public static final int
typeIndex(
Class type) {
Class[]
list =
primitiveTypes;
int
n =
list.length;
for (int
i = 0;
i <
n;
i++)
if (
list[
i] ==
type)
return
i;
throw new
RuntimeException("bad type:" +
type.
getName());
}
/**
* <code>Class</code> objects representing primitive types.
*/
public static final
Class[]
primitiveTypes = {
Boolean.
TYPE,
Byte.
TYPE,
Character.
TYPE,
Short.
TYPE,
Integer.
TYPE,
Long.
TYPE,
Float.
TYPE,
Double.
TYPE,
Void.
TYPE
};
/**
* The fully-qualified names of wrapper classes for primitive types.
*/
public static final
String[]
wrapperTypes = {
"java.lang.Boolean", "java.lang.Byte", "java.lang.Character",
"java.lang.Short", "java.lang.Integer", "java.lang.Long",
"java.lang.Float", "java.lang.Double", "java.lang.Void"
};
/**
* The descriptors of the constructors of wrapper classes.
*/
public static final
String[]
wrapperDesc = {
"(Z)V", "(B)V", "(C)V", "(S)V", "(I)V", "(J)V",
"(F)V", "(D)V"
};
/**
* The names of methods for obtaining a primitive value
* from a wrapper object. For example, <code>intValue()</code>
* is such a method for obtaining an integer value from a
* <code>java.lang.Integer</code> object.
*/
public static final
String[]
unwarpMethods = {
"booleanValue", "byteValue", "charValue", "shortValue",
"intValue", "longValue", "floatValue", "doubleValue"
};
/**
* The descriptors of the unwrapping methods contained
* in <code>unwrapMethods</code>.
*/
public static final
String[]
unwrapDesc = {
"()Z", "()B", "()C", "()S", "()I", "()J", "()F", "()D"
};
/**
* The data size of primitive types. <code>long</code>
* and <code>double</code> are 2; the others are 1.
*/
public static final int[]
dataSize = {
1, 1, 1, 1, 1, 2, 1, 2
};
/**
* Loads a class file by a given class loader.
* This method uses a default protection domain for the class
* but it may not work with a security manager or a sigend jar file.
*
* @see #toClass(ClassFile,ClassLoader,ProtectionDomain)
*/
public static
Class toClass(
ClassFile cf,
ClassLoader loader)
throws
CannotCompileException
{
return
toClass(
cf,
loader, null);
}
/**
* Loads a class file by a given class loader.
*
* @param domain if it is null, a default domain is used.
* @since 3.3
*/
public static
Class toClass(
ClassFile cf,
ClassLoader loader,
ProtectionDomain domain)
throws
CannotCompileException
{
try {
byte[]
b =
toBytecode(
cf);
Method method;
Object[]
args;
if (
domain == null) {
method =
defineClass1;
args = new
Object[] {
cf.
getName(),
b, new
Integer(0),
new
Integer(
b.length) };
}
else {
method =
defineClass2;
args = new
Object[] {
cf.
getName(),
b, new
Integer(0),
new
Integer(
b.length),
domain };
}
return
toClass2(
method,
loader,
args);
}
catch (
RuntimeException e) {
throw
e;
}
catch (java.lang.reflect.
InvocationTargetException e) {
throw new
CannotCompileException(
e.
getTargetException());
}
catch (
Exception e) {
throw new
CannotCompileException(
e);
}
}
private static synchronized
Class toClass2(
Method method,
ClassLoader loader,
Object[]
args)
throws
Exception
{
SecurityActions.
setAccessible(
method, true);
Class clazz = (
Class)
method.
invoke(
loader,
args);
SecurityActions.
setAccessible(
method, false);
return
clazz;
}
private static byte[]
toBytecode(
ClassFile cf) throws
IOException {
ByteArrayOutputStream barray = new
ByteArrayOutputStream();
DataOutputStream out = new
DataOutputStream(
barray);
try {
cf.
write(
out);
}
finally {
out.
close();
}
return
barray.
toByteArray();
}
/**
* Writes a class file.
*/
public static void
writeFile(
ClassFile cf,
String directoryName)
throws
CannotCompileException {
try {
writeFile0(
cf,
directoryName);
}
catch (
IOException e) {
throw new
CannotCompileException(
e);
}
}
private static void
writeFile0(
ClassFile cf,
String directoryName)
throws
CannotCompileException,
IOException {
String classname =
cf.
getName();
String filename =
directoryName +
File.
separatorChar
+
classname.
replace('.',
File.
separatorChar) + ".class";
int
pos =
filename.
lastIndexOf(
File.
separatorChar);
if (
pos > 0) {
String dir =
filename.
substring(0,
pos);
if (!
dir.
equals("."))
new
File(
dir).
mkdirs();
}
DataOutputStream out = new
DataOutputStream(new
BufferedOutputStream(
new
FileOutputStream(
filename)));
try {
cf.
write(
out);
}
catch (
IOException e) {
throw
e;
}
finally {
out.
close();
}
}
}