• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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