Home | History | Annotate | Download | only in internal
      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