/platform/platform-impl/src/net/sf/cglib/core/AbstractClassGenerator.java

https://bitbucket.org/nbargnesi/idea · Java · 245 lines · 152 code · 27 blank · 66 comment · 25 complexity · da313f1c598b8b205971e880b8fe2ff3 MD5 · raw file

  1. /*
  2. * Copyright 2003,2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package net.sf.cglib.core;
  17. import org.objectweb.asm.ClassReader;
  18. import java.lang.ref.Reference;
  19. import java.lang.ref.WeakReference;
  20. import java.util.*;
  21. /**
  22. * Abstract class for all code-generating CGLIB utilities.
  23. * In addition to caching generated classes for performance, it provides hooks for
  24. * customizing the <code>ClassLoader</code>, name of the generated class, and transformations
  25. * applied before generation.
  26. *
  27. * intellij changes: made some fields final
  28. */
  29. abstract public class AbstractClassGenerator
  30. implements ClassGenerator
  31. {
  32. private static final Object NAME_KEY = new Object();
  33. private static final ThreadLocal CURRENT = new ThreadLocal();
  34. private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE;
  35. private NamingPolicy namingPolicy = DefaultNamingPolicy.INSTANCE;
  36. //change by Peter: make fields final
  37. private final Source source;
  38. private ClassLoader classLoader;
  39. private String namePrefix;
  40. private Object key;
  41. private boolean useCache = true;
  42. private String className;
  43. private boolean attemptLoad;
  44. protected static class Source {
  45. //change by Peter: made fields final
  46. final String name;
  47. final Map cache = new WeakHashMap();
  48. public Source(String name) {
  49. this.name = name;
  50. }
  51. }
  52. protected AbstractClassGenerator(Source source) {
  53. this.source = source;
  54. }
  55. protected void setNamePrefix(String namePrefix) {
  56. this.namePrefix = namePrefix;
  57. }
  58. final protected String getClassName() {
  59. if (className == null)
  60. className = getClassName(getClassLoader());
  61. return className;
  62. }
  63. private String getClassName(final ClassLoader loader) {
  64. final Set nameCache = getClassNameCache(loader);
  65. return namingPolicy.getClassName(namePrefix, source.name, key, new Predicate() {
  66. public boolean evaluate(Object arg) {
  67. return nameCache.contains(arg);
  68. }
  69. });
  70. }
  71. private Set getClassNameCache(ClassLoader loader) {
  72. return (Set)((Map)source.cache.get(loader)).get(NAME_KEY);
  73. }
  74. /**
  75. * Set the <code>ClassLoader</code> in which the class will be generated.
  76. * Concrete subclasses of <code>AbstractClassGenerator</code> (such as <code>Enhancer</code>)
  77. * will try to choose an appropriate default if this is unset.
  78. * <p>
  79. * Classes are cached per-<code>ClassLoader</code> using a <code>WeakHashMap</code>, to allow
  80. * the generated classes to be removed when the associated loader is garbage collected.
  81. * @param classLoader the loader to generate the new class with, or null to use the default
  82. */
  83. public void setClassLoader(ClassLoader classLoader) {
  84. this.classLoader = classLoader;
  85. }
  86. /**
  87. * Override the default naming policy.
  88. * @see DefaultNamingPolicy
  89. * @param namingPolicy the custom policy, or null to use the default
  90. */
  91. public void setNamingPolicy(NamingPolicy namingPolicy) {
  92. if (namingPolicy == null)
  93. namingPolicy = DefaultNamingPolicy.INSTANCE;
  94. this.namingPolicy = namingPolicy;
  95. }
  96. /**
  97. * @see #setNamingPolicy
  98. */
  99. public NamingPolicy getNamingPolicy() {
  100. return namingPolicy;
  101. }
  102. /**
  103. * Whether use and update the static cache of generated classes
  104. * for a class with the same properties. Default is <code>true</code>.
  105. */
  106. public void setUseCache(boolean useCache) {
  107. this.useCache = useCache;
  108. }
  109. /**
  110. * @see #setUseCache
  111. */
  112. public boolean getUseCache() {
  113. return useCache;
  114. }
  115. /**
  116. * If set, CGLIB will attempt to load classes from the specified
  117. * <code>ClassLoader</code> before generating them. Because generated
  118. * class names are not guaranteed to be unique, the default is <code>false</code>.
  119. */
  120. public void setAttemptLoad(boolean attemptLoad) {
  121. this.attemptLoad = attemptLoad;
  122. }
  123. public boolean getAttemptLoad() {
  124. return attemptLoad;
  125. }
  126. /**
  127. * Set the strategy to use to create the bytecode from this generator.
  128. * By default an instance of {@see DefaultGeneratorStrategy} is used.
  129. */
  130. public void setStrategy(GeneratorStrategy strategy) {
  131. if (strategy == null)
  132. strategy = DefaultGeneratorStrategy.INSTANCE;
  133. this.strategy = strategy;
  134. }
  135. /**
  136. * @see #setStrategy
  137. */
  138. public GeneratorStrategy getStrategy() {
  139. return strategy;
  140. }
  141. /**
  142. * Used internally by CGLIB. Returns the <code>AbstractClassGenerator</code>
  143. * that is being used to generate a class in the current thread.
  144. */
  145. public static AbstractClassGenerator getCurrent() {
  146. return (AbstractClassGenerator)CURRENT.get();
  147. }
  148. public ClassLoader getClassLoader() {
  149. ClassLoader t = classLoader;
  150. if (t == null) {
  151. t = getDefaultClassLoader();
  152. }
  153. if (t == null) {
  154. t = getClass().getClassLoader();
  155. }
  156. if (t == null) {
  157. t = Thread.currentThread().getContextClassLoader();
  158. }
  159. if (t == null) {
  160. throw new IllegalStateException("Cannot determine classloader");
  161. }
  162. return t;
  163. }
  164. abstract protected ClassLoader getDefaultClassLoader();
  165. protected Object create(Object key) {
  166. try {
  167. Class gen = null;
  168. synchronized (source) {
  169. ClassLoader loader = getClassLoader();
  170. Map cache2 = null;
  171. cache2 = (Map)source.cache.get(loader);
  172. if (cache2 == null) {
  173. cache2 = new HashMap();
  174. cache2.put(NAME_KEY, new HashSet());
  175. source.cache.put(loader, cache2);
  176. } else if (useCache) {
  177. Reference ref = (Reference)cache2.get(key);
  178. gen = (Class) (( ref == null ) ? null : ref.get());
  179. }
  180. if (gen == null) {
  181. Object save = CURRENT.get();
  182. CURRENT.set(this);
  183. try {
  184. this.key = key;
  185. if (attemptLoad) {
  186. try {
  187. gen = loader.loadClass(getClassName());
  188. } catch (ClassNotFoundException e) {
  189. // ignore
  190. }
  191. }
  192. if (gen == null) {
  193. byte[] b = strategy.generate(this);
  194. String className = ClassNameReader.getClassName(new ClassReader(b));
  195. getClassNameCache(loader).add(className);
  196. gen = ReflectUtils.defineClass(className, b, loader);
  197. }
  198. if (useCache) {
  199. cache2.put(key, new WeakReference(gen));
  200. }
  201. return firstInstance(gen);
  202. } finally {
  203. CURRENT.set(save);
  204. }
  205. }
  206. }
  207. return firstInstance(gen);
  208. } catch (RuntimeException e) {
  209. throw e;
  210. } catch (Error e) {
  211. throw e;
  212. } catch (Exception e) {
  213. throw new CodeGenerationException(e);
  214. }
  215. }
  216. abstract protected Object firstInstance(Class type) throws Exception;
  217. abstract protected Object nextInstance(Object instance) throws Exception;
  218. }