This patch introduces a factory method to get instances, such that there
only ever is a single instance for a particular class pool. This fixes
the potential issue of adding a class path multiple times.
Change-Id: Ia8ff47674b768bd85ae50200734b8f14927f8a5c
Signed-off-by: Robert Varga <rovarga@cisco.com>
import com.google.common.base.Preconditions;
import com.google.common.base.Preconditions;
-public class JavassistUtils {
+public final class JavassistUtils {
private static final Logger LOG = LoggerFactory.getLogger(JavassistUtils.class);
private static final Logger LOG = LoggerFactory.getLogger(JavassistUtils.class);
+ private static final Map<ClassPool, JavassistUtils> INSTANCES = new WeakHashMap<>();
private final Map<ClassLoader, ClassPath> loaderClassPaths = new WeakHashMap<>();
private final Lock lock = new ReentrantLock();
private final ClassPool classPool;
private final Map<ClassLoader, ClassPath> loaderClassPaths = new WeakHashMap<>();
private final Lock lock = new ReentrantLock();
private final ClassPool classPool;
+ /**
+ * @deprecated Use {@link #forClassPool(ClassPool)} instead.
+ *
+ * This class provides auto-loading into the classpool. Unfortunately reusing
+ * the same class pool with multiple instances can lead the same classpath
+ * being added multiple times, which lowers performance and leaks memory.
+ */
+ @Deprecated
public JavassistUtils(final ClassPool pool) {
public JavassistUtils(final ClassPool pool) {
+ this(pool, null);
+ }
+
+ private JavassistUtils(final ClassPool pool, final Object dummy) {
+ // FIXME: Remove 'dummy' once deprecated constructor is removed
classPool = Preconditions.checkNotNull(pool);
}
classPool = Preconditions.checkNotNull(pool);
}
+ /**
+ * Get a utility instance for a particular class pool. A new instance is
+ * created if this is a new pool. If an instance already exists, is is
+ * returned.
+ *
+ * @param pool
+ * @return
+ */
+ public static synchronized JavassistUtils forClassPool(final ClassPool pool) {
+ JavassistUtils ret = INSTANCES.get(pool);
+ if (ret == null) {
+ ret = new JavassistUtils(pool, null);
+ INSTANCES.put(pool, ret);
+ }
+ return ret;
+ }
+
public Lock getLock() {
return lock;
}
public Lock getLock() {
return lock;
}
}
public synchronized void appendClassLoaderIfMissing(final ClassLoader loader) {
}
public synchronized void appendClassLoaderIfMissing(final ClassLoader loader) {
- // FIXME: this works as long as the ClassPool is not shared between instances of this class
- // How is synchronization across multiple instances done? The ClassPool itself just
- // keeps on adding the loaders and does not check for duplicates!
if (!loaderClassPaths.containsKey(loader)) {
final ClassPath ctLoader = new LoaderClassPath(loader);
classPool.appendClassPath(ctLoader);
if (!loaderClassPaths.containsKey(loader)) {
final ClassPath ctLoader = new LoaderClassPath(loader);
classPool.appendClassPath(ctLoader);