1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later. 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 */ 15 16 package javassist.util.proxy; 17 18 import java.lang.reflect.Method; 19 import java.io.BufferedOutputStream; 20 import java.io.ByteArrayOutputStream; 21 import java.io.DataOutputStream; 22 import java.io.File; 23 import java.io.FileOutputStream; 24 import java.io.IOException; 25 import java.security.ProtectionDomain; 26 27 import javassist.CannotCompileException; 28 import javassist.bytecode.ClassFile; 29 30 /** 31 * A helper class for implementing <code>ProxyFactory</code>. 32 * The users of <code>ProxyFactory</code> do not have to see this class. 33 * 34 * @see ProxyFactory 35 */ 36 public class FactoryHelper { 37 private static java.lang.reflect.Method defineClass1, defineClass2; 38 39 static { 40 try { 41 Class cl = Class.forName("java.lang.ClassLoader"); 42 defineClass1 = SecurityActions.getDeclaredMethod( 43 cl, 44 "defineClass", 45 new Class[] { String.class, byte[].class, 46 int.class, int.class }); 47 48 defineClass2 = SecurityActions.getDeclaredMethod( 49 cl, 50 "defineClass", 51 new Class[] { String.class, byte[].class, 52 int.class, int.class, ProtectionDomain.class }); 53 } 54 catch (Exception e) { 55 throw new RuntimeException("cannot initialize"); 56 } 57 } 58 59 /** 60 * Returns an index for accessing arrays in this class. 61 * 62 * @throws RuntimeException if a given type is not a primitive type. 63 */ typeIndex(Class type)64 public static final int typeIndex(Class type) { 65 Class[] list = primitiveTypes; 66 int n = list.length; 67 for (int i = 0; i < n; i++) 68 if (list[i] == type) 69 return i; 70 71 throw new RuntimeException("bad type:" + type.getName()); 72 } 73 74 /** 75 * <code>Class</code> objects representing primitive types. 76 */ 77 public static final Class[] primitiveTypes = { 78 Boolean.TYPE, Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE, 79 Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE 80 }; 81 82 /** 83 * The fully-qualified names of wrapper classes for primitive types. 84 */ 85 public static final String[] wrapperTypes = { 86 "java.lang.Boolean", "java.lang.Byte", "java.lang.Character", 87 "java.lang.Short", "java.lang.Integer", "java.lang.Long", 88 "java.lang.Float", "java.lang.Double", "java.lang.Void" 89 }; 90 91 /** 92 * The descriptors of the constructors of wrapper classes. 93 */ 94 public static final String[] wrapperDesc = { 95 "(Z)V", "(B)V", "(C)V", "(S)V", "(I)V", "(J)V", 96 "(F)V", "(D)V" 97 }; 98 99 /** 100 * The names of methods for obtaining a primitive value 101 * from a wrapper object. For example, <code>intValue()</code> 102 * is such a method for obtaining an integer value from a 103 * <code>java.lang.Integer</code> object. 104 */ 105 public static final String[] unwarpMethods = { 106 "booleanValue", "byteValue", "charValue", "shortValue", 107 "intValue", "longValue", "floatValue", "doubleValue" 108 }; 109 110 /** 111 * The descriptors of the unwrapping methods contained 112 * in <code>unwrapMethods</code>. 113 */ 114 public static final String[] unwrapDesc = { 115 "()Z", "()B", "()C", "()S", "()I", "()J", "()F", "()D" 116 }; 117 118 /** 119 * The data size of primitive types. <code>long</code> 120 * and <code>double</code> are 2; the others are 1. 121 */ 122 public static final int[] dataSize = { 123 1, 1, 1, 1, 1, 2, 1, 2 124 }; 125 126 /** 127 * Loads a class file by a given class loader. 128 * This method uses a default protection domain for the class 129 * but it may not work with a security manager or a sigend jar file. 130 * 131 * @see #toClass(ClassFile,ClassLoader,ProtectionDomain) 132 */ toClass(ClassFile cf, ClassLoader loader)133 public static Class toClass(ClassFile cf, ClassLoader loader) 134 throws CannotCompileException 135 { 136 return toClass(cf, loader, null); 137 } 138 139 /** 140 * Loads a class file by a given class loader. 141 * 142 * @param domain if it is null, a default domain is used. 143 * @since 3.3 144 */ toClass(ClassFile cf, ClassLoader loader, ProtectionDomain domain)145 public static Class toClass(ClassFile cf, ClassLoader loader, ProtectionDomain domain) 146 throws CannotCompileException 147 { 148 try { 149 byte[] b = toBytecode(cf); 150 Method method; 151 Object[] args; 152 if (domain == null) { 153 method = defineClass1; 154 args = new Object[] { cf.getName(), b, new Integer(0), 155 new Integer(b.length) }; 156 } 157 else { 158 method = defineClass2; 159 args = new Object[] { cf.getName(), b, new Integer(0), 160 new Integer(b.length), domain }; 161 } 162 163 return toClass2(method, loader, args); 164 } 165 catch (RuntimeException e) { 166 throw e; 167 } 168 catch (java.lang.reflect.InvocationTargetException e) { 169 throw new CannotCompileException(e.getTargetException()); 170 } 171 catch (Exception e) { 172 throw new CannotCompileException(e); 173 } 174 } 175 toClass2(Method method, ClassLoader loader, Object[] args)176 private static synchronized Class toClass2(Method method, 177 ClassLoader loader, Object[] args) 178 throws Exception 179 { 180 SecurityActions.setAccessible(method, true); 181 Class clazz = (Class)method.invoke(loader, args); 182 SecurityActions.setAccessible(method, false); 183 return clazz; 184 } 185 toBytecode(ClassFile cf)186 private static byte[] toBytecode(ClassFile cf) throws IOException { 187 ByteArrayOutputStream barray = new ByteArrayOutputStream(); 188 DataOutputStream out = new DataOutputStream(barray); 189 try { 190 cf.write(out); 191 } 192 finally { 193 out.close(); 194 } 195 196 return barray.toByteArray(); 197 } 198 199 /** 200 * Writes a class file. 201 */ writeFile(ClassFile cf, String directoryName)202 public static void writeFile(ClassFile cf, String directoryName) 203 throws CannotCompileException { 204 try { 205 writeFile0(cf, directoryName); 206 } 207 catch (IOException e) { 208 throw new CannotCompileException(e); 209 } 210 } 211 writeFile0(ClassFile cf, String directoryName)212 private static void writeFile0(ClassFile cf, String directoryName) 213 throws CannotCompileException, IOException { 214 String classname = cf.getName(); 215 String filename = directoryName + File.separatorChar 216 + classname.replace('.', File.separatorChar) + ".class"; 217 int pos = filename.lastIndexOf(File.separatorChar); 218 if (pos > 0) { 219 String dir = filename.substring(0, pos); 220 if (!dir.equals(".")) 221 new File(dir).mkdirs(); 222 } 223 224 DataOutputStream out = new DataOutputStream(new BufferedOutputStream( 225 new FileOutputStream(filename))); 226 try { 227 cf.write(out); 228 } 229 catch (IOException e) { 230 throw e; 231 } 232 finally { 233 out.close(); 234 } 235 } 236 } 237