1 /** 2 * Copyright (C) 2008 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.inject.internal; 18 19 import static com.google.inject.internal.InternalFlags.getCustomClassLoadingOption; 20 21 import com.google.common.cache.CacheBuilder; 22 import com.google.common.cache.CacheLoader; 23 import com.google.common.cache.LoadingCache; 24 import com.google.inject.internal.InternalFlags.CustomClassLoadingOption; 25 26 import java.lang.reflect.Constructor; 27 import java.lang.reflect.Member; 28 import java.lang.reflect.Method; 29 import java.lang.reflect.Modifier; 30 import java.security.AccessController; 31 import java.security.PrivilegedAction; 32 import java.util.logging.Logger; 33 34 /** 35 * Utility methods for runtime code generation and class loading. We use this stuff for {@link 36 * net.sf.cglib.reflect.FastClass faster reflection}, {@link net.sf.cglib.proxy.Enhancer method 37 * interceptors} and to proxy circular dependencies. 38 * 39 * <p>When loading classes, we need to be careful of: 40 * <ul> 41 * <li><strong>Memory leaks.</strong> Generated classes need to be garbage collected in long-lived 42 * applications. Once an injector and any instances it created can be garbage collected, the 43 * corresponding generated classes should be collectable. 44 * <li><strong>Visibility.</strong> Containers like <code>OSGi</code> use class loader boundaries 45 * to enforce modularity at runtime. 46 * </ul> 47 * 48 * <p>For each generated class, there's multiple class loaders involved: 49 * <ul> 50 * <li><strong>The related class's class loader.</strong> Every generated class services exactly 51 * one user-supplied class. This class loader must be used to access members with private and 52 * package visibility. 53 * <li><strong>Guice's class loader.</strong> 54 * <li><strong>Our bridge class loader.</strong> This is a child of the user's class loader. It 55 * selectively delegates to either the user's class loader (for user classes) or the Guice 56 * class loader (for internal classes that are used by the generated classes). This class 57 * loader that owns the classes generated by Guice. 58 * </ul> 59 * 60 * @author mcculls@gmail.com (Stuart McCulloch) 61 * @author jessewilson@google.com (Jesse Wilson) 62 */ 63 public final class BytecodeGen { 64 65 static final Logger logger = Logger.getLogger(BytecodeGen.class.getName()); 66 67 static final ClassLoader GUICE_CLASS_LOADER = canonicalize(BytecodeGen.class.getClassLoader()); 68 69 // initialization-on-demand... 70 private static class SystemBridgeHolder { 71 static final BridgeClassLoader SYSTEM_BRIDGE = new BridgeClassLoader(); 72 } 73 74 /** ie. "com.google.inject.internal" */ 75 static final String GUICE_INTERNAL_PACKAGE 76 = BytecodeGen.class.getName().replaceFirst("\\.internal\\..*$", ".internal"); 77 78 /*if[AOP]*/ 79 /** either "net.sf.cglib", or "com.google.inject.internal.cglib" */ 80 static final String CGLIB_PACKAGE 81 = net.sf.cglib.proxy.Enhancer.class.getName().replaceFirst("\\.cglib\\..*$", ".cglib"); 82 83 static final net.sf.cglib.core.NamingPolicy FASTCLASS_NAMING_POLICY 84 = new net.sf.cglib.core.DefaultNamingPolicy() { 85 @Override protected String getTag() { 86 return "ByGuice"; 87 } 88 89 @Override 90 public String getClassName(String prefix, String source, Object key, 91 net.sf.cglib.core.Predicate names) { 92 // we explicitly set the source here to "FastClass" so that our jarjar renaming 93 // to $FastClass doesn't leak into the class names. if we did not do this, 94 // classes would end up looking like $$$FastClassByGuice$$, with the extra $ 95 // at the front. 96 return super.getClassName(prefix, "FastClass", key, names); 97 } 98 }; 99 100 static final net.sf.cglib.core.NamingPolicy ENHANCER_NAMING_POLICY 101 = new net.sf.cglib.core.DefaultNamingPolicy() { 102 @Override 103 protected String getTag() { 104 return "ByGuice"; 105 } 106 107 @Override 108 public String getClassName(String prefix, String source, Object key, 109 net.sf.cglib.core.Predicate names) { 110 // we explicitly set the source here to "Enhancer" so that our jarjar renaming 111 // to $Enhancer doesn't leak into the class names. if we did not do this, 112 // classes would end up looking like $$$EnhancerByGuice$$, with the extra $ 113 // at the front. 114 return super.getClassName(prefix, "Enhancer", key, names); 115 } 116 }; 117 /*end[AOP]*/ 118 /*if[NO_AOP] 119 private static final String CGLIB_PACKAGE = " "; // any string that's illegal in a package name 120 end[NO_AOP]*/ 121 122 /** 123 * Weak cache of bridge class loaders that make the Guice implementation 124 * classes visible to various code-generated proxies of client classes. 125 */ 126 private static final LoadingCache<ClassLoader, ClassLoader> CLASS_LOADER_CACHE; 127 128 static { 129 CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder().weakKeys().weakValues(); 130 if (getCustomClassLoadingOption() == CustomClassLoadingOption.OFF) { 131 builder.maximumSize(0); 132 } 133 CLASS_LOADER_CACHE = builder.build( 134 new CacheLoader<ClassLoader, ClassLoader>() { 135 @Override public ClassLoader load(final ClassLoader typeClassLoader) { 136 logger.fine("Creating a bridge ClassLoader for " + typeClassLoader); 137 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { 138 public ClassLoader run() { 139 return new BridgeClassLoader(typeClassLoader); 140 } 141 }); 142 } 143 }); 144 } 145 146 /** 147 * Attempts to canonicalize null references to the system class loader. 148 * May return null if for some reason the system loader is unavailable. 149 */ canonicalize(ClassLoader classLoader)150 private static ClassLoader canonicalize(ClassLoader classLoader) { 151 return classLoader != null ? classLoader : SystemBridgeHolder.SYSTEM_BRIDGE.getParent(); 152 } 153 154 /** 155 * Returns the class loader to host generated classes for {@code type}. 156 */ getClassLoader(Class<?> type)157 public static ClassLoader getClassLoader(Class<?> type) { 158 return getClassLoader(type, type.getClassLoader()); 159 } 160 getClassLoader(Class<?> type, ClassLoader delegate)161 private static ClassLoader getClassLoader(Class<?> type, ClassLoader delegate) { 162 163 // simple case: do nothing! 164 if (getCustomClassLoadingOption() == CustomClassLoadingOption.OFF) { 165 return delegate; 166 } 167 168 // java.* types can be seen everywhere 169 if (type.getName().startsWith("java.")) { 170 return GUICE_CLASS_LOADER; 171 } 172 173 delegate = canonicalize(delegate); 174 175 // no need for a bridge if using same class loader, or it's already a bridge 176 if (delegate == GUICE_CLASS_LOADER || delegate instanceof BridgeClassLoader) { 177 return delegate; 178 } 179 180 // don't try bridging private types as it won't work 181 if (Visibility.forType(type) == Visibility.PUBLIC) { 182 if (delegate != SystemBridgeHolder.SYSTEM_BRIDGE.getParent()) { 183 // delegate guaranteed to be non-null here 184 return CLASS_LOADER_CACHE.getUnchecked(delegate); 185 } 186 // delegate may or may not be null here 187 return SystemBridgeHolder.SYSTEM_BRIDGE; 188 } 189 190 return delegate; // last-resort: do nothing! 191 } 192 193 /*if[AOP]*/ 194 // use fully-qualified names so imports don't need preprocessor statements newFastClass(Class<?> type, Visibility visibility)195 public static net.sf.cglib.reflect.FastClass newFastClass(Class<?> type, Visibility visibility) { 196 net.sf.cglib.reflect.FastClass.Generator generator 197 = new net.sf.cglib.reflect.FastClass.Generator(); 198 generator.setType(type); 199 if (visibility == Visibility.PUBLIC) { 200 generator.setClassLoader(getClassLoader(type)); 201 } 202 generator.setNamingPolicy(FASTCLASS_NAMING_POLICY); 203 logger.fine("Loading " + type + " FastClass with " + generator.getClassLoader()); 204 return generator.create(); 205 } 206 newEnhancer(Class<?> type, Visibility visibility)207 public static net.sf.cglib.proxy.Enhancer newEnhancer(Class<?> type, Visibility visibility) { 208 net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer(); 209 enhancer.setSuperclass(type); 210 enhancer.setUseFactory(false); 211 if (visibility == Visibility.PUBLIC) { 212 enhancer.setClassLoader(getClassLoader(type)); 213 } 214 enhancer.setNamingPolicy(ENHANCER_NAMING_POLICY); 215 logger.fine("Loading " + type + " Enhancer with " + enhancer.getClassLoader()); 216 return enhancer; 217 } 218 /*end[AOP]*/ 219 220 /** 221 * The required visibility of a user's class from a Guice-generated class. Visibility of 222 * package-private members depends on the loading classloader: only if two classes were loaded by 223 * the same classloader can they see each other's package-private members. We need to be careful 224 * when choosing which classloader to use for generated classes. We prefer our bridge classloader, 225 * since it's OSGi-safe and doesn't leak permgen space. But often we cannot due to visibility. 226 */ 227 public enum Visibility { 228 229 /** 230 * Indicates that Guice-generated classes only need to call and override public members of the 231 * target class. These generated classes may be loaded by our bridge classloader. 232 */ 233 PUBLIC { 234 @Override and(Visibility that)235 public Visibility and(Visibility that) { 236 return that; 237 } 238 }, 239 240 /** 241 * Indicates that Guice-generated classes need to call or override package-private members. 242 * These generated classes must be loaded in the same classloader as the target class. They 243 * won't work with OSGi, and won't get garbage collected until the target class' classloader is 244 * garbage collected. 245 */ 246 SAME_PACKAGE { 247 @Override and(Visibility that)248 public Visibility and(Visibility that) { 249 return this; 250 } 251 }; 252 forMember(Member member)253 public static Visibility forMember(Member member) { 254 if ((member.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) == 0) { 255 return SAME_PACKAGE; 256 } 257 258 Class[] parameterTypes; 259 if (member instanceof Constructor) { 260 parameterTypes = ((Constructor) member).getParameterTypes(); 261 } else { 262 Method method = (Method) member; 263 if (forType(method.getReturnType()) == SAME_PACKAGE) { 264 return SAME_PACKAGE; 265 } 266 parameterTypes = method.getParameterTypes(); 267 } 268 269 for (Class<?> type : parameterTypes) { 270 if (forType(type) == SAME_PACKAGE) { 271 return SAME_PACKAGE; 272 } 273 } 274 275 return PUBLIC; 276 } 277 forType(Class<?> type)278 public static Visibility forType(Class<?> type) { 279 return (type.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) != 0 280 ? PUBLIC 281 : SAME_PACKAGE; 282 } 283 and(Visibility that)284 public abstract Visibility and(Visibility that); 285 } 286 287 /** 288 * Loader for Guice-generated classes. For referenced classes, this delegates to either either the 289 * user's classloader (which is the parent of this classloader) or Guice's class loader. 290 */ 291 private static class BridgeClassLoader extends ClassLoader { 292 BridgeClassLoader()293 BridgeClassLoader() { 294 // use system loader as parent 295 } 296 BridgeClassLoader(ClassLoader usersClassLoader)297 BridgeClassLoader(ClassLoader usersClassLoader) { 298 super(usersClassLoader); 299 } 300 loadClass(String name, boolean resolve)301 @Override protected Class<?> loadClass(String name, boolean resolve) 302 throws ClassNotFoundException { 303 304 if (name.startsWith("sun.reflect")) { 305 // these reflection classes must be loaded from bootstrap class loader 306 return SystemBridgeHolder.SYSTEM_BRIDGE.classicLoadClass(name, resolve); 307 } 308 309 if (name.startsWith(GUICE_INTERNAL_PACKAGE) || name.startsWith(CGLIB_PACKAGE)) { 310 if (null == GUICE_CLASS_LOADER) { 311 // use special system bridge to load classes from bootstrap class loader 312 return SystemBridgeHolder.SYSTEM_BRIDGE.classicLoadClass(name, resolve); 313 } 314 try { 315 Class<?> clazz = GUICE_CLASS_LOADER.loadClass(name); 316 if (resolve) { 317 resolveClass(clazz); 318 } 319 return clazz; 320 } catch (Throwable e) { 321 // fall-back to classic delegation 322 } 323 } 324 325 return classicLoadClass(name, resolve); 326 } 327 328 // make the classic delegating loadClass method visible classicLoadClass(String name, boolean resolve)329 Class<?> classicLoadClass(String name, boolean resolve) 330 throws ClassNotFoundException { 331 return super.loadClass(name, resolve); 332 } 333 } 334 } 335