forked from google/guice
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Patches to let Guice be more OSGi (and classloader) friendly. Solves …
…issue 439, issue 337, issue 443, and issue 343. All provided by Stuart McCulloch. Many thanks, Stuart! git-svn-id: https://google-guice.googlecode.com/svn/trunk@1158 d779f126-a31b-0410-b53b-1d3aecad763e
- Loading branch information
sberlin
committed
May 9, 2010
1 parent
34d2f00
commit f7ac6ea
Showing
24 changed files
with
787 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,6 @@ | |
|
||
package com.google.inject.internal; | ||
|
||
import static com.google.inject.internal.Preconditions.checkNotNull; | ||
import java.lang.reflect.Constructor; | ||
import java.lang.reflect.Member; | ||
import java.lang.reflect.Method; | ||
|
@@ -55,19 +54,24 @@ | |
* @author [email protected] (Stuart McCulloch) | ||
* @author [email protected] (Jesse Wilson) | ||
*/ | ||
final class BytecodeGen { | ||
public final class BytecodeGen { | ||
|
||
private static final Logger logger = Logger.getLogger(BytecodeGen.class.getName()); | ||
static final Logger logger = Logger.getLogger(BytecodeGen.class.getName()); | ||
|
||
static final ClassLoader GUICE_CLASS_LOADER = BytecodeGen.class.getClassLoader(); | ||
static final ClassLoader GUICE_CLASS_LOADER = canonicalize(BytecodeGen.class.getClassLoader()); | ||
|
||
// initialization-on-demand... | ||
private static class SystemBridgeHolder { | ||
static final BridgeClassLoader SYSTEM_BRIDGE = new BridgeClassLoader(); | ||
} | ||
|
||
/** ie. "com.google.inject.internal" */ | ||
private static final String GUICE_INTERNAL_PACKAGE | ||
static final String GUICE_INTERNAL_PACKAGE | ||
= BytecodeGen.class.getName().replaceFirst("\\.internal\\..*$", ".internal"); | ||
|
||
/*if[AOP]*/ | ||
/** either "net.sf.cglib", or "com.google.inject.internal.cglib" */ | ||
private static final String CGLIB_PACKAGE | ||
static final String CGLIB_PACKAGE | ||
= net.sf.cglib.proxy.Enhancer.class.getName().replaceFirst("\\.cglib\\..*$", ".cglib"); | ||
|
||
static final net.sf.cglib.core.NamingPolicy NAMING_POLICY | ||
|
@@ -82,47 +86,39 @@ final class BytecodeGen { | |
end[NO_AOP]*/ | ||
|
||
/** Use "-Dguice.custom.loader=false" to disable custom classloading. */ | ||
static final boolean HOOK_ENABLED | ||
= "true".equals(System.getProperty("guice.custom.loader", "true")); | ||
private static final boolean CUSTOM_LOADER_ENABLED | ||
= Boolean.parseBoolean(System.getProperty("guice.custom.loader", "true")); | ||
|
||
/** | ||
* Weak cache of bridge class loaders that make the Guice implementation | ||
* classes visible to various code-generated proxies of client classes. | ||
*/ | ||
private static final Map<ClassLoader, ClassLoader> CLASS_LOADER_CACHE | ||
= new MapMaker().weakKeys().weakValues().makeComputingMap( | ||
private static final Map<ClassLoader, ClassLoader> CLASS_LOADER_CACHE; | ||
|
||
static { | ||
if (CUSTOM_LOADER_ENABLED) { | ||
CLASS_LOADER_CACHE = new MapMaker().weakKeys().weakValues().makeComputingMap( | ||
new Function<ClassLoader, ClassLoader>() { | ||
public ClassLoader apply(final @Nullable ClassLoader typeClassLoader) { | ||
logger.fine("Creating a bridge ClassLoader for " + typeClassLoader); | ||
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { | ||
public ClassLoader run() { | ||
return new BridgeClassLoader(typeClassLoader); | ||
} | ||
}); | ||
public ClassLoader apply(final @Nullable ClassLoader typeClassLoader) { | ||
logger.fine("Creating a bridge ClassLoader for " + typeClassLoader); | ||
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { | ||
public ClassLoader run() { | ||
return new BridgeClassLoader(typeClassLoader); | ||
} | ||
}); | ||
} | ||
}); | ||
} else { | ||
CLASS_LOADER_CACHE = ImmutableMap.of(); | ||
} | ||
}); | ||
|
||
/** | ||
* For class loaders, {@code null}, is always an alias to the | ||
* {@link ClassLoader#getSystemClassLoader() system class loader}. This method | ||
* will not return null. | ||
*/ | ||
private static ClassLoader canonicalize(ClassLoader classLoader) { | ||
return classLoader != null | ||
? classLoader | ||
: checkNotNull(getSystemClassLoaderOrNull(), "Couldn't get a ClassLoader"); | ||
} | ||
|
||
/** | ||
* Returns the system classloader, or {@code null} if we don't have | ||
* permission. | ||
* Attempts to canonicalize null references to the system class loader. | ||
* May return null if for some reason the system loader is unavailable. | ||
*/ | ||
private static ClassLoader getSystemClassLoaderOrNull() { | ||
try { | ||
return ClassLoader.getSystemClassLoader(); | ||
} catch (SecurityException e) { | ||
return null; | ||
} | ||
private static ClassLoader canonicalize(ClassLoader classLoader) { | ||
return classLoader != null ? classLoader : SystemBridgeHolder.SYSTEM_BRIDGE.getParent(); | ||
} | ||
|
||
/** | ||
|
@@ -133,23 +129,30 @@ public static ClassLoader getClassLoader(Class<?> type) { | |
} | ||
|
||
private static ClassLoader getClassLoader(Class<?> type, ClassLoader delegate) { | ||
delegate = canonicalize(delegate); | ||
|
||
// if the application is running in the System classloader, assume we can run there too | ||
if (delegate == getSystemClassLoaderOrNull()) { | ||
// simple case: do nothing! | ||
if (!CUSTOM_LOADER_ENABLED) { | ||
return delegate; | ||
} | ||
|
||
// Don't bother bridging existing bridge classloaders | ||
if (delegate instanceof BridgeClassLoader) { | ||
delegate = canonicalize(delegate); | ||
|
||
// no need for a bridge if using same class loader, or it's already a bridge | ||
if (delegate == GUICE_CLASS_LOADER || delegate instanceof BridgeClassLoader) { | ||
return delegate; | ||
} | ||
|
||
if (HOOK_ENABLED && Visibility.forType(type) == Visibility.PUBLIC) { | ||
return CLASS_LOADER_CACHE.get(delegate); | ||
// don't try bridging private types as it won't work | ||
if (Visibility.forType(type) == Visibility.PUBLIC) { | ||
if (delegate != SystemBridgeHolder.SYSTEM_BRIDGE.getParent()) { | ||
// delegate guaranteed to be non-null here | ||
return CLASS_LOADER_CACHE.get(delegate); | ||
} | ||
// delegate may or may not be null here | ||
return SystemBridgeHolder.SYSTEM_BRIDGE; | ||
} | ||
|
||
return delegate; | ||
return delegate; // last-resort: do nothing! | ||
} | ||
|
||
/*if[AOP]*/ | ||
|
@@ -193,6 +196,7 @@ public enum Visibility { | |
* target class. These generated classes may be loaded by our bridge classloader. | ||
*/ | ||
PUBLIC { | ||
@Override | ||
public Visibility and(Visibility that) { | ||
return that; | ||
} | ||
|
@@ -205,6 +209,7 @@ public Visibility and(Visibility that) { | |
* garbage collected. | ||
*/ | ||
SAME_PACKAGE { | ||
@Override | ||
public Visibility and(Visibility that) { | ||
return this; | ||
} | ||
|
@@ -242,26 +247,44 @@ public static Visibility forType(Class<?> type) { | |
*/ | ||
private static class BridgeClassLoader extends ClassLoader { | ||
|
||
public BridgeClassLoader(ClassLoader usersClassLoader) { | ||
BridgeClassLoader() { | ||
// use system loader as parent | ||
} | ||
|
||
BridgeClassLoader(ClassLoader usersClassLoader) { | ||
super(usersClassLoader); | ||
} | ||
|
||
@Override protected Class<?> loadClass(String name, boolean resolve) | ||
throws ClassNotFoundException { | ||
|
||
// delegate internal requests to Guice class space | ||
if (name.startsWith("sun.reflect")) { | ||
// these reflection classes must be loaded from bootstrap class loader | ||
return SystemBridgeHolder.SYSTEM_BRIDGE.classicLoadClass(name, resolve); | ||
} | ||
|
||
if (name.startsWith(GUICE_INTERNAL_PACKAGE) || name.startsWith(CGLIB_PACKAGE)) { | ||
if (null == GUICE_CLASS_LOADER) { | ||
// use special system bridge to load classes from bootstrap class loader | ||
return SystemBridgeHolder.SYSTEM_BRIDGE.classicLoadClass(name, resolve); | ||
} | ||
try { | ||
Class<?> clazz = GUICE_CLASS_LOADER.loadClass(name); | ||
if (resolve) { | ||
resolveClass(clazz); | ||
} | ||
return clazz; | ||
} catch (Exception e) { | ||
// fall back to classic delegation | ||
} catch (Throwable e) { | ||
// fall-back to classic delegation | ||
} | ||
} | ||
|
||
return classicLoadClass(name, resolve); | ||
} | ||
|
||
// make the classic delegating loadClass method visible | ||
Class<?> classicLoadClass(String name, boolean resolve) | ||
throws ClassNotFoundException { | ||
return super.loadClass(name, resolve); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.