home | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (BytecodeGenTest.java)

This example Java source code file (BytecodeGenTest.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

abstractmodule, class, classnotfoundexception, hidden, injector, logcreator, module, multipleversionsofguiceclassloader, net, network, object, reflection, string, testvisibilityclassloader, throwable, world

The BytecodeGenTest.java Java example source code

/**
 * Copyright (C) 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.guice;

import static com.google.inject.matcher.Matchers.any;

import com.google.common.testing.GcFinalization;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;

import com.googlecode.guice.BytecodeGenTest.LogCreator;
import com.googlecode.guice.PackageVisibilityTestModule.PublicUserOfPackagePrivate;

import junit.framework.TestCase;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URLClassLoader;

import javax.inject.Inject;

/**
 * This test is in a separate package so we can test package-level visibility
 * with confidence.
 *
 * @author mcculls@gmail.com (Stuart McCulloch)
 */
public class BytecodeGenTest extends TestCase {

  private final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();

  private final Module interceptorModule = new AbstractModule() {
    protected void configure() {
      bindInterceptor(any(), any(), new MethodInterceptor() {
        public Object invoke(MethodInvocation chain)
            throws Throwable {
          return chain.proceed() + " WORLD";
        }
      });
    }
  };

  private final Module noopInterceptorModule = new AbstractModule() {
      protected void configure() {
        bindInterceptor(any(), any(), new MethodInterceptor() {
          public Object invoke(MethodInvocation chain)
              throws Throwable {
            return chain.proceed();
          }
        });
      }
    };

  public void testPackageVisibility() {
    Injector injector = Guice.createInjector(new PackageVisibilityTestModule());
    injector.getInstance(PublicUserOfPackagePrivate.class); // This must pass.
  }

  public void testInterceptedPackageVisibility() {
    Injector injector = Guice.createInjector(interceptorModule, new PackageVisibilityTestModule());
    injector.getInstance(PublicUserOfPackagePrivate.class); // This must pass.
  }

  public void testEnhancerNaming() {
    Injector injector = Guice.createInjector(interceptorModule, new PackageVisibilityTestModule());
    PublicUserOfPackagePrivate pupp = injector.getInstance(PublicUserOfPackagePrivate.class);
    assertTrue(pupp.getClass().getName().startsWith(
        PublicUserOfPackagePrivate.class.getName() + "$$EnhancerByGuice$$"));
  }

  // TODO(sameb): Figure out how to test FastClass naming tests.

  /**
   * Custom URL classloader with basic visibility rules
   */
  static class TestVisibilityClassLoader
      extends URLClassLoader {

    final boolean hideInternals;

    TestVisibilityClassLoader(boolean hideInternals) {
      this((URLClassLoader) TestVisibilityClassLoader.class.getClassLoader(), hideInternals);
    }

    TestVisibilityClassLoader(URLClassLoader classloader, boolean hideInternals) {
      super(classloader.getURLs(), classloader);
      this.hideInternals = hideInternals;
    }

    /**
     * Classic parent-delegating classloaders are meant to override findClass.
     * However, non-delegating classloaders (as used in OSGi) instead override
     * loadClass to provide support for "class-space" separation.
     */
    @Override
    protected Class<?> loadClass(final String name, final boolean resolve)
        throws ClassNotFoundException {

      synchronized (this) {
        // check our local cache to avoid duplicates
        final Class<?> clazz = findLoadedClass(name);
        if (clazz != null) {
          return clazz;
        }
      }

      if (name.startsWith("java.")) {

        // standard bootdelegation of java.*
        return super.loadClass(name, resolve);

      } else if (!name.contains(".internal.") && !name.contains(".cglib.")) {

        /*
         * load public and test classes directly from the classpath - we don't
         * delegate to our parent because then the loaded classes would also be
         * able to see private internal Guice classes, as they are also loaded
         * by the parent classloader.
         */
        final Class<?> clazz = findClass(name);
        if (resolve) {
          resolveClass(clazz);
        }
        return clazz;
      }

      // hide internal non-test classes
      if (hideInternals) {
        throw new ClassNotFoundException();
      }
      return super.loadClass(name, resolve);
    }
  }

  /** as loaded by another class loader */
  private Class<ProxyTest> proxyTestClass;
  private Class<ProxyTestImpl> realClass;
  private Module testModule;

  @SuppressWarnings("unchecked")
  protected void setUp() throws Exception {
    super.setUp();

    ClassLoader testClassLoader = new TestVisibilityClassLoader(true);
    proxyTestClass = (Class<ProxyTest>) testClassLoader.loadClass(ProxyTest.class.getName());
    realClass = (Class<ProxyTestImpl>) testClassLoader.loadClass(ProxyTestImpl.class.getName());

    testModule = new AbstractModule() {
      public void configure() {
        bind(proxyTestClass).to(realClass);
      }
    };
  }

  interface ProxyTest {
    String sayHello();
  }

  /**
   * Note: this class must be marked as public or protected so that the Guice
   * custom classloader will intercept it. Private and implementation classes
   * are not intercepted by the custom classloader.
   *
   * @see com.google.inject.internal.BytecodeGen.Visibility
   */
  public static class ProxyTestImpl implements ProxyTest {

    static {
      //System.out.println(ProxyTestImpl.class.getClassLoader());
    }

    public String sayHello() {
      return "HELLO";
    }
  }

  public void testProxyClassLoading() throws Exception {
    Object testObject = Guice.createInjector(interceptorModule, testModule)
        .getInstance(proxyTestClass);

    // verify method interception still works
    Method m = realClass.getMethod("sayHello");
    assertEquals("HELLO WORLD", m.invoke(testObject));
  }

  public void testSystemClassLoaderIsUsedIfProxiedClassUsesIt() {
    ProxyTest testProxy = Guice.createInjector(interceptorModule, new Module() {
      public void configure(Binder binder) {
        binder.bind(ProxyTest.class).to(ProxyTestImpl.class);
      }
    }).getInstance(ProxyTest.class);

    if (ProxyTest.class.getClassLoader() == systemClassLoader) {
      assertSame(testProxy.getClass().getClassLoader(), systemClassLoader);
    } else {
      assertNotSame(testProxy.getClass().getClassLoader(), systemClassLoader);
    }
  }

  public void testProxyClassUnloading() {
    Object testObject = Guice.createInjector(interceptorModule, testModule)
        .getInstance(proxyTestClass);
    assertNotNull(testObject.getClass().getClassLoader());
    assertNotSame(testObject.getClass().getClassLoader(), systemClassLoader);

    // take a weak reference to the generated proxy class
    WeakReference<Class clazzRef = new WeakReference>(testObject.getClass());

    assertNotNull(clazzRef.get());

    // null the proxy
    testObject = null;

    /*
     * this should be enough to queue the weak reference
     * unless something is holding onto it accidentally.
     */
    GcFinalization.awaitClear(clazzRef);

    // This test could be somewhat flaky when the GC isn't working.
    // If it fails, run the test again to make sure it's failing reliably.
    assertNull("Proxy class was not unloaded.", clazzRef.get());
  }

  public void testProxyingPackagePrivateMethods() {
    Injector injector = Guice.createInjector(interceptorModule);
    assertEquals("HI WORLD", injector.getInstance(PackageClassPackageMethod.class).sayHi());
    assertEquals("HI WORLD", injector.getInstance(PublicClassPackageMethod.class).sayHi());
    assertEquals("HI WORLD", injector.getInstance(ProtectedClassProtectedMethod.class).sayHi());
  }

  static class PackageClassPackageMethod {
    String sayHi() {
      return "HI";
    }
  }

  public static class PublicClassPackageMethod {
    String sayHi() {
      return "HI";
    }
  }

  protected static class ProtectedClassProtectedMethod {
    protected String sayHi() {
      return "HI";
    }
  }

  static class Hidden {
  }

  public static class HiddenMethodReturn {
    public Hidden method() {
      return new Hidden();
    }
  }

  public static class HiddenMethodParameter {
    public void method(Hidden h) {
    }
  }

  public void testClassLoaderBridging() throws Exception {
    ClassLoader testClassLoader = new TestVisibilityClassLoader(false);

    Class hiddenMethodReturnClass = testClassLoader.loadClass(HiddenMethodReturn.class.getName());
    Class hiddenMethodParameterClass = testClassLoader.loadClass(HiddenMethodParameter.class.getName());

    Injector injector = Guice.createInjector(noopInterceptorModule);

    Class hiddenClass = testClassLoader.loadClass(Hidden.class.getName());
    Constructor ctor = hiddenClass.getDeclaredConstructor();

    ctor.setAccessible(true);

    // don't use bridging for proxies with private parameters
    Object o1 = injector.getInstance(hiddenMethodParameterClass);
    o1.getClass().getDeclaredMethod("method", hiddenClass).invoke(o1, ctor.newInstance());

    // don't use bridging for proxies with private return types
    Object o2 = injector.getInstance(hiddenMethodReturnClass);
    o2.getClass().getDeclaredMethod("method").invoke(o2);
  }

  // This tests for a situation where a osgi bundle contains a version of guice.  When guice
  // generates a fast class it will use a bridge classloader
  public void testFastClassUsesBridgeClassloader() throws Throwable {
    Injector injector = Guice.createInjector();
    // These classes are all in the same classloader as guice itself, so other than the private one
    // they can all be fast class invoked
    injector.getInstance(PublicInject.class).assertIsFastClassInvoked();
    injector.getInstance(ProtectedInject.class).assertIsFastClassInvoked();
    injector.getInstance(PackagePrivateInject.class).assertIsFastClassInvoked();
    injector.getInstance(PrivateInject.class).assertIsReflectionInvoked();

    // This classloader will load the types in an loader with a different version of guice/cglib
    // this prevents the use of fastclass for all but the public types (where the bridge
    // classloader can be used).
    MultipleVersionsOfGuiceClassLoader fakeLoader = new MultipleVersionsOfGuiceClassLoader();
    injector.getInstance(fakeLoader.loadLogCreatorType(PublicInject.class))
        .assertIsFastClassInvoked();
    injector.getInstance(fakeLoader.loadLogCreatorType(ProtectedInject.class))
        .assertIsReflectionInvoked();
    injector.getInstance(fakeLoader.loadLogCreatorType(PackagePrivateInject.class))
        .assertIsReflectionInvoked();
    injector.getInstance(fakeLoader.loadLogCreatorType(PrivateInject.class))
        .assertIsReflectionInvoked();
  }

  // This classloader simulates an OSGI environment where a bundle has a conflicting definition of
  // cglib (or guice).  This is sort of the opposite of the BridgeClassloader and is meant to test
  // its use.
  static class MultipleVersionsOfGuiceClassLoader extends URLClassLoader  {
    MultipleVersionsOfGuiceClassLoader() {
      this((URLClassLoader) MultipleVersionsOfGuiceClassLoader.class.getClassLoader());
    }

    MultipleVersionsOfGuiceClassLoader(URLClassLoader classloader) {
      super(classloader.getURLs(), classloader);
    }

    public Class<? extends LogCreator> loadLogCreatorType(Class cls)
        throws ClassNotFoundException {
      return loadClass(cls.getName()).asSubclass(LogCreator.class);
    }

    /**
     * Classic parent-delegating classloaders are meant to override findClass.
     * However, non-delegating classloaders (as used in OSGi) instead override
     * loadClass to provide support for "class-space" separation.
     */
    @Override
    protected Class<?> loadClass(final String name, final boolean resolve)
        throws ClassNotFoundException {

      synchronized (this) {
        // check our local cache to avoid duplicates
        final Class<?> clazz = findLoadedClass(name);
        if (clazz != null) {
          return clazz;
        }
      }

      if (name.startsWith("java.")
          || name.startsWith("javax.")
          || name.equals(LogCreator.class.getName())
          || (!name.startsWith("com.google.inject.")
              && !name.contains(".cglib.")
              && !name.startsWith("com.googlecode.guice"))) {

        // standard parent delegation
        return super.loadClass(name, resolve);

      } else {
        // load a new copy of the class
        final Class<?> clazz = findClass(name);
        if (resolve) {
          resolveClass(clazz);
        }
        return clazz;
      }
    }
  }

  public static class LogCreator {
    final Throwable caller;
    public LogCreator() {
      this.caller = new Throwable();
    }

    void assertIsFastClassInvoked() throws Throwable {
      // 2 because the first 2 elements are
      // LogCreator.<init>()
      // Subclass.<init>()
      if (!caller.getStackTrace()[2].getClassName().contains("$$FastClassByGuice$$")) {
        throw new AssertionError("Caller was not FastClass").initCause(caller);
      }
    }

    void assertIsReflectionInvoked() throws Throwable {
      // Scan for a call to Constructor.newInstance, but stop if we see the test itself.
      for (StackTraceElement element : caller.getStackTrace()) {
        if (element.getClassName().equals(BytecodeGenTest.class.getName())) {
          // break when we hit the test method.
          break;
        }
        if (element.getClassName().equals(Constructor.class.getName())
            && element.getMethodName().equals("newInstance")) {
          return;
        }
      }
      throw new AssertionError("Caller was not Constructor.newInstance").initCause(caller);
    }
  }

  public static class PublicInject extends LogCreator {
    @Inject public PublicInject() {}
  }

  static class PackagePrivateInject extends LogCreator {
    @Inject PackagePrivateInject() {}
  }

  protected static class ProtectedInject extends LogCreator {
    @Inject protected ProtectedInject() {}
  }

  private static class PrivateInject extends LogCreator {
    @Inject private PrivateInject() {}
  }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java BytecodeGenTest.java source code file:



my book on functional programming

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.