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 import java.lang.reflect.Constructor; 26 import java.lang.reflect.Member; 27 import java.lang.reflect.Method; 28 import java.lang.reflect.Modifier; 29 import java.security.AccessController; 30 import java.security.PrivilegedAction; 31 import java.util.logging.Level; 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 * 41 * <ul> 42 * <li><strong>Memory leaks.</strong> Generated classes need to be garbage collected in long-lived 43 * applications. Once an injector and any instances it created can be garbage collected, the 44 * corresponding generated classes should be collectable. 45 * <li><strong>Visibility.</strong> Containers like <code>OSGi</code> use class loader boundaries to 46 * enforce modularity at runtime. 47 * </ul> 48 * 49 * <p>For each generated class, there's multiple class loaders involved: 50 * 51 * <ul> 52 * <li><strong>The related class's class loader.</strong> Every generated class services exactly one 53 * user-supplied class. This class loader must be used to access members with protected and 54 * package visibility. 55 * <li><strong>Guice's class loader.</strong> 56 * <li><strong>Our bridge class loader.</strong> This is a child of the user's class loader. It 57 * selectively delegates to either the user's class loader (for user classes) or the Guice class 58 * loader (for internal classes that are used by the generated classes). This class loader that 59 * owns the classes generated by Guice. 60 * </ul> 61 * 62 * @author mcculls (at) gmail.com (Stuart McCulloch) 63 * @author jessewilson (at) google.com (Jesse Wilson) 64 */ 65 public final class BytecodeGen { 66 67 static final Logger logger = Logger.getLogger(BytecodeGen.class.getName()); 68 69 static final ClassLoader GUICE_CLASS_LOADER = canonicalize(BytecodeGen.class.getClassLoader()); 70 71 // initialization-on-demand... 72 private static class SystemBridgeHolder { 73 static final BridgeClassLoader SYSTEM_BRIDGE = new BridgeClassLoader(); 74 } 75 76 /** ie. "com.google.inject.internal" */ 77 static final String GUICE_INTERNAL_PACKAGE = 78 BytecodeGen.class.getName().replaceFirst("\\.internal\\..*$", ".internal"); 79 80 /*if[AOP]*/ 81 /** either "net.sf.cglib", or "com.google.inject.internal.cglib" */ 82 static final String CGLIB_PACKAGE = 83 net.sf.cglib.proxy.Enhancer.class.getName().replaceFirst("\\.cglib\\..*$", ".cglib"); 84 85 static final net.sf.cglib.core.NamingPolicy FASTCLASS_NAMING_POLICY = 86 new net.sf.cglib.core.DefaultNamingPolicy() { 87 @Override 88 protected String getTag() { 89 return "ByGuice"; 90 } 91 92 @Override 93 public String getClassName( 94 String prefix, String source, Object key, net.sf.cglib.core.Predicate names) { 95 // we explicitly set the source here to "FastClass" so that our jarjar renaming 96 // to $FastClass doesn't leak into the class names. if we did not do this, 97 // classes would end up looking like $$$FastClassByGuice$$, with the extra $ 98 // at the front. 99 return super.getClassName(prefix, "FastClass", key, names); 100 } 101 }; 102 103 static final net.sf.cglib.core.NamingPolicy ENHANCER_NAMING_POLICY = 104 new net.sf.cglib.core.DefaultNamingPolicy() { 105 @Override 106 protected String getTag() { 107 return "ByGuice"; 108 } 109 110 @Override 111 public String getClassName( 112 String prefix, String source, Object key, net.sf.cglib.core.Predicate names) { 113 // we explicitly set the source here to "Enhancer" so that our jarjar renaming 114 // to $Enhancer doesn't leak into the class names. if we did not do this, 115 // classes would end up looking like $$$EnhancerByGuice$$, with the extra $ 116 // at the front. 117 return super.getClassName(prefix, "Enhancer", key, names); 118 } 119 }; 120 /*end[AOP]*/ 121 /*if[NO_AOP] 122 private static final String CGLIB_PACKAGE = " "; // any string that's illegal in a package name 123 end[NO_AOP]*/ 124 125 /** 126 * Weak cache of bridge class loaders that make the Guice implementation classes visible to 127 * various code-generated proxies of client classes. 128 */ 129 private static final LoadingCache<ClassLoader, ClassLoader> CLASS_LOADER_CACHE; 130 131 static { 132 CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder().weakKeys().weakValues(); 133 if (getCustomClassLoadingOption() == CustomClassLoadingOption.OFF) { 134 builder.maximumSize(0); 135 } 136 CLASS_LOADER_CACHE = 137 builder.build( 138 new CacheLoader<ClassLoader, ClassLoader>() { 139 @Override 140 public ClassLoader load(final ClassLoader typeClassLoader) { 141 logger.fine("Creating a bridge ClassLoader for " + typeClassLoader); 142 return AccessController.doPrivileged( 143 new PrivilegedAction<ClassLoader>() { 144 @Override 145 public ClassLoader run() { 146 return new BridgeClassLoader(typeClassLoader); 147 } 148 }); 149 } 150 }); 151 } 152 153 /** 154 * Attempts to canonicalize null references to the system class loader. May return null if for 155 * some reason the system loader is unavailable. 156 */ 157 private static ClassLoader canonicalize(ClassLoader classLoader) { 158 return classLoader != null ? classLoader : SystemBridgeHolder.SYSTEM_BRIDGE.getParent(); 159 } 160 161 /** Returns the class loader to host generated classes for {@code type}. */ 162 public static ClassLoader getClassLoader(Class<?> type) { 163 return getClassLoader(type, type.getClassLoader()); 164 } 165 166 private static ClassLoader getClassLoader(Class<?> type, ClassLoader delegate) { 167 168 // simple case: do nothing! 169 if (getCustomClassLoadingOption() == CustomClassLoadingOption.OFF) { 170 return delegate; 171 } 172 173 // java.* types can be seen everywhere 174 if (type.getName().startsWith("java.")) { 175 return GUICE_CLASS_LOADER; 176 } 177 178 delegate = canonicalize(delegate); 179 180 // no need for a bridge if using same class loader, or it's already a bridge 181 if (delegate == GUICE_CLASS_LOADER || delegate instanceof BridgeClassLoader) { 182 return delegate; 183 } 184 185 // don't try bridging private types as it won't work 186 if (Visibility.forType(type) == Visibility.PUBLIC) { 187 if (delegate != SystemBridgeHolder.SYSTEM_BRIDGE.getParent()) { 188 // delegate guaranteed to be non-null here 189 return CLASS_LOADER_CACHE.getUnchecked(delegate); 190 } 191 // delegate may or may not be null here 192 return SystemBridgeHolder.SYSTEM_BRIDGE; 193 } 194 195 return delegate; // last-resort: do nothing! 196 } 197 198 /*if[AOP]*/ 199 // use fully-qualified names so imports don't need preprocessor statements 200 /** 201 * Returns a FastClass proxy for invoking the given member or {@code null} if access rules 202 * disallow it. 203 * 204 * @see #newFastClassForMember(Class, Member) for a full description 205 */ 206 public static net.sf.cglib.reflect.FastClass newFastClassForMember(Member member) { 207 return newFastClassForMember(member.getDeclaringClass(), member); 208 } 209 210 /** 211 * Returns a FastClass proxy for invoking the given member or {@code null} if access rules 212 * disallow it. 213 * 214 * <p>FastClass works by generating a type in the same package as the target {@code type}. This 215 * may or may not work depending on the access level of the class/member. It breaks down into the 216 * following cases depending on accessibility: 217 * 218 * <ul> 219 * <li>Public: This always works since we can generate the type into the {@link BridgeClassLoader} 220 * which ensures there are no versioning issues. 221 * <li>Package private and Protected: This works as long as: 222 * <ul> 223 * <li>We can generate into the same classloader as the type. This is not possible for JDK 224 * types which use the 'bootstrap' loader. 225 * <li>The classloader of the type has the same version of {@code FastClass} as we do. This 226 * may be violated when running in OSGI bundles. 227 * </ul> 228 * 229 * <li>Private: This never works. 230 * </ul> 231 * 232 * If we are unable to generate the type, then we return null and callers should work around by 233 * using normal java reflection. 234 */ 235 public static net.sf.cglib.reflect.FastClass newFastClassForMember(Class<?> type, Member member) { 236 if (!new net.sf.cglib.core.VisibilityPredicate(type, false).evaluate(member)) { 237 // the member cannot be indexed by fast class. Bail out. 238 return null; 239 } 240 241 boolean publiclyCallable = isPubliclyCallable(member); 242 if (!publiclyCallable && !hasSameVersionOfCglib(type.getClassLoader())) { 243 // The type is in a classloader with a different version of cglib and is not publicly visible 244 // (so we can't use the bridge classloader to work around). Bail out. 245 return null; 246 } 247 net.sf.cglib.reflect.FastClass.Generator generator = 248 new net.sf.cglib.reflect.FastClass.Generator(); 249 if (publiclyCallable) { 250 // Use the bridge classloader if we can 251 generator.setClassLoader(getClassLoader(type)); 252 } 253 generator.setType(type); 254 generator.setNamingPolicy(FASTCLASS_NAMING_POLICY); 255 if (logger.isLoggable(Level.FINE)) { 256 logger.fine("Loading " + type + " FastClass with " + generator.getClassLoader()); 257 } 258 return generator.create(); 259 } 260 261 /** 262 * Returns true if the types classloader has the same version of cglib that BytecodeGen has. This 263 * only returns false in strange OSGI situations, but it prevents us from using FastClass for non 264 * public members. 265 */ 266 private static boolean hasSameVersionOfCglib(ClassLoader classLoader) { 267 Class<?> fc = net.sf.cglib.reflect.FastClass.class; 268 try { 269 return classLoader.loadClass(fc.getName()) == fc; 270 } catch (ClassNotFoundException e) { 271 return false; 272 } 273 } 274 275 /** 276 * Returns true if the member can be called by a fast class generated in a different classloader. 277 */ 278 private static boolean isPubliclyCallable(Member member) { 279 if (!Modifier.isPublic(member.getModifiers())) { 280 return false; 281 } 282 Class<?>[] parameterTypes; 283 if (member instanceof Constructor) { 284 parameterTypes = ((Constructor) member).getParameterTypes(); 285 } else { 286 Method method = (Method) member; 287 if (!Modifier.isPublic(method.getReturnType().getModifiers())) { 288 return false; 289 } 290 parameterTypes = method.getParameterTypes(); 291 } 292 293 for (Class<?> type : parameterTypes) { 294 if (!Modifier.isPublic(type.getModifiers())) { 295 return false; 296 } 297 } 298 return true; 299 } 300 301 public static net.sf.cglib.proxy.Enhancer newEnhancer(Class<?> type, Visibility visibility) { 302 net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer(); 303 enhancer.setSuperclass(type); 304 enhancer.setUseFactory(false); 305 if (visibility == Visibility.PUBLIC) { 306 enhancer.setClassLoader(getClassLoader(type)); 307 } 308 enhancer.setNamingPolicy(ENHANCER_NAMING_POLICY); 309 logger.fine("Loading " + type + " Enhancer with " + enhancer.getClassLoader()); 310 return enhancer; 311 } 312 /*end[AOP]*/ 313 314 /** 315 * The required visibility of a user's class from a Guice-generated class. Visibility of 316 * package-private members depends on the loading classloader: only if two classes were loaded by 317 * the same classloader can they see each other's package-private members. We need to be careful 318 * when choosing which classloader to use for generated classes. We prefer our bridge classloader, 319 * since it's OSGi-safe and doesn't leak permgen space. But often we cannot due to visibility. 320 */ 321 public enum Visibility { 322 323 /** 324 * Indicates that Guice-generated classes only need to call and override public members of the 325 * target class. These generated classes may be loaded by our bridge classloader. 326 */ 327 PUBLIC { 328 @Override 329 public Visibility and(Visibility that) { 330 return that; 331 } 332 }, 333 334 /** 335 * Indicates that Guice-generated classes need to call or override package-private members. 336 * These generated classes must be loaded in the same classloader as the target class. They 337 * won't work with OSGi, and won't get garbage collected until the target class' classloader is 338 * garbage collected. 339 */ 340 SAME_PACKAGE { 341 @Override 342 public Visibility and(Visibility that) { 343 return this; 344 } 345 }; 346 347 public static Visibility forMember(Member member) { 348 if ((member.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) == 0) { 349 return SAME_PACKAGE; 350 } 351 352 Class[] parameterTypes; 353 if (member instanceof Constructor) { 354 parameterTypes = ((Constructor) member).getParameterTypes(); 355 } else { 356 Method method = (Method) member; 357 if (forType(method.getReturnType()) == SAME_PACKAGE) { 358 return SAME_PACKAGE; 359 } 360 parameterTypes = method.getParameterTypes(); 361 } 362 363 for (Class<?> type : parameterTypes) { 364 if (forType(type) == SAME_PACKAGE) { 365 return SAME_PACKAGE; 366 } 367 } 368 369 return PUBLIC; 370 } 371 372 public static Visibility forType(Class<?> type) { 373 return (type.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) != 0 374 ? PUBLIC 375 : SAME_PACKAGE; 376 } 377 378 public abstract Visibility and(Visibility that); 379 } 380 381 /** 382 * Loader for Guice-generated classes. For referenced classes, this delegates to either either the 383 * user's classloader (which is the parent of this classloader) or Guice's class loader. 384 */ 385 private static class BridgeClassLoader extends ClassLoader { 386 387 BridgeClassLoader() { 388 // use system loader as parent 389 } 390 391 BridgeClassLoader(ClassLoader usersClassLoader) { 392 super(usersClassLoader); 393 } 394 395 @Override 396 protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 397 398 if (name.startsWith("sun.reflect") || name.startsWith("jdk.internal.reflect")) { 399 // these reflection classes must be loaded from bootstrap class loader 400 return SystemBridgeHolder.SYSTEM_BRIDGE.classicLoadClass(name, resolve); 401 } 402 403 if (name.startsWith(GUICE_INTERNAL_PACKAGE) || name.startsWith(CGLIB_PACKAGE)) { 404 if (null == GUICE_CLASS_LOADER) { 405 // use special system bridge to load classes from bootstrap class loader 406 return SystemBridgeHolder.SYSTEM_BRIDGE.classicLoadClass(name, resolve); 407 } 408 try { 409 Class<?> clazz = GUICE_CLASS_LOADER.loadClass(name); 410 if (resolve) { 411 resolveClass(clazz); 412 } 413 return clazz; 414 } catch (Throwable e) { 415 // fall-back to classic delegation 416 } 417 } 418 419 return classicLoadClass(name, resolve); 420 } 421 422 // make the classic delegating loadClass method visible 423 Class<?> classicLoadClass(String name, boolean resolve) throws ClassNotFoundException { 424 return super.loadClass(name, resolve); 425 } 426 } 427 } 428