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