View Javadoc
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 }