aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorShigeru Chiba <chibash@users.noreply.github.com>2017-11-15 00:06:52 +0900
committerGitHub <noreply@github.com>2017-11-15 00:06:52 +0900
commitb7e59d4dc0222d34732c8efd87872b562501e14b (patch)
treef41f98b560cea64a496a3353fe4f369283c1a32a /src
parentc4e194994f5d07cab64b54754fcee884d9287949 (diff)
parent53325f5637042322f1b810ad32c8ee3bad2915f4 (diff)
downloadjavassist-b7e59d4dc0222d34732c8efd87872b562501e14b.tar.gz
javassist-b7e59d4dc0222d34732c8efd87872b562501e14b.zip
Merge pull request #159 from nickl-/scoped-pool
Fixes to javassist.scopepool
Diffstat (limited to 'src')
-rw-r--r--src/main/javassist/scopedpool/ScopedClassPool.java26
-rw-r--r--src/main/javassist/scopedpool/ScopedClassPoolRepository.java2
-rw-r--r--src/main/javassist/scopedpool/ScopedClassPoolRepositoryImpl.java47
-rw-r--r--src/main/javassist/scopedpool/SoftValueHashMap.java132
-rw-r--r--src/test/scoped/ScopedRepositoryTestCase.java242
-rw-r--r--src/test/scoped/TestAnnotation.java34
-rw-r--r--src/test/scoped/UnscopedAnnotationDefaultUsage.java29
-rw-r--r--src/test/scoped/UnscopedAnnotationUsage.java29
-rw-r--r--src/test/scoped/jar1/FullyScopedAnnotationDefaultUsage.java29
-rw-r--r--src/test/scoped/jar1/FullyScopedAnnotationUsage.java29
-rw-r--r--src/test/scoped/jar1/ScopedAnnotationDefaultUsage.java31
-rw-r--r--src/test/scoped/jar1/ScopedAnnotationUsage.java31
-rw-r--r--src/test/scoped/jar1/ScopedTestAnnotation.java34
-rw-r--r--src/test/scoped/jar1/TestClass1.java26
14 files changed, 650 insertions, 71 deletions
diff --git a/src/main/javassist/scopedpool/ScopedClassPool.java b/src/main/javassist/scopedpool/ScopedClassPool.java
index bcda0ded..fb87709d 100644
--- a/src/main/javassist/scopedpool/ScopedClassPool.java
+++ b/src/main/javassist/scopedpool/ScopedClassPool.java
@@ -16,9 +16,9 @@
package javassist.scopedpool;
+import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.security.ProtectionDomain;
-import java.util.Iterator;
import java.util.Map;
import javassist.CannotCompileException;
import javassist.ClassPool;
@@ -37,11 +37,11 @@ import javassist.NotFoundException;
public class ScopedClassPool extends ClassPool {
protected ScopedClassPoolRepository repository;
- protected WeakReference classLoader;
+ protected Reference<ClassLoader> classLoader;
protected LoaderClassPath classPath;
- protected SoftValueHashMap softcache = new SoftValueHashMap();
+ protected Map<String,CtClass> softcache = new SoftValueHashMap<String,CtClass>();
boolean isBootstrapCl = true;
@@ -59,10 +59,10 @@ public class ScopedClassPool extends ClassPool {
* the original class pool
* @param repository
* the repository
- *@deprecated
*/
protected ScopedClassPool(ClassLoader cl, ClassPool src,
- ScopedClassPoolRepository repository) {
+ ScopedClassPoolRepository repository)
+ {
this(cl, src, repository, false);
}
@@ -78,11 +78,12 @@ public class ScopedClassPool extends ClassPool {
* @param isTemp
* 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);
this.repository = repository;
- this.classLoader = new WeakReference(cl);
+ this.classLoader = new WeakReference<ClassLoader>(cl);
if (cl != null) {
classPath = new LoaderClassPath(cl);
this.insertClassPath(classPath);
@@ -110,7 +111,7 @@ public class ScopedClassPool extends ClassPool {
}
protected ClassLoader getClassLoader0() {
- return (ClassLoader)classLoader.get();
+ return classLoader.get();
}
/**
@@ -163,6 +164,7 @@ public class ScopedClassPool extends ClassPool {
* the class name
* @return the class
*/
+ @Override
protected CtClass getCached(String classname) {
CtClass clazz = getCachedLocally(classname);
if (clazz == null) {
@@ -186,11 +188,9 @@ public class ScopedClassPool extends ClassPool {
}
if (!isLocal) {
- Map registeredCLs = repository.getRegisteredCLs();
+ Map<ClassLoader,ScopedClassPool> registeredCLs = repository.getRegisteredCLs();
synchronized (registeredCLs) {
- Iterator it = registeredCLs.values().iterator();
- while (it.hasNext()) {
- ScopedClassPool pool = (ScopedClassPool)it.next();
+ for (ScopedClassPool pool:registeredCLs.values()) {
if (pool.isUnloadedClassLoader()) {
repository.unregisterClassLoader(pool
.getClassLoader());
@@ -289,7 +289,7 @@ public class ScopedClassPool extends ClassPool {
* @throws CannotCompileException
* for any error
*/
- public Class toClass(CtClass ct, ClassLoader loader, ProtectionDomain domain)
+ public Class<?> toClass(CtClass ct, ClassLoader loader, ProtectionDomain domain)
throws CannotCompileException {
// We need to pass up the classloader stored in this pool, as the
// default implementation uses the Thread context cl.
diff --git a/src/main/javassist/scopedpool/ScopedClassPoolRepository.java b/src/main/javassist/scopedpool/ScopedClassPoolRepository.java
index 497501be..33e47124 100644
--- a/src/main/javassist/scopedpool/ScopedClassPoolRepository.java
+++ b/src/main/javassist/scopedpool/ScopedClassPoolRepository.java
@@ -81,7 +81,7 @@ public interface ScopedClassPoolRepository {
*
* @return the registered classloaders.
*/
- Map getRegisteredCLs();
+ Map<ClassLoader,ScopedClassPool> getRegisteredCLs();
/**
* This method will check to see if a register classloader has been
diff --git a/src/main/javassist/scopedpool/ScopedClassPoolRepositoryImpl.java b/src/main/javassist/scopedpool/ScopedClassPoolRepositoryImpl.java
index a9a3c822..8c20d97c 100644
--- a/src/main/javassist/scopedpool/ScopedClassPoolRepositoryImpl.java
+++ b/src/main/javassist/scopedpool/ScopedClassPoolRepositoryImpl.java
@@ -18,7 +18,7 @@ package javassist.scopedpool;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
@@ -43,8 +43,8 @@ public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository
boolean pruneWhenCached;
/** 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 */
protected ClassPool classpool;
@@ -76,6 +76,7 @@ public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository
*
* @return the prune.
*/
+ @Override
public boolean isPrune() {
return prune;
}
@@ -85,6 +86,7 @@ public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository
*
* @param prune a new value.
*/
+ @Override
public void setPrune(boolean prune) {
this.prune = prune;
}
@@ -96,10 +98,12 @@ public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository
* @param src the original classpool.
* @return the classpool
*/
+ @Override
public ScopedClassPool createScopedClassPool(ClassLoader cl, ClassPool src) {
return factory.create(cl, src, this);
}
+ @Override
public ClassPool findClassPool(ClassLoader cl) {
if (cl == null)
return registerClassLoader(ClassLoader.getSystemClassLoader());
@@ -113,6 +117,7 @@ public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository
* @param ucl the classloader.
* @return the classpool
*/
+ @Override
public ClassPool registerClassLoader(ClassLoader ucl) {
synchronized (registeredCLs) {
// FIXME: Probably want to take this method out later
@@ -121,7 +126,7 @@ public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository
// a
// ClassPool.classpath
if (registeredCLs.containsKey(ucl)) {
- return (ClassPool)registeredCLs.get(ucl);
+ return registeredCLs.get(ucl);
}
ScopedClassPool pool = createScopedClassPool(ucl, classpool);
registeredCLs.put(ucl, pool);
@@ -132,7 +137,8 @@ public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository
/**
* Get the registered classloaders.
*/
- public Map getRegisteredCLs() {
+ @Override
+ public Map<ClassLoader,ScopedClassPool> getRegisteredCLs() {
clearUnregisteredClassLoaders();
return registeredCLs;
}
@@ -141,34 +147,31 @@ public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository
* This method will check to see if a register classloader has been
* undeployed (as in JBoss)
*/
+ @Override
public void clearUnregisteredClassLoaders() {
- ArrayList toUnregister = null;
+ List<ClassLoader> toUnregister = null;
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 (toUnregister == null) {
- toUnregister = new ArrayList();
- }
+ if (toUnregister == null)
+ toUnregister = new ArrayList<ClassLoader>();
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) {
synchronized (registeredCLs) {
- ScopedClassPool pool = (ScopedClassPool)registeredCLs.remove(cl);
+ ScopedClassPool pool = registeredCLs.remove(cl);
if (pool != null)
pool.close();
}
@@ -178,10 +181,12 @@ public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository
// Noop - this is the end
}
+ @Override
public void setClassPoolFactory(ScopedClassPoolFactory factory) {
this.factory = factory;
}
+ @Override
public ScopedClassPoolFactory getClassPoolFactory() {
return factory;
}
diff --git a/src/main/javassist/scopedpool/SoftValueHashMap.java b/src/main/javassist/scopedpool/SoftValueHashMap.java
index df6ae599..1154e62e 100644
--- a/src/main/javassist/scopedpool/SoftValueHashMap.java
+++ b/src/main/javassist/scopedpool/SoftValueHashMap.java
@@ -18,10 +18,14 @@ package javassist.scopedpool;
import java.lang.ref.ReferenceQueue;
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.Set;
+import java.util.concurrent.ConcurrentHashMap;
/**
* This Map will remove entries when the value in the map has been cleaned from
@@ -30,21 +34,21 @@ import java.util.Set;
* @version <tt>$Revision: 1.4 $</tt>
* @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);
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)
return null;
else
- return new SoftValueRef(key, val, q);
+ return new SoftValueRef<K,V>(key, val, q);
}
}
@@ -52,30 +56,37 @@ public class SoftValueHashMap extends AbstractMap implements Map {
/**
* Returns a set of the mappings contained in this hash table.
*/
- public Set entrySet() {
+ @Override
+ public Set<Map.Entry<K, V>> entrySet() {
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 */
- private Map hash;
+ private Map<K,SoftValueRef<K,V>> hash;
/* 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
* whose values have been discarded.
*/
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 -- */
@@ -95,7 +106,7 @@ public class SoftValueHashMap extends AbstractMap implements Map {
* factor is nonpositive
*/
public SoftValueHashMap(int initialCapacity, float loadFactor) {
- hash = new HashMap(initialCapacity, loadFactor);
+ hash = new ConcurrentHashMap<K,SoftValueRef<K,V>>(initialCapacity, loadFactor);
}
/**
@@ -109,7 +120,7 @@ public class SoftValueHashMap extends AbstractMap implements Map {
* If the initial capacity is less than zero
*/
public SoftValueHashMap(int initialCapacity) {
- hash = new HashMap(initialCapacity);
+ hash = new ConcurrentHashMap<K,SoftValueRef<K,V>>(initialCapacity);
}
/**
@@ -117,7 +128,7 @@ public class SoftValueHashMap extends AbstractMap implements Map {
* initial capacity and the default load factor, which is <code>0.75</code>.
*/
public SoftValueHashMap() {
- hash = new HashMap();
+ hash = new ConcurrentHashMap<K,SoftValueRef<K,V>>();
}
/**
@@ -129,7 +140,7 @@ public class SoftValueHashMap extends AbstractMap implements 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);
putAll(t);
}
@@ -142,6 +153,7 @@ public class SoftValueHashMap extends AbstractMap implements Map {
* <code>Map</code> interface, the time required by this operation is
* linear in the size of the map.</em>
*/
+ @Override
public int size() {
processQueue();
return hash.size();
@@ -150,6 +162,7 @@ public class SoftValueHashMap extends AbstractMap implements Map {
/**
* Returns <code>true</code> if this map contains no key-value mappings.
*/
+ @Override
public boolean isEmpty() {
processQueue();
return hash.isEmpty();
@@ -162,6 +175,7 @@ public class SoftValueHashMap extends AbstractMap implements Map {
* @param key
* The key whose presence in this map is to be tested.
*/
+ @Override
public boolean containsKey(Object key) {
processQueue();
return hash.containsKey(key);
@@ -177,12 +191,10 @@ public class SoftValueHashMap extends AbstractMap implements Map {
* @param key
* The key whose associated value, if any, is to be returned.
*/
- public Object get(Object key) {
+ @Override
+ public V get(Object key) {
processQueue();
- SoftReference ref = (SoftReference)hash.get(key);
- if (ref != null)
- return ref.get();
- return null;
+ return valueOrNull(hash.get(key));
}
/**
@@ -200,12 +212,10 @@ public class SoftValueHashMap extends AbstractMap implements Map {
* @return The previous value to which this key was mapped, or
* <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();
- 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)));
}
/**
@@ -218,16 +228,66 @@ public class SoftValueHashMap extends AbstractMap implements Map {
* @return The value to which this key was mapped, or <code>null</code> if
* there was no mapping for the key.
*/
- public Object remove(Object key) {
+ @Override
+ public V remove(Object key) {
processQueue();
- return hash.remove(key);
+ return valueOrNull(hash.remove(key));
}
/**
* Removes all mappings from this map.
*/
+ @Override
public void clear() {
processQueue();
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();
+ }
}
diff --git a/src/test/scoped/ScopedRepositoryTestCase.java b/src/test/scoped/ScopedRepositoryTestCase.java
new file mode 100644
index 00000000..9dca4f56
--- /dev/null
+++ b/src/test/scoped/ScopedRepositoryTestCase.java
@@ -0,0 +1,242 @@
+/*
+ * 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 });
+ }
+}
diff --git a/src/test/scoped/TestAnnotation.java b/src/test/scoped/TestAnnotation.java
new file mode 100644
index 00000000..dd5c7b8c
--- /dev/null
+++ b/src/test/scoped/TestAnnotation.java
@@ -0,0 +1,34 @@
+/*
+ * 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";
+}
diff --git a/src/test/scoped/UnscopedAnnotationDefaultUsage.java b/src/test/scoped/UnscopedAnnotationDefaultUsage.java
new file mode 100644
index 00000000..bcbecfe6
--- /dev/null
+++ b/src/test/scoped/UnscopedAnnotationDefaultUsage.java
@@ -0,0 +1,29 @@
+/*
+ * 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) {}
+}
diff --git a/src/test/scoped/UnscopedAnnotationUsage.java b/src/test/scoped/UnscopedAnnotationUsage.java
new file mode 100644
index 00000000..e63db330
--- /dev/null
+++ b/src/test/scoped/UnscopedAnnotationUsage.java
@@ -0,0 +1,29 @@
+/*
+ * 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) {}
+}
diff --git a/src/test/scoped/jar1/FullyScopedAnnotationDefaultUsage.java b/src/test/scoped/jar1/FullyScopedAnnotationDefaultUsage.java
new file mode 100644
index 00000000..663d18f8
--- /dev/null
+++ b/src/test/scoped/jar1/FullyScopedAnnotationDefaultUsage.java
@@ -0,0 +1,29 @@
+/*
+ * 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) {}
+}
diff --git a/src/test/scoped/jar1/FullyScopedAnnotationUsage.java b/src/test/scoped/jar1/FullyScopedAnnotationUsage.java
new file mode 100644
index 00000000..c44aeb75
--- /dev/null
+++ b/src/test/scoped/jar1/FullyScopedAnnotationUsage.java
@@ -0,0 +1,29 @@
+/*
+ * 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) {}
+}
diff --git a/src/test/scoped/jar1/ScopedAnnotationDefaultUsage.java b/src/test/scoped/jar1/ScopedAnnotationDefaultUsage.java
new file mode 100644
index 00000000..284b0868
--- /dev/null
+++ b/src/test/scoped/jar1/ScopedAnnotationDefaultUsage.java
@@ -0,0 +1,31 @@
+/*
+ * 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) {}
+}
diff --git a/src/test/scoped/jar1/ScopedAnnotationUsage.java b/src/test/scoped/jar1/ScopedAnnotationUsage.java
new file mode 100644
index 00000000..23400f27
--- /dev/null
+++ b/src/test/scoped/jar1/ScopedAnnotationUsage.java
@@ -0,0 +1,31 @@
+/*
+ * 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) {}
+}
diff --git a/src/test/scoped/jar1/ScopedTestAnnotation.java b/src/test/scoped/jar1/ScopedTestAnnotation.java
new file mode 100644
index 00000000..25a36a58
--- /dev/null
+++ b/src/test/scoped/jar1/ScopedTestAnnotation.java
@@ -0,0 +1,34 @@
+/*
+ * 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";
+}
diff --git a/src/test/scoped/jar1/TestClass1.java b/src/test/scoped/jar1/TestClass1.java
new file mode 100644
index 00000000..a538bf77
--- /dev/null
+++ b/src/test/scoped/jar1/TestClass1.java
@@ -0,0 +1,26 @@
+/*
+ * 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
+{
+}