2 * Copyright 2003,2004 The Apache Software Foundation
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package net
.sf
.cglib
.core
;
18 import org
.objectweb
.asm
.ClassReader
;
20 import java
.lang
.ref
.Reference
;
21 import java
.lang
.ref
.WeakReference
;
25 * Abstract class for all code-generating CGLIB utilities.
26 * In addition to caching generated classes for performance, it provides hooks for
27 * customizing the <code>ClassLoader</code>, name of the generated class, and transformations
28 * applied before generation.
30 * intellij changes: made some fields final
32 abstract public class AbstractClassGenerator
33 implements ClassGenerator
35 private static final Object NAME_KEY
= new Object();
36 private static final ThreadLocal CURRENT
= new ThreadLocal();
38 private GeneratorStrategy strategy
= DefaultGeneratorStrategy
.INSTANCE
;
39 private NamingPolicy namingPolicy
= DefaultNamingPolicy
.INSTANCE
;
40 //change by Peter: make fields final
41 private final Source source
;
42 private ClassLoader classLoader
;
43 private String namePrefix
;
45 private boolean useCache
= true;
46 private String className
;
47 private boolean attemptLoad
;
49 protected static class Source
{
50 //change by Peter: made fields final
52 final Map cache
= new WeakHashMap();
53 public Source(String name
) {
58 protected AbstractClassGenerator(Source source
) {
62 protected void setNamePrefix(String namePrefix
) {
63 this.namePrefix
= namePrefix
;
66 final protected String
getClassName() {
67 if (className
== null)
68 className
= getClassName(getClassLoader());
72 private String
getClassName(final ClassLoader loader
) {
73 final Set nameCache
= getClassNameCache(loader
);
74 return namingPolicy
.getClassName(namePrefix
, source
.name
, key
, new Predicate() {
75 public boolean evaluate(Object arg
) {
76 return nameCache
.contains(arg
);
81 private Set
getClassNameCache(ClassLoader loader
) {
82 return (Set
)((Map
)source
.cache
.get(loader
)).get(NAME_KEY
);
86 * Set the <code>ClassLoader</code> in which the class will be generated.
87 * Concrete subclasses of <code>AbstractClassGenerator</code> (such as <code>Enhancer</code>)
88 * will try to choose an appropriate default if this is unset.
90 * Classes are cached per-<code>ClassLoader</code> using a <code>WeakHashMap</code>, to allow
91 * the generated classes to be removed when the associated loader is garbage collected.
92 * @param classLoader the loader to generate the new class with, or null to use the default
94 public void setClassLoader(ClassLoader classLoader
) {
95 this.classLoader
= classLoader
;
99 * Override the default naming policy.
100 * @see DefaultNamingPolicy
101 * @param namingPolicy the custom policy, or null to use the default
103 public void setNamingPolicy(NamingPolicy namingPolicy
) {
104 if (namingPolicy
== null)
105 namingPolicy
= DefaultNamingPolicy
.INSTANCE
;
106 this.namingPolicy
= namingPolicy
;
110 * @see #setNamingPolicy
112 public NamingPolicy
getNamingPolicy() {
117 * Whether use and update the static cache of generated classes
118 * for a class with the same properties. Default is <code>true</code>.
120 public void setUseCache(boolean useCache
) {
121 this.useCache
= useCache
;
127 public boolean getUseCache() {
132 * If set, CGLIB will attempt to load classes from the specified
133 * <code>ClassLoader</code> before generating them. Because generated
134 * class names are not guaranteed to be unique, the default is <code>false</code>.
136 public void setAttemptLoad(boolean attemptLoad
) {
137 this.attemptLoad
= attemptLoad
;
140 public boolean getAttemptLoad() {
145 * Set the strategy to use to create the bytecode from this generator.
146 * By default an instance of {@see DefaultGeneratorStrategy} is used.
148 public void setStrategy(GeneratorStrategy strategy
) {
149 if (strategy
== null)
150 strategy
= DefaultGeneratorStrategy
.INSTANCE
;
151 this.strategy
= strategy
;
157 public GeneratorStrategy
getStrategy() {
162 * Used internally by CGLIB. Returns the <code>AbstractClassGenerator</code>
163 * that is being used to generate a class in the current thread.
165 public static AbstractClassGenerator
getCurrent() {
166 return (AbstractClassGenerator
)CURRENT
.get();
169 public ClassLoader
getClassLoader() {
170 ClassLoader t
= classLoader
;
172 t
= getDefaultClassLoader();
175 t
= getClass().getClassLoader();
178 t
= Thread
.currentThread().getContextClassLoader();
181 throw new IllegalStateException("Cannot determine classloader");
186 abstract protected ClassLoader
getDefaultClassLoader();
188 protected Object
create(Object key
) {
192 synchronized (source
) {
193 ClassLoader loader
= getClassLoader();
195 cache2
= (Map
)source
.cache
.get(loader
);
196 if (cache2
== null) {
197 cache2
= new HashMap();
198 cache2
.put(NAME_KEY
, new HashSet());
199 source
.cache
.put(loader
, cache2
);
200 } else if (useCache
) {
201 Reference ref
= (Reference
)cache2
.get(key
);
202 gen
= (Class
) (( ref
== null ) ?
null : ref
.get());
205 Object save
= CURRENT
.get();
212 gen
= loader
.loadClass(getClassName());
213 } catch (ClassNotFoundException e
) {
218 byte[] b
= strategy
.generate(this);
219 String className
= ClassNameReader
.getClassName(new ClassReader(b
));
220 getClassNameCache(loader
).add(className
);
221 gen
= ReflectUtils
.defineClass(className
, b
, loader
);
225 cache2
.put(key
, new WeakReference(gen
));
227 return firstInstance(gen
);
233 return firstInstance(gen
);
234 } catch (RuntimeException e
) {
238 } catch (Exception e
) {
239 throw new CodeGenerationException(e
);
243 abstract protected Object
firstInstance(Class type
) throws Exception
;
244 abstract protected Object
nextInstance(Object instance
) throws Exception
;