Fixes to javassist.scopepooltags/rel_3_23_0_ga
package javassist.scopedpool; | package javassist.scopedpool; | ||||
import java.lang.ref.Reference; | |||||
import java.lang.ref.WeakReference; | import java.lang.ref.WeakReference; | ||||
import java.security.ProtectionDomain; | import java.security.ProtectionDomain; | ||||
import java.util.Iterator; | |||||
import java.util.Map; | import java.util.Map; | ||||
import javassist.CannotCompileException; | import javassist.CannotCompileException; | ||||
import javassist.ClassPool; | import javassist.ClassPool; | ||||
public class ScopedClassPool extends ClassPool { | public class ScopedClassPool extends ClassPool { | ||||
protected ScopedClassPoolRepository repository; | protected ScopedClassPoolRepository repository; | ||||
protected WeakReference classLoader; | |||||
protected Reference<ClassLoader> classLoader; | |||||
protected LoaderClassPath classPath; | protected LoaderClassPath classPath; | ||||
protected SoftValueHashMap softcache = new SoftValueHashMap(); | |||||
protected Map<String,CtClass> softcache = new SoftValueHashMap<String,CtClass>(); | |||||
boolean isBootstrapCl = true; | boolean isBootstrapCl = true; | ||||
* the original class pool | * the original class pool | ||||
* @param repository | * @param repository | ||||
* the repository | * the repository | ||||
*@deprecated | |||||
*/ | */ | ||||
protected ScopedClassPool(ClassLoader cl, ClassPool src, | protected ScopedClassPool(ClassLoader cl, ClassPool src, | ||||
ScopedClassPoolRepository repository) { | |||||
ScopedClassPoolRepository repository) | |||||
{ | |||||
this(cl, src, repository, false); | this(cl, src, repository, false); | ||||
} | } | ||||
* @param isTemp | * @param isTemp | ||||
* Whether this is a temporary pool used to resolve references | * Whether this is a temporary pool used to resolve references | ||||
*/ | */ | ||||
protected ScopedClassPool(ClassLoader cl, ClassPool src, ScopedClassPoolRepository repository, boolean isTemp) | |||||
protected ScopedClassPool(ClassLoader cl, ClassPool src, | |||||
ScopedClassPoolRepository repository, boolean isTemp) | |||||
{ | { | ||||
super(src); | super(src); | ||||
this.repository = repository; | this.repository = repository; | ||||
this.classLoader = new WeakReference(cl); | |||||
this.classLoader = new WeakReference<ClassLoader>(cl); | |||||
if (cl != null) { | if (cl != null) { | ||||
classPath = new LoaderClassPath(cl); | classPath = new LoaderClassPath(cl); | ||||
this.insertClassPath(classPath); | this.insertClassPath(classPath); | ||||
} | } | ||||
protected ClassLoader getClassLoader0() { | protected ClassLoader getClassLoader0() { | ||||
return (ClassLoader)classLoader.get(); | |||||
return classLoader.get(); | |||||
} | } | ||||
/** | /** | ||||
* the class name | * the class name | ||||
* @return the class | * @return the class | ||||
*/ | */ | ||||
@Override | |||||
protected CtClass getCached(String classname) { | protected CtClass getCached(String classname) { | ||||
CtClass clazz = getCachedLocally(classname); | CtClass clazz = getCachedLocally(classname); | ||||
if (clazz == null) { | if (clazz == null) { | ||||
} | } | ||||
if (!isLocal) { | if (!isLocal) { | ||||
Map registeredCLs = repository.getRegisteredCLs(); | |||||
Map<ClassLoader,ScopedClassPool> registeredCLs = repository.getRegisteredCLs(); | |||||
synchronized (registeredCLs) { | synchronized (registeredCLs) { | ||||
Iterator it = registeredCLs.values().iterator(); | |||||
while (it.hasNext()) { | |||||
ScopedClassPool pool = (ScopedClassPool)it.next(); | |||||
for (ScopedClassPool pool:registeredCLs.values()) { | |||||
if (pool.isUnloadedClassLoader()) { | if (pool.isUnloadedClassLoader()) { | ||||
repository.unregisterClassLoader(pool | repository.unregisterClassLoader(pool | ||||
.getClassLoader()); | .getClassLoader()); | ||||
* @throws CannotCompileException | * @throws CannotCompileException | ||||
* for any error | * for any error | ||||
*/ | */ | ||||
public Class toClass(CtClass ct, ClassLoader loader, ProtectionDomain domain) | |||||
public Class<?> toClass(CtClass ct, ClassLoader loader, ProtectionDomain domain) | |||||
throws CannotCompileException { | throws CannotCompileException { | ||||
// We need to pass up the classloader stored in this pool, as the | // We need to pass up the classloader stored in this pool, as the | ||||
// default implementation uses the Thread context cl. | // default implementation uses the Thread context cl. |
* | * | ||||
* @return the registered classloaders. | * @return the registered classloaders. | ||||
*/ | */ | ||||
Map getRegisteredCLs(); | |||||
Map<ClassLoader,ScopedClassPool> getRegisteredCLs(); | |||||
/** | /** | ||||
* This method will check to see if a register classloader has been | * This method will check to see if a register classloader has been |
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.Collections; | import java.util.Collections; | ||||
import java.util.Iterator; | |||||
import java.util.List; | |||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.WeakHashMap; | import java.util.WeakHashMap; | ||||
boolean pruneWhenCached; | boolean pruneWhenCached; | ||||
/** The registered classloaders */ | /** The registered classloaders */ | ||||
protected Map registeredCLs = Collections | |||||
.synchronizedMap(new WeakHashMap()); | |||||
protected Map<ClassLoader,ScopedClassPool> registeredCLs = Collections | |||||
.synchronizedMap(new WeakHashMap<ClassLoader,ScopedClassPool>()); | |||||
/** The default class pool */ | /** The default class pool */ | ||||
protected ClassPool classpool; | protected ClassPool classpool; | ||||
* | * | ||||
* @return the prune. | * @return the prune. | ||||
*/ | */ | ||||
@Override | |||||
public boolean isPrune() { | public boolean isPrune() { | ||||
return prune; | return prune; | ||||
} | } | ||||
* | * | ||||
* @param prune a new value. | * @param prune a new value. | ||||
*/ | */ | ||||
@Override | |||||
public void setPrune(boolean prune) { | public void setPrune(boolean prune) { | ||||
this.prune = prune; | this.prune = prune; | ||||
} | } | ||||
* @param src the original classpool. | * @param src the original classpool. | ||||
* @return the classpool | * @return the classpool | ||||
*/ | */ | ||||
@Override | |||||
public ScopedClassPool createScopedClassPool(ClassLoader cl, ClassPool src) { | public ScopedClassPool createScopedClassPool(ClassLoader cl, ClassPool src) { | ||||
return factory.create(cl, src, this); | return factory.create(cl, src, this); | ||||
} | } | ||||
@Override | |||||
public ClassPool findClassPool(ClassLoader cl) { | public ClassPool findClassPool(ClassLoader cl) { | ||||
if (cl == null) | if (cl == null) | ||||
return registerClassLoader(ClassLoader.getSystemClassLoader()); | return registerClassLoader(ClassLoader.getSystemClassLoader()); | ||||
* @param ucl the classloader. | * @param ucl the classloader. | ||||
* @return the classpool | * @return the classpool | ||||
*/ | */ | ||||
@Override | |||||
public ClassPool registerClassLoader(ClassLoader ucl) { | public ClassPool registerClassLoader(ClassLoader ucl) { | ||||
synchronized (registeredCLs) { | synchronized (registeredCLs) { | ||||
// FIXME: Probably want to take this method out later | // FIXME: Probably want to take this method out later | ||||
// a | // a | ||||
// ClassPool.classpath | // ClassPool.classpath | ||||
if (registeredCLs.containsKey(ucl)) { | if (registeredCLs.containsKey(ucl)) { | ||||
return (ClassPool)registeredCLs.get(ucl); | |||||
return registeredCLs.get(ucl); | |||||
} | } | ||||
ScopedClassPool pool = createScopedClassPool(ucl, classpool); | ScopedClassPool pool = createScopedClassPool(ucl, classpool); | ||||
registeredCLs.put(ucl, pool); | registeredCLs.put(ucl, pool); | ||||
/** | /** | ||||
* Get the registered classloaders. | * Get the registered classloaders. | ||||
*/ | */ | ||||
public Map getRegisteredCLs() { | |||||
@Override | |||||
public Map<ClassLoader,ScopedClassPool> getRegisteredCLs() { | |||||
clearUnregisteredClassLoaders(); | clearUnregisteredClassLoaders(); | ||||
return registeredCLs; | return registeredCLs; | ||||
} | } | ||||
* This method will check to see if a register classloader has been | * This method will check to see if a register classloader has been | ||||
* undeployed (as in JBoss) | * undeployed (as in JBoss) | ||||
*/ | */ | ||||
@Override | |||||
public void clearUnregisteredClassLoaders() { | public void clearUnregisteredClassLoaders() { | ||||
ArrayList toUnregister = null; | |||||
List<ClassLoader> toUnregister = null; | |||||
synchronized (registeredCLs) { | synchronized (registeredCLs) { | ||||
Iterator it = registeredCLs.values().iterator(); | |||||
while (it.hasNext()) { | |||||
ScopedClassPool pool = (ScopedClassPool)it.next(); | |||||
if (pool.isUnloadedClassLoader()) { | |||||
it.remove(); | |||||
ClassLoader cl = pool.getClassLoader(); | |||||
for (Map.Entry<ClassLoader,ScopedClassPool> reg:registeredCLs.entrySet()) { | |||||
if (reg.getValue().isUnloadedClassLoader()) { | |||||
ClassLoader cl = reg.getValue().getClassLoader(); | |||||
if (cl != null) { | if (cl != null) { | ||||
if (toUnregister == null) { | |||||
toUnregister = new ArrayList(); | |||||
} | |||||
if (toUnregister == null) | |||||
toUnregister = new ArrayList<ClassLoader>(); | |||||
toUnregister.add(cl); | toUnregister.add(cl); | ||||
} | } | ||||
registeredCLs.remove(reg.getKey()); | |||||
} | } | ||||
} | } | ||||
if (toUnregister != null) { | |||||
for (int i = 0; i < toUnregister.size(); i++) { | |||||
unregisterClassLoader((ClassLoader)toUnregister.get(i)); | |||||
} | |||||
} | |||||
if (toUnregister != null) | |||||
for (ClassLoader cl:toUnregister) | |||||
unregisterClassLoader(cl); | |||||
} | } | ||||
} | } | ||||
@Override | |||||
public void unregisterClassLoader(ClassLoader cl) { | public void unregisterClassLoader(ClassLoader cl) { | ||||
synchronized (registeredCLs) { | synchronized (registeredCLs) { | ||||
ScopedClassPool pool = (ScopedClassPool)registeredCLs.remove(cl); | |||||
ScopedClassPool pool = registeredCLs.remove(cl); | |||||
if (pool != null) | if (pool != null) | ||||
pool.close(); | pool.close(); | ||||
} | } | ||||
// Noop - this is the end | // Noop - this is the end | ||||
} | } | ||||
@Override | |||||
public void setClassPoolFactory(ScopedClassPoolFactory factory) { | public void setClassPoolFactory(ScopedClassPoolFactory factory) { | ||||
this.factory = factory; | this.factory = factory; | ||||
} | } | ||||
@Override | |||||
public ScopedClassPoolFactory getClassPoolFactory() { | public ScopedClassPoolFactory getClassPoolFactory() { | ||||
return factory; | return factory; | ||||
} | } |
import java.lang.ref.ReferenceQueue; | import java.lang.ref.ReferenceQueue; | ||||
import java.lang.ref.SoftReference; | import java.lang.ref.SoftReference; | ||||
import java.util.AbstractMap; | |||||
import java.util.HashMap; | |||||
import java.util.AbstractMap.SimpleImmutableEntry; | |||||
import java.util.ArrayList; | |||||
import java.util.Collection; | |||||
import java.util.HashSet; | |||||
import java.util.List; | |||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Set; | import java.util.Set; | ||||
import java.util.concurrent.ConcurrentHashMap; | |||||
/** | /** | ||||
* This Map will remove entries when the value in the map has been cleaned from | * This Map will remove entries when the value in the map has been cleaned from | ||||
* @version <tt>$Revision: 1.4 $</tt> | * @version <tt>$Revision: 1.4 $</tt> | ||||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> | * @author <a href="mailto:bill@jboss.org">Bill Burke</a> | ||||
*/ | */ | ||||
public class SoftValueHashMap extends AbstractMap implements Map { | |||||
private static class SoftValueRef extends SoftReference { | |||||
public Object key; | |||||
public class SoftValueHashMap<K,V> implements Map<K,V> { | |||||
private static class SoftValueRef<K,V> extends SoftReference<V> { | |||||
public K key; | |||||
private SoftValueRef(Object key, Object val, ReferenceQueue q) { | |||||
private SoftValueRef(K key, V val, ReferenceQueue<V> q) { | |||||
super(val, q); | super(val, q); | ||||
this.key = key; | this.key = key; | ||||
} | } | ||||
private static SoftValueRef create(Object key, Object val, | |||||
ReferenceQueue q) { | |||||
private static <K,V> SoftValueRef<K,V> create( | |||||
K key, V val, ReferenceQueue<V> q) { | |||||
if (val == null) | if (val == null) | ||||
return null; | return null; | ||||
else | else | ||||
return new SoftValueRef(key, val, q); | |||||
return new SoftValueRef<K,V>(key, val, q); | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Returns a set of the mappings contained in this hash table. | * Returns a set of the mappings contained in this hash table. | ||||
*/ | */ | ||||
public Set entrySet() { | |||||
@Override | |||||
public Set<Map.Entry<K, V>> entrySet() { | |||||
processQueue(); | processQueue(); | ||||
return hash.entrySet(); | |||||
Set<Entry<K,V>> ret = new HashSet<Entry<K,V>>(); | |||||
for (Entry<K,SoftValueRef<K,V>> e:hash.entrySet()) | |||||
ret.add(new SimpleImmutableEntry<K,V> ( | |||||
e.getKey(), e.getValue().get())); | |||||
return ret; | |||||
} | } | ||||
/* Hash table mapping WeakKeys to values */ | /* Hash table mapping WeakKeys to values */ | ||||
private Map hash; | |||||
private Map<K,SoftValueRef<K,V>> hash; | |||||
/* Reference queue for cleared WeakKeys */ | /* Reference queue for cleared WeakKeys */ | ||||
private ReferenceQueue queue = new ReferenceQueue(); | |||||
private ReferenceQueue<V> queue = new ReferenceQueue<V>(); | |||||
/* | /* | ||||
* Remove all invalidated entries from the map, that is, remove all entries | * Remove all invalidated entries from the map, that is, remove all entries | ||||
* whose values have been discarded. | * whose values have been discarded. | ||||
*/ | */ | ||||
private void processQueue() { | private void processQueue() { | ||||
SoftValueRef ref; | |||||
while ((ref = (SoftValueRef)queue.poll()) != null) { | |||||
if (ref == (SoftValueRef)hash.get(ref.key)) { | |||||
// only remove if it is the *exact* same WeakValueRef | |||||
// | |||||
hash.remove(ref.key); | |||||
Object ref; | |||||
if (!hash.isEmpty()) | |||||
while ((ref = queue.poll()) != null) | |||||
if (ref instanceof SoftValueRef) { | |||||
@SuppressWarnings("rawtypes") | |||||
SoftValueRef que =(SoftValueRef) ref; | |||||
if (ref == hash.get(que.key)) | |||||
// only remove if it is the *exact* same SoftValueRef | |||||
hash.remove(que.key); | |||||
} | } | ||||
} | |||||
} | } | ||||
/* -- Constructors -- */ | /* -- Constructors -- */ | ||||
* factor is nonpositive | * factor is nonpositive | ||||
*/ | */ | ||||
public SoftValueHashMap(int initialCapacity, float loadFactor) { | public SoftValueHashMap(int initialCapacity, float loadFactor) { | ||||
hash = new HashMap(initialCapacity, loadFactor); | |||||
hash = new ConcurrentHashMap<K,SoftValueRef<K,V>>(initialCapacity, loadFactor); | |||||
} | } | ||||
/** | /** | ||||
* If the initial capacity is less than zero | * If the initial capacity is less than zero | ||||
*/ | */ | ||||
public SoftValueHashMap(int initialCapacity) { | public SoftValueHashMap(int initialCapacity) { | ||||
hash = new HashMap(initialCapacity); | |||||
hash = new ConcurrentHashMap<K,SoftValueRef<K,V>>(initialCapacity); | |||||
} | } | ||||
/** | /** | ||||
* initial capacity and the default load factor, which is <code>0.75</code>. | * initial capacity and the default load factor, which is <code>0.75</code>. | ||||
*/ | */ | ||||
public SoftValueHashMap() { | public SoftValueHashMap() { | ||||
hash = new HashMap(); | |||||
hash = new ConcurrentHashMap<K,SoftValueRef<K,V>>(); | |||||
} | } | ||||
/** | /** | ||||
* | * | ||||
* @param t the map whose mappings are to be placed in this map. | * @param t the map whose mappings are to be placed in this map. | ||||
*/ | */ | ||||
public SoftValueHashMap(Map t) { | |||||
public SoftValueHashMap(Map<K,V> t) { | |||||
this(Math.max(2 * t.size(), 11), 0.75f); | this(Math.max(2 * t.size(), 11), 0.75f); | ||||
putAll(t); | putAll(t); | ||||
} | } | ||||
* <code>Map</code> interface, the time required by this operation is | * <code>Map</code> interface, the time required by this operation is | ||||
* linear in the size of the map.</em> | * linear in the size of the map.</em> | ||||
*/ | */ | ||||
@Override | |||||
public int size() { | public int size() { | ||||
processQueue(); | processQueue(); | ||||
return hash.size(); | return hash.size(); | ||||
/** | /** | ||||
* Returns <code>true</code> if this map contains no key-value mappings. | * Returns <code>true</code> if this map contains no key-value mappings. | ||||
*/ | */ | ||||
@Override | |||||
public boolean isEmpty() { | public boolean isEmpty() { | ||||
processQueue(); | processQueue(); | ||||
return hash.isEmpty(); | return hash.isEmpty(); | ||||
* @param key | * @param key | ||||
* The key whose presence in this map is to be tested. | * The key whose presence in this map is to be tested. | ||||
*/ | */ | ||||
@Override | |||||
public boolean containsKey(Object key) { | public boolean containsKey(Object key) { | ||||
processQueue(); | processQueue(); | ||||
return hash.containsKey(key); | return hash.containsKey(key); | ||||
* @param key | * @param key | ||||
* The key whose associated value, if any, is to be returned. | * The key whose associated value, if any, is to be returned. | ||||
*/ | */ | ||||
public Object get(Object key) { | |||||
@Override | |||||
public V get(Object key) { | |||||
processQueue(); | processQueue(); | ||||
SoftReference ref = (SoftReference)hash.get(key); | |||||
if (ref != null) | |||||
return ref.get(); | |||||
return null; | |||||
return valueOrNull(hash.get(key)); | |||||
} | } | ||||
/** | /** | ||||
* @return The previous value to which this key was mapped, or | * @return The previous value to which this key was mapped, or | ||||
* <code>null</code> if if there was no mapping for the key | * <code>null</code> if if there was no mapping for the key | ||||
*/ | */ | ||||
public Object put(Object key, Object value) { | |||||
@Override | |||||
public V put(K key, V value) { | |||||
processQueue(); | processQueue(); | ||||
Object rtn = hash.put(key, SoftValueRef.create(key, value, queue)); | |||||
if (rtn != null) | |||||
rtn = ((SoftReference)rtn).get(); | |||||
return rtn; | |||||
return valueOrNull(hash.put(key, SoftValueRef.create(key, value, queue))); | |||||
} | } | ||||
/** | /** | ||||
* @return The value to which this key was mapped, or <code>null</code> if | * @return The value to which this key was mapped, or <code>null</code> if | ||||
* there was no mapping for the key. | * there was no mapping for the key. | ||||
*/ | */ | ||||
public Object remove(Object key) { | |||||
@Override | |||||
public V remove(Object key) { | |||||
processQueue(); | processQueue(); | ||||
return hash.remove(key); | |||||
return valueOrNull(hash.remove(key)); | |||||
} | } | ||||
/** | /** | ||||
* Removes all mappings from this map. | * Removes all mappings from this map. | ||||
*/ | */ | ||||
@Override | |||||
public void clear() { | public void clear() { | ||||
processQueue(); | processQueue(); | ||||
hash.clear(); | hash.clear(); | ||||
} | } | ||||
/* | |||||
* Check whether the supplied value exists. | |||||
* @param Object the value to compare. | |||||
* @return true if it was found or null. | |||||
*/ | |||||
@Override | |||||
public boolean containsValue(Object arg0) { | |||||
processQueue(); | |||||
if (null == arg0) | |||||
return false; | |||||
for (SoftValueRef<K,V> e:hash.values()) | |||||
if (null != e && arg0.equals(e.get())) | |||||
return true; | |||||
return false; | |||||
} | |||||
/* {@inheritDoc} */ | |||||
@Override | |||||
public Set<K> keySet() { | |||||
processQueue(); | |||||
return hash.keySet(); | |||||
} | |||||
/* {@inheritDoc} */ | |||||
@Override | |||||
public void putAll(Map<? extends K,? extends V> arg0) { | |||||
processQueue(); | |||||
for (K key:arg0.keySet()) | |||||
put(key, arg0.get(key)); | |||||
} | |||||
/* {@inheritDoc} */ | |||||
@Override | |||||
public Collection<V> values() { | |||||
processQueue(); | |||||
List<V> ret = new ArrayList<V>(); | |||||
for (SoftValueRef<K,V> e:hash.values()) | |||||
ret.add(e.get()); | |||||
return ret; | |||||
} | |||||
private V valueOrNull(SoftValueRef<K,V> rtn) { | |||||
if (null == rtn) | |||||
return null; | |||||
return rtn.get(); | |||||
} | |||||
} | } |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later, | |||||
* or the Apache License Version 2.0. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package scoped; | |||||
import java.io.File; | |||||
import java.lang.reflect.Method; | |||||
import java.math.BigDecimal; | |||||
import java.net.URL; | |||||
import java.net.URLClassLoader; | |||||
import java.util.Arrays; | |||||
import java.util.Map; | |||||
import java.util.stream.LongStream; | |||||
import javassist.ClassPool; | |||||
import javassist.CtClass; | |||||
import javassist.CtConstructor; | |||||
import javassist.CtField; | |||||
import javassist.CtMethod; | |||||
import javassist.scopedpool.ScopedClassPool; | |||||
import javassist.scopedpool.ScopedClassPoolRepository; | |||||
import javassist.scopedpool.ScopedClassPoolRepositoryImpl; | |||||
import javassist.scopedpool.SoftValueHashMap; | |||||
import junit.framework.TestCase; | |||||
/** | |||||
* ScopedRepositoryTest. | |||||
* | |||||
* @author <a href="adrian@jboss.com">Adrian Brock</a> | |||||
* @version $Revision$ | |||||
*/ | |||||
public class ScopedRepositoryTestCase extends TestCase | |||||
{ | |||||
private static final ScopedClassPoolRepository repository = ScopedClassPoolRepositoryImpl.getInstance(); | |||||
public void testJDKClasses() throws Exception | |||||
{ | |||||
ClassPool poolClass = repository.findClassPool(Class.class.getClassLoader()); | |||||
assertNotNull(poolClass); | |||||
ClassPool poolString = repository.findClassPool(String.class.getClassLoader()); | |||||
assertNotNull(poolString); | |||||
assertEquals(poolClass, poolString); | |||||
} | |||||
public void testScopedClasses() throws Exception | |||||
{ | |||||
ClassLoader cl = getURLClassLoader("test-classes14-jar1"); | |||||
ClassPool pool1 = repository.findClassPool(cl); | |||||
CtClass clazz = pool1.get("scoped.jar1.TestClass1"); | |||||
assertNotNull(clazz); | |||||
ClassPool poolClass = repository.findClassPool(Class.class.getClassLoader()); | |||||
assertNotNull(poolClass); | |||||
assertNotSame(pool1, poolClass); | |||||
} | |||||
public void testUnscopedAnnotationUsage() throws Exception | |||||
{ | |||||
CtClass clazz = getCtClass(UnscopedAnnotationUsage.class); | |||||
checkTestAnnotation(clazz, "notDefault"); | |||||
} | |||||
public void testUnscopedAnnotationDefaultUsage() throws Exception | |||||
{ | |||||
CtClass clazz = getCtClass(UnscopedAnnotationDefaultUsage.class); | |||||
checkTestAnnotation(clazz, "defaultValue"); | |||||
} | |||||
public void testScopedAnnotationUsage() throws Exception | |||||
{ | |||||
ClassLoader cl = getURLClassLoader("test-classes14-jar1"); | |||||
CtClass clazz = getCtClass("scoped.jar1.ScopedAnnotationUsage", cl); | |||||
checkTestAnnotation(clazz, "notDefault"); | |||||
} | |||||
public void testScopedAnnotationDefaultUsage() throws Exception | |||||
{ | |||||
ClassLoader cl = getURLClassLoader("test-classes14-jar1"); | |||||
CtClass clazz = getCtClass("scoped.jar1.ScopedAnnotationDefaultUsage", cl); | |||||
checkTestAnnotation(clazz, "defaultValue"); | |||||
} | |||||
public void testFullyScopedAnnotationUsage() throws Exception | |||||
{ | |||||
ClassLoader cl = getURLClassLoader("test-classes14-jar1"); | |||||
CtClass clazz = getCtClass("scoped.jar1.FullyScopedAnnotationUsage", cl); | |||||
checkScopedAnnotation(cl, clazz, "notDefault"); | |||||
} | |||||
public void testFullyScopedAnnotationDefaultUsage() throws Exception | |||||
{ | |||||
ClassLoader cl = getURLClassLoader("test-classes14-jar1"); | |||||
CtClass clazz = getCtClass("scoped.jar1.FullyScopedAnnotationDefaultUsage", cl); | |||||
checkScopedAnnotation(cl, clazz, "defaultValue"); | |||||
} | |||||
public void testSoftValueHashMap() throws Exception { | |||||
Map<String,Class<?>> map = new SoftValueHashMap<>(); | |||||
Class<?> cls = this.getClass(); | |||||
assertTrue(map.put(cls.getName(), cls) == null); | |||||
assertTrue(map.put(cls.getName(), cls) == cls); | |||||
assertTrue(map.size() == 1); | |||||
assertTrue(map.get(cls.getName()) == cls); | |||||
assertTrue(map.values().iterator().next() == cls); | |||||
assertTrue(map.entrySet().iterator().next().getValue() == cls); | |||||
assertTrue(map.containsValue(cls)); | |||||
assertTrue(map.remove(cls.getName()) == cls); | |||||
assertTrue(map.size() == 0); | |||||
} | |||||
public void testSoftCache() throws Exception { | |||||
// Overload the heap to test that the map auto cleans | |||||
Map<String,long[]> map = new SoftValueHashMap<>(); | |||||
// 12+8*30000000 = +- 252 MB | |||||
long[] data = LongStream.range(0, 30000000).toArray(); | |||||
int current = map.size(); | |||||
while (current <= map.size()) { | |||||
current = map.size(); | |||||
for (int ii = 0; ii < 5; ii++) { | |||||
map.put(current+"-"+ii, Arrays.copyOf(data, data.length)); | |||||
} | |||||
} | |||||
assertTrue(current > map.size()); | |||||
} | |||||
protected CtClass getCtClass(Class<?> clazz) throws Exception | |||||
{ | |||||
return getCtClass(clazz.getName(), clazz.getClassLoader()); | |||||
} | |||||
protected CtClass getCtClass(String name, ClassLoader cl) throws Exception | |||||
{ | |||||
ClassPool pool = repository.findClassPool(cl); | |||||
assertNotNull(pool); | |||||
CtClass clazz = pool.get(name); | |||||
assertNotNull(clazz); | |||||
return clazz; | |||||
} | |||||
protected void checkTestAnnotation(CtClass ctClass, String value) throws Exception | |||||
{ | |||||
checkTestAnnotation(ctClass.getAnnotations(), value); | |||||
checkTestAnnotation(getFieldAnnotations(ctClass), value); | |||||
checkTestAnnotation(getConstructorAnnotations(ctClass), value); | |||||
checkTestAnnotation(getConstructorParameterAnnotations(ctClass), value); | |||||
checkTestAnnotation(getMethodAnnotations(ctClass), value); | |||||
checkTestAnnotation(getMethodParameterAnnotations(ctClass), value); | |||||
} | |||||
protected void checkTestAnnotation(Object[] annotations, String value) throws Exception | |||||
{ | |||||
assertNotNull(annotations); | |||||
assertEquals(1, annotations.length); | |||||
assertNotNull(annotations[0]); | |||||
assertTrue(annotations[0] instanceof TestAnnotation); | |||||
TestAnnotation annotation = (TestAnnotation) annotations[0]; | |||||
assertEquals(value, annotation.something()); | |||||
} | |||||
protected void checkScopedAnnotation(ClassLoader cl, CtClass ctClass, String value) throws Exception | |||||
{ | |||||
Class<?> annotationClass = cl.loadClass("scoped.jar1.ScopedTestAnnotation"); | |||||
checkScopedAnnotation(annotationClass, ctClass.getAnnotations(), value); | |||||
checkScopedAnnotation(annotationClass, getFieldAnnotations(ctClass), value); | |||||
checkScopedAnnotation(annotationClass, getConstructorAnnotations(ctClass), value); | |||||
checkScopedAnnotation(annotationClass, getConstructorParameterAnnotations(ctClass), value); | |||||
checkScopedAnnotation(annotationClass, getMethodAnnotations(ctClass), value); | |||||
checkScopedAnnotation(annotationClass, getMethodParameterAnnotations(ctClass), value); | |||||
} | |||||
protected void checkScopedAnnotation(Class<?> annotationClass, Object[] annotations, String value) throws Exception | |||||
{ | |||||
assertNotNull(annotations); | |||||
assertEquals(1, annotations.length); | |||||
assertNotNull(annotations[0]); | |||||
assertTrue(annotationClass.isInstance(annotations[0])); | |||||
Method method = annotationClass.getMethod("something", new Class<?>[0]); | |||||
assertEquals(value, method.invoke(annotations[0], (Object[]) null)); | |||||
} | |||||
protected Object[] getFieldAnnotations(CtClass clazz) throws Exception | |||||
{ | |||||
CtField field = clazz.getField("aField"); | |||||
assertNotNull(field); | |||||
return field.getAnnotations(); | |||||
} | |||||
protected Object[] getMethodAnnotations(CtClass clazz) throws Exception | |||||
{ | |||||
CtMethod method = clazz.getMethod("doSomething", "(I)V"); | |||||
assertNotNull(method); | |||||
return method.getAnnotations(); | |||||
} | |||||
protected Object[] getMethodParameterAnnotations(CtClass clazz) throws Exception | |||||
{ | |||||
CtMethod method = clazz.getMethod("doSomething", "(I)V"); | |||||
assertNotNull(method); | |||||
Object[] paramAnnotations = method.getParameterAnnotations(); | |||||
assertNotNull(paramAnnotations); | |||||
assertEquals(1, paramAnnotations.length); | |||||
return (Object[]) paramAnnotations[0]; | |||||
} | |||||
protected Object[] getConstructorAnnotations(CtClass clazz) throws Exception | |||||
{ | |||||
CtConstructor constructor = clazz.getConstructor("(I)V"); | |||||
assertNotNull(constructor); | |||||
return constructor.getAnnotations(); | |||||
} | |||||
protected Object[] getConstructorParameterAnnotations(CtClass clazz) throws Exception | |||||
{ | |||||
CtConstructor constructor = clazz.getConstructor("(I)V"); | |||||
assertNotNull(constructor); | |||||
Object[] paramAnnotations = constructor.getParameterAnnotations(); | |||||
assertNotNull(paramAnnotations); | |||||
assertEquals(1, paramAnnotations.length); | |||||
return (Object[]) paramAnnotations[0]; | |||||
} | |||||
protected ClassLoader getURLClassLoader(String context) throws Exception | |||||
{ | |||||
String output = "."; | |||||
File file = new File(output + File.separator + context); | |||||
URL url = file.toURI().toURL(); | |||||
return new URLClassLoader(new URL[] { url }); | |||||
} | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later, | |||||
* or the Apache License Version 2.0. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package scoped; | |||||
import java.lang.annotation.ElementType; | |||||
import java.lang.annotation.Retention; | |||||
import java.lang.annotation.RetentionPolicy; | |||||
import java.lang.annotation.Target; | |||||
/** | |||||
* TestAnnotation. | |||||
* | |||||
* @author <a href="adrian@jboss.com">Adrian Brock</a> | |||||
* @version $Revision$ | |||||
*/ | |||||
@Retention(value = RetentionPolicy.RUNTIME) | |||||
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.CONSTRUCTOR }) | |||||
public @interface TestAnnotation | |||||
{ | |||||
String something() default "defaultValue"; | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later, | |||||
* or the Apache License Version 2.0. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package scoped; | |||||
@TestAnnotation | |||||
public class UnscopedAnnotationDefaultUsage | |||||
{ | |||||
@TestAnnotation | |||||
public int aField; | |||||
@TestAnnotation | |||||
public UnscopedAnnotationDefaultUsage(@TestAnnotation int param) {} | |||||
@TestAnnotation | |||||
public void doSomething(@TestAnnotation int param) {} | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later, | |||||
* or the Apache License Version 2.0. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package scoped; | |||||
@TestAnnotation(something="notDefault") | |||||
public class UnscopedAnnotationUsage | |||||
{ | |||||
@TestAnnotation(something="notDefault") | |||||
public int aField; | |||||
@TestAnnotation(something="notDefault") | |||||
public UnscopedAnnotationUsage(@TestAnnotation(something="notDefault") int param) {} | |||||
@TestAnnotation(something="notDefault") | |||||
public void doSomething(@TestAnnotation(something="notDefault") int param) {} | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later, | |||||
* or the Apache License Version 2.0. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package scoped.jar1; | |||||
@ScopedTestAnnotation | |||||
public class FullyScopedAnnotationDefaultUsage | |||||
{ | |||||
@ScopedTestAnnotation | |||||
public int aField; | |||||
@ScopedTestAnnotation | |||||
public FullyScopedAnnotationDefaultUsage(@ScopedTestAnnotation int value) {} | |||||
@ScopedTestAnnotation | |||||
public void doSomething(@ScopedTestAnnotation int value) {} | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later, | |||||
* or the Apache License Version 2.0. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package scoped.jar1; | |||||
@ScopedTestAnnotation(something="notDefault") | |||||
public class FullyScopedAnnotationUsage | |||||
{ | |||||
@ScopedTestAnnotation(something="notDefault") | |||||
public int aField; | |||||
@ScopedTestAnnotation(something="notDefault") | |||||
public FullyScopedAnnotationUsage(@ScopedTestAnnotation(something="notDefault") int param) {} | |||||
@ScopedTestAnnotation(something="notDefault") | |||||
public void doSomething(@ScopedTestAnnotation(something="notDefault") int param) {} | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later, | |||||
* or the Apache License Version 2.0. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package scoped.jar1; | |||||
import scoped.TestAnnotation; | |||||
@TestAnnotation | |||||
public class ScopedAnnotationDefaultUsage | |||||
{ | |||||
@TestAnnotation | |||||
public int aField; | |||||
@TestAnnotation | |||||
public ScopedAnnotationDefaultUsage(@TestAnnotation int param) {} | |||||
@TestAnnotation | |||||
public void doSomething(@TestAnnotation int param) {} | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later, | |||||
* or the Apache License Version 2.0. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package scoped.jar1; | |||||
import scoped.TestAnnotation; | |||||
@TestAnnotation(something="notDefault") | |||||
public class ScopedAnnotationUsage | |||||
{ | |||||
@TestAnnotation(something="notDefault") | |||||
public int aField; | |||||
@TestAnnotation(something="notDefault") | |||||
public ScopedAnnotationUsage(@TestAnnotation(something="notDefault") int param) {} | |||||
@TestAnnotation(something="notDefault") | |||||
public void doSomething(@TestAnnotation(something="notDefault") int param) {} | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later, | |||||
* or the Apache License Version 2.0. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package scoped.jar1; | |||||
import java.lang.annotation.ElementType; | |||||
import java.lang.annotation.Retention; | |||||
import java.lang.annotation.RetentionPolicy; | |||||
import java.lang.annotation.Target; | |||||
/** | |||||
* TestAnnotation. | |||||
* | |||||
* @author <a href="adrian@jboss.com">Adrian Brock</a> | |||||
* @version $Revision$ | |||||
*/ | |||||
@Retention(value = RetentionPolicy.RUNTIME) | |||||
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.CONSTRUCTOR }) | |||||
public @interface ScopedTestAnnotation | |||||
{ | |||||
String something() default "defaultValue"; | |||||
} |
/* | |||||
* Javassist, a Java-bytecode translator toolkit. | |||||
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. | |||||
* | |||||
* The contents of this file are subject to the Mozilla Public License Version | |||||
* 1.1 (the "License"); you may not use this file except in compliance with | |||||
* the License. Alternatively, the contents of this file may be used under | |||||
* the terms of the GNU Lesser General Public License Version 2.1 or later, | |||||
* or the Apache License Version 2.0. | |||||
* | |||||
* Software distributed under the License is distributed on an "AS IS" basis, | |||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |||||
* for the specific language governing rights and limitations under the | |||||
* License. | |||||
*/ | |||||
package scoped.jar1; | |||||
/** | |||||
* TestClass1. | |||||
* | |||||
* @author <a href="adrian@jboss.com">Adrian Brock</a> | |||||
* @version $Revision$ | |||||
*/ | |||||
public class TestClass1 | |||||
{ | |||||
} |