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.proxy2.javassist;
19
20 import java.util.HashSet;
21 import java.util.Set;
22 import java.util.concurrent.atomic.AtomicInteger;
23
24 import javassist.CannotCompileException;
25 import javassist.ClassPool;
26 import javassist.CtClass;
27 import javassist.CtField;
28 import javassist.LoaderClassPath;
29 import javassist.NotFoundException;
30
31 import org.apache.commons.proxy2.ProxyUtils;
32 import org.apache.commons.proxy2.exception.ObjectProviderException;
33
34 /**
35 * Some utility methods for dealing with Javassist. This class is not part of the public API!
36 *
37 * @since 1.0
38 */
39 final class JavassistUtils
40 {
41 //******************************************************************************************************************
42 // Fields
43 //******************************************************************************************************************
44
45 public static final String DEFAULT_BASE_NAME = "JavassistUtilsGenerated";
46 private static final AtomicInteger CLASS_NUMBER = new AtomicInteger(0);
47 private static final ClassPool CLASS_POOL = new ClassPool();
48 private static final Set<ClassLoader> CLASS_LOADERS = new HashSet<ClassLoader>();
49
50 //******************************************************************************************************************
51 // Static Methods
52 //******************************************************************************************************************
53
54 static
55 {
56 CLASS_POOL.appendClassPath(new LoaderClassPath(ClassLoader.getSystemClassLoader()));
57 }
58
59 /**
60 * Adds a field to a class.
61 *
62 * @param fieldType
63 * the field's type
64 * @param fieldName
65 * the field name
66 * @param enclosingClass
67 * the class receiving the new field
68 * @throws CannotCompileException
69 * if a compilation problem occurs
70 */
71 public static void addField(Class<?> fieldType, String fieldName, CtClass enclosingClass)
72 throws CannotCompileException
73 {
74 enclosingClass.addField(new CtField(resolve(fieldType), fieldName, enclosingClass));
75 }
76
77 /**
78 * Adds interfaces to a {@link CtClass}
79 *
80 * @param ctClass
81 * the {@link CtClass}
82 * @param proxyClasses
83 * the interfaces
84 */
85 public static void addInterfaces(CtClass ctClass, Class<?>[] proxyClasses)
86 {
87 for (int i = 0; i < proxyClasses.length; i++)
88 {
89 Class<?> proxyInterface = proxyClasses[i];
90 ctClass.addInterface(resolve(proxyInterface));
91 }
92 }
93
94 /**
95 * Creates a new {@link CtClass} derived from the Java {@link Class} using the default base name.
96 *
97 * @param superclass
98 * the superclass
99 * @return the new derived {@link CtClass}
100 */
101 public static CtClass createClass(Class<?> superclass)
102 {
103 return createClass(DEFAULT_BASE_NAME, superclass);
104 }
105
106 /**
107 * Creates a new {@link CtClass} derived from the Java {@link Class} using the supplied base name.
108 *
109 * @param baseName
110 * the base name
111 * @param superclass
112 * the superclass
113 * @return the new derived {@link CtClass}
114 */
115 public static synchronized CtClass createClass(String baseName, Class<?> superclass)
116 {
117 return CLASS_POOL.makeClass(baseName + "_" + CLASS_NUMBER.incrementAndGet(), resolve(superclass));
118 }
119
120 /**
121 * Finds the {@link CtClass} corresponding to the Java {@link Class} passed in.
122 *
123 * @param clazz
124 * the Java {@link Class}
125 * @return the {@link CtClass}
126 */
127 public static CtClass resolve(Class<?> clazz)
128 {
129 synchronized (CLASS_LOADERS)
130 {
131 try
132 {
133 final ClassLoader loader = clazz.getClassLoader();
134 if (loader != null && !CLASS_LOADERS.contains(loader))
135 {
136 CLASS_LOADERS.add(loader);
137 CLASS_POOL.appendClassPath(new LoaderClassPath(loader));
138 }
139 return CLASS_POOL.get(ProxyUtils.getJavaClassName(clazz));
140 }
141 catch (NotFoundException e)
142 {
143 throw new ObjectProviderException("Unable to find class " + clazz.getName()
144 + " in default Javassist class pool.", e);
145 }
146 }
147 }
148
149 /**
150 * Resolves an array of Java {@link Class}es to an array of their corresponding {@link CtClass}es.
151 *
152 * @param classes
153 * the Java {@link Class}es
154 * @return the corresponding {@link CtClass}es
155 */
156 public static CtClass[] resolve(Class<?>[] classes)
157 {
158 final CtClass[] ctClasses = new CtClass[classes.length];
159 for (int i = 0; i < ctClasses.length; ++i)
160 {
161 ctClasses[i] = resolve(classes[i]);
162 }
163 return ctClasses;
164 }
165
166 private JavassistUtils()
167 {
168 // Hiding constructor in utility class!
169 }
170 }