1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.proxy.factory.javassist;
19
20 import javassist.CannotCompileException;
21 import javassist.ClassPool;
22 import javassist.CtClass;
23 import javassist.CtField;
24 import javassist.LoaderClassPath;
25 import javassist.NotFoundException;
26 import org.apache.commons.proxy.ProxyUtils;
27 import org.apache.commons.proxy.exception.ObjectProviderException;
28
29 import java.util.HashSet;
30 import java.util.Set;
31
32 /**
33 * Some utility methods for dealing with Javassist. This class is not part of the public API!
34 *
35 * @author James Carman
36 * @since 1.0
37 */
38 class JavassistUtils
39 {
40 //----------------------------------------------------------------------------------------------------------------------
41 // Fields
42 //----------------------------------------------------------------------------------------------------------------------
43 public static final String DEFAULT_BASE_NAME = "JavassistUtilsGenerated";
44 private static int classNumber = 0;
45 private static final ClassPool classPool = new ClassPool();
46
47 static
48 {
49 classPool.appendClassPath( new LoaderClassPath( ClassLoader.getSystemClassLoader() ) );
50 }
51
52 private static final Set classLoaders = new HashSet();
53 //----------------------------------------------------------------------------------------------------------------------
54 // Static Methods
55 //----------------------------------------------------------------------------------------------------------------------
56
57 /**
58 * Adds a field to a class.
59 *
60 * @param fieldType the field's type
61 * @param fieldName the field name
62 * @param enclosingClass the class receiving the new field
63 * @throws CannotCompileException if a compilation problem occurs
64 */
65 public static void addField( Class fieldType, String fieldName, CtClass enclosingClass )
66 throws CannotCompileException
67 {
68 enclosingClass.addField( new CtField( resolve( fieldType ), fieldName, enclosingClass ) );
69 }
70
71 /**
72 * Finds the {@link CtClass} corresponding to the Java {@link Class} passed in.
73 *
74 * @param clazz the Java {@link Class}
75 * @return the {@link CtClass}
76 */
77 public static CtClass resolve( Class clazz )
78 {
79 synchronized( classLoaders )
80 {
81 try
82 {
83 final ClassLoader loader = clazz.getClassLoader();
84 if( loader != null && !classLoaders.contains( loader ) )
85 {
86 classLoaders.add( loader );
87 classPool.appendClassPath( new LoaderClassPath( loader ) );
88 }
89 return classPool.get( ProxyUtils.getJavaClassName( clazz ) );
90 }
91 catch( NotFoundException e )
92 {
93 throw new ObjectProviderException(
94 "Unable to find class " + clazz.getName() + " in default Javassist class pool.", e );
95 }
96 }
97 }
98
99 /**
100 * Adds interfaces to a {@link CtClass}
101 *
102 * @param ctClass the {@link CtClass}
103 * @param proxyClasses the interfaces
104 */
105 public static void addInterfaces( CtClass ctClass, Class[] proxyClasses )
106 {
107 for( int i = 0; i < proxyClasses.length; i++ )
108 {
109 Class proxyInterface = proxyClasses[i];
110 ctClass.addInterface( resolve( proxyInterface ) );
111 }
112 }
113
114 /**
115 * Creates a new {@link CtClass} derived from the Java {@link Class} using the default base name.
116 *
117 * @param superclass the superclass
118 * @return the new derived {@link CtClass}
119 */
120 public static CtClass createClass( Class superclass )
121 {
122 return createClass( DEFAULT_BASE_NAME, superclass );
123 }
124
125 /**
126 * Creates a new {@link CtClass} derived from the Java {@link Class} using the supplied base name.
127 *
128 * @param baseName the base name
129 * @param superclass the superclass
130 * @return the new derived {@link CtClass}
131 */
132 public synchronized static CtClass createClass( String baseName, Class superclass )
133 {
134 return classPool.makeClass( baseName + "_" + classNumber++, resolve( superclass ) );
135 }
136
137 /**
138 * Resolves an array of Java {@link Class}es to an array of their corresponding {@link CtClass}es.
139 *
140 * @param classes the Java {@link Class}es
141 * @return the corresponding {@link CtClass}es
142 */
143 public static CtClass[] resolve( Class[] classes )
144 {
145 final CtClass[] ctClasses = new CtClass[classes.length];
146 for( int i = 0; i < ctClasses.length; ++i )
147 {
148 ctClasses[i] = resolve( classes[i] );
149 }
150 return ctClasses;
151 }
152 }
153