1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999- 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 * or the Apache License Version 2.0. 10 * 11 * Software distributed under the License is distributed on an "AS IS" basis, 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 13 * for the specific language governing rights and limitations under the 14 * License. 15 */ 16 17 package javassist.util.proxy; 18 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 /** 38 * Returns an index for accessing arrays in this class. 39 * 40 * @throws RuntimeException if a given type is not a primitive type. 41 */ typeIndex(Class<?> type)42 public static final int typeIndex(Class<?> type) { 43 for (int i = 0; i < primitiveTypes.length; i++) 44 if (primitiveTypes[i] == type) 45 return i; 46 47 throw new RuntimeException("bad type:" + type.getName()); 48 } 49 50 /** 51 * <code>Class</code> objects representing primitive types. 52 */ 53 public static final Class<?>[] primitiveTypes = { 54 Boolean.TYPE, Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE, 55 Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE 56 }; 57 58 /** 59 * The fully-qualified names of wrapper classes for primitive types. 60 */ 61 public static final String[] wrapperTypes = { 62 "java.lang.Boolean", "java.lang.Byte", "java.lang.Character", 63 "java.lang.Short", "java.lang.Integer", "java.lang.Long", 64 "java.lang.Float", "java.lang.Double", "java.lang.Void" 65 }; 66 67 /** 68 * The descriptors of the constructors of wrapper classes. 69 */ 70 public static final String[] wrapperDesc = { 71 "(Z)V", "(B)V", "(C)V", "(S)V", "(I)V", "(J)V", 72 "(F)V", "(D)V" 73 }; 74 75 /** 76 * The names of methods for obtaining a primitive value 77 * from a wrapper object. For example, <code>intValue()</code> 78 * is such a method for obtaining an integer value from a 79 * <code>java.lang.Integer</code> object. 80 */ 81 public static final String[] unwarpMethods = { 82 "booleanValue", "byteValue", "charValue", "shortValue", 83 "intValue", "longValue", "floatValue", "doubleValue" 84 }; 85 86 /** 87 * The descriptors of the unwrapping methods contained 88 * in <code>unwrapMethods</code>. 89 */ 90 public static final String[] unwrapDesc = { 91 "()Z", "()B", "()C", "()S", "()I", "()J", "()F", "()D" 92 }; 93 94 /** 95 * The data size of primitive types. <code>long</code> 96 * and <code>double</code> are 2; the others are 1. 97 */ 98 public static final int[] dataSize = { 99 1, 1, 1, 1, 1, 2, 1, 2 100 }; 101 102 /** 103 * Loads a class file by a given class loader. 104 * This method uses a default protection domain for the class 105 * but it may not work with a security manager or a signed jar file. 106 * 107 * @see #toClass(ClassFile,Class,ClassLoader,ProtectionDomain) 108 * @deprecated 109 */ toClass(ClassFile cf, ClassLoader loader)110 public static Class<?> toClass(ClassFile cf, ClassLoader loader) 111 throws CannotCompileException 112 { 113 return toClass(cf, null, loader, null); 114 } 115 116 /** 117 * Loads a class file by a given class loader. 118 * 119 * @param neighbor a class belonging to the same package that 120 * the loaded class belongs to. 121 * It can be null. 122 * @param loader The class loader. It can be null if {@code neighbor} 123 * is not null. 124 * @param domain if it is null, a default domain is used. 125 * @since 3.3 126 */ toClass(ClassFile cf, Class<?> neighbor, ClassLoader loader, ProtectionDomain domain)127 public static Class<?> toClass(ClassFile cf, Class<?> neighbor, 128 ClassLoader loader, ProtectionDomain domain) 129 throws CannotCompileException 130 { 131 try { 132 byte[] b = toBytecode(cf); 133 if (ProxyFactory.onlyPublicMethods) 134 return DefineClassHelper.toPublicClass(cf.getName(), b); 135 else 136 return DefineClassHelper.toClass(cf.getName(), neighbor, 137 loader, domain, b); 138 } 139 catch (IOException e) { 140 throw new CannotCompileException(e); 141 } 142 } 143 144 /** 145 * Loads a class file by a given lookup. 146 * 147 * @param lookup used to define the class. 148 * @since 3.24 149 */ toClass(ClassFile cf, java.lang.invoke.MethodHandles.Lookup lookup)150 public static Class<?> toClass(ClassFile cf, java.lang.invoke.MethodHandles.Lookup lookup) 151 throws CannotCompileException 152 { 153 try { 154 byte[] b = toBytecode(cf); 155 return DefineClassHelper.toClass(lookup, b); 156 } 157 catch (IOException e) { 158 throw new CannotCompileException(e); 159 } 160 } 161 toBytecode(ClassFile cf)162 private static byte[] toBytecode(ClassFile cf) throws IOException { 163 ByteArrayOutputStream barray = new ByteArrayOutputStream(); 164 DataOutputStream out = new DataOutputStream(barray); 165 try { 166 cf.write(out); 167 } 168 finally { 169 out.close(); 170 } 171 172 return barray.toByteArray(); 173 } 174 175 /** 176 * Writes a class file. 177 */ writeFile(ClassFile cf, String directoryName)178 public static void writeFile(ClassFile cf, String directoryName) 179 throws CannotCompileException { 180 try { 181 writeFile0(cf, directoryName); 182 } 183 catch (IOException e) { 184 throw new CannotCompileException(e); 185 } 186 } 187 writeFile0(ClassFile cf, String directoryName)188 private static void writeFile0(ClassFile cf, String directoryName) 189 throws CannotCompileException, IOException { 190 String classname = cf.getName(); 191 String filename = directoryName + File.separatorChar 192 + classname.replace('.', File.separatorChar) + ".class"; 193 int pos = filename.lastIndexOf(File.separatorChar); 194 if (pos > 0) { 195 String dir = filename.substring(0, pos); 196 if (!dir.equals(".")) 197 new File(dir).mkdirs(); 198 } 199 200 DataOutputStream out = new DataOutputStream(new BufferedOutputStream( 201 new FileOutputStream(filename))); 202 try { 203 cf.write(out); 204 } 205 catch (IOException e) { 206 throw e; 207 } 208 finally { 209 out.close(); 210 } 211 } 212 } 213