1d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit/**
2d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit * Copyright (C) 2008 Google Inc.
3d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit *
4d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit * Licensed under the Apache License, Version 2.0 (the "License");
5d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit * you may not use this file except in compliance with the License.
6d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit * You may obtain a copy of the License at
7d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit *
8d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit * http://www.apache.org/licenses/LICENSE-2.0
9d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit *
10d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit * Unless required by applicable law or agreed to in writing, software
11d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit * distributed under the License is distributed on an "AS IS" BASIS,
12d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit * See the License for the specific language governing permissions and
14d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit * limitations under the License.
15d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit */
16d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
17d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitpackage com.googlecode.guice;
18d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
19b7a02b02d81c830d148355c90bc309bcd66fb592sberlinimport static com.google.inject.matcher.Matchers.any;
20b7a02b02d81c830d148355c90bc309bcd66fb592sberlin
21d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitimport com.google.inject.AbstractModule;
22d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitimport com.google.inject.Binder;
23d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitimport com.google.inject.Guice;
24d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitimport com.google.inject.Injector;
25d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitimport com.google.inject.Module;
26a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkitimport com.googlecode.guice.PackageVisibilityTestModule.PublicUserOfPackagePrivate;
27b7a02b02d81c830d148355c90bc309bcd66fb592sberlin
28b7a02b02d81c830d148355c90bc309bcd66fb592sberlinimport junit.framework.TestCase;
29b7a02b02d81c830d148355c90bc309bcd66fb592sberlin
30b7a02b02d81c830d148355c90bc309bcd66fb592sberlinimport org.aopalliance.intercept.MethodInterceptor;
31b7a02b02d81c830d148355c90bc309bcd66fb592sberlinimport org.aopalliance.intercept.MethodInvocation;
32b7a02b02d81c830d148355c90bc309bcd66fb592sberlin
33d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitimport java.io.File;
34d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitimport java.lang.ref.Reference;
35d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitimport java.lang.ref.WeakReference;
361c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlinimport java.lang.reflect.Constructor;
37eb06177abdd178c9cc05312be7147e2ccc20becflimpbizkitimport java.lang.reflect.Method;
38d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitimport java.net.MalformedURLException;
39d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitimport java.net.URL;
40d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitimport java.net.URLClassLoader;
418743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruberimport java.util.concurrent.TimeoutException;
42d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
43d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit/**
4446db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit * This test is in a separate package so we can test package-level visibility
4546db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit * with confidence.
4646db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit *
47d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit * @author mcculls@gmail.com (Stuart McCulloch)
48d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit */
49d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkitpublic class BytecodeGenTest extends TestCase {
50d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
513697a672aa70dc38d89270b6ac434cff16c053d8limpbizkit  private final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
523697a672aa70dc38d89270b6ac434cff16c053d8limpbizkit
53d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  private final Module interceptorModule = new AbstractModule() {
54d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    protected void configure() {
55d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      bindInterceptor(any(), any(), new MethodInterceptor() {
56d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        public Object invoke(MethodInvocation chain)
57d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit            throws Throwable {
58d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit          return chain.proceed() + " WORLD";
59d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        }
60d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      });
61d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    }
62d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  };
63d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
641c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin  private final Module noopInterceptorModule = new AbstractModule() {
651c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin      protected void configure() {
661c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin        bindInterceptor(any(), any(), new MethodInterceptor() {
671c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin          public Object invoke(MethodInvocation chain)
681c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin              throws Throwable {
691c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin            return chain.proceed();
701c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin          }
711c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin        });
721c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin      }
731c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    };
741c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
7585fa885aecb69448bd624a56c8ea3bcb3c84ef1flimpbizkit  public void testPackageVisibility() {
76a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit    Injector injector = Guice.createInjector(new PackageVisibilityTestModule());
77a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit    injector.getInstance(PublicUserOfPackagePrivate.class); // This must pass.
78a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit  }
79a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit
80a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit  public void testInterceptedPackageVisibility() {
81a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit    Injector injector = Guice.createInjector(interceptorModule, new PackageVisibilityTestModule());
8285fa885aecb69448bd624a56c8ea3bcb3c84ef1flimpbizkit    injector.getInstance(PublicUserOfPackagePrivate.class); // This must pass.
8385fa885aecb69448bd624a56c8ea3bcb3c84ef1flimpbizkit  }
848743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber
85a102c17638ec586de3d6930c8ef794c751d157d6sberlin  public void testEnhancerNaming() {
86a102c17638ec586de3d6930c8ef794c751d157d6sberlin    Injector injector = Guice.createInjector(interceptorModule, new PackageVisibilityTestModule());
87a102c17638ec586de3d6930c8ef794c751d157d6sberlin    PublicUserOfPackagePrivate pupp = injector.getInstance(PublicUserOfPackagePrivate.class);
88a102c17638ec586de3d6930c8ef794c751d157d6sberlin    assertTrue(pupp.getClass().getName().startsWith(
89a102c17638ec586de3d6930c8ef794c751d157d6sberlin        PublicUserOfPackagePrivate.class.getName() + "$$EnhancerByGuice$$"));
90a102c17638ec586de3d6930c8ef794c751d157d6sberlin  }
918743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber
92ec76179f50f9d8c340b311c6b019c00526566b66sberlin  // TODO(sameb): Figure out how to test FastClass naming tests.
9385fa885aecb69448bd624a56c8ea3bcb3c84ef1flimpbizkit
94d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  /**
95d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit   * Custom URL classloader with basic visibility rules
96d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit   */
97d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  static class TestVisibilityClassLoader
98d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      extends URLClassLoader {
99d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
1001c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    boolean hideInternals;
1011c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
1021c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    public TestVisibilityClassLoader(boolean hideInternals) {
103d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      super(new URL[0]);
104d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
1051c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin      this.hideInternals = hideInternals;
1061c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
107d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      final String[] classpath = System.getProperty("java.class.path").split(File.pathSeparator);
108d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      for (final String element : classpath) {
109d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        try {
110d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit          // is it a remote/local URL?
111d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit          addURL(new URL(element));
112d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        } catch (final MalformedURLException e1) {
113d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit          try {
114d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit            // nope - perhaps it's a filename?
115d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit            addURL(new File(element).toURI().toURL());
116d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit          } catch (final MalformedURLException e2) {
117d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit            throw new RuntimeException(e1);
118d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit          }
119d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        }
120d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      }
121d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    }
122d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
123d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    /**
124d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit     * Classic parent-delegating classloaders are meant to override findClass.
125d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit     * However, non-delegating classloaders (as used in OSGi) instead override
126d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit     * loadClass to provide support for "class-space" separation.
127d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit     */
128d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    @Override
129d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    protected Class<?> loadClass(final String name, final boolean resolve)
130d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        throws ClassNotFoundException {
131d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
132eb06177abdd178c9cc05312be7147e2ccc20becflimpbizkit      synchronized (this) {
133eb06177abdd178c9cc05312be7147e2ccc20becflimpbizkit        // check our local cache to avoid duplicates
134eb06177abdd178c9cc05312be7147e2ccc20becflimpbizkit        final Class<?> clazz = findLoadedClass(name);
135eb06177abdd178c9cc05312be7147e2ccc20becflimpbizkit        if (clazz != null) {
136eb06177abdd178c9cc05312be7147e2ccc20becflimpbizkit          return clazz;
137eb06177abdd178c9cc05312be7147e2ccc20becflimpbizkit        }
138eb06177abdd178c9cc05312be7147e2ccc20becflimpbizkit      }
139eb06177abdd178c9cc05312be7147e2ccc20becflimpbizkit
140d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      if (name.startsWith("java.")) {
141d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
142d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        // standard bootdelegation of java.*
143d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        return super.loadClass(name, resolve);
144d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
145eb06177abdd178c9cc05312be7147e2ccc20becflimpbizkit      } else if (!name.contains(".internal.") && !name.contains(".cglib.")) {
146d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
147d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        /*
148d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit         * load public and test classes directly from the classpath - we don't
149d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit         * delegate to our parent because then the loaded classes would also be
150d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit         * able to see private internal Guice classes, as they are also loaded
151d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit         * by the parent classloader.
152d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit         */
153d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        final Class<?> clazz = findClass(name);
154d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        if (resolve) {
155d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit          resolveClass(clazz);
156d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        }
157d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        return clazz;
158d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      }
159d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
160d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      // hide internal non-test classes
1611c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin      if (hideInternals) {
1621c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin        throw new ClassNotFoundException();
1631c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin      }
1641c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin      return super.loadClass(name, resolve);
165d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    }
166d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  }
167d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
168e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit  /** as loaded by another class loader */
169e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit  private Class<ProxyTest> proxyTestClass;
170e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit  private Class<ProxyTestImpl> realClass;
171e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit  private Module testModule;
172e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit
173e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit  @SuppressWarnings("unchecked")
174e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit  protected void setUp() throws Exception {
175e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit    super.setUp();
176e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit
1771c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    ClassLoader testClassLoader = new TestVisibilityClassLoader(true);
178e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit    proxyTestClass = (Class<ProxyTest>) testClassLoader.loadClass(ProxyTest.class.getName());
179e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit    realClass = (Class<ProxyTestImpl>) testClassLoader.loadClass(ProxyTestImpl.class.getName());
180e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit
181e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit    testModule = new AbstractModule() {
182e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit      public void configure() {
183e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit        bind(proxyTestClass).to(realClass);
184e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit      }
185e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit    };
186e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit  }
187e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit
188d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  interface ProxyTest {
189d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    String sayHello();
190d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  }
191d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
192d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  /**
193d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit   * Note: this class must be marked as public or protected so that the Guice
194d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit   * custom classloader will intercept it. Private and implementation classes
195d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit   * are not intercepted by the custom classloader.
196ec76179f50f9d8c340b311c6b019c00526566b66sberlin   *
19746db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit   * @see com.google.inject.internal.BytecodeGen.Visibility
198d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit   */
199d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  public static class ProxyTestImpl implements ProxyTest {
200d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
201d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    static {
202eb06177abdd178c9cc05312be7147e2ccc20becflimpbizkit      //System.out.println(ProxyTestImpl.class.getClassLoader());
203d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    }
204d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
205d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    public String sayHello() {
206d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      return "HELLO";
207d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    }
208d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  }
209d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
210e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit  public void testProxyClassLoading() throws Exception {
211e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit    Object testObject = Guice.createInjector(interceptorModule, testModule)
212e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit        .getInstance(proxyTestClass);
213d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
214e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit    // verify method interception still works
215e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit    Method m = realClass.getMethod("sayHello");
216e731d19e9286db34e12c13e73e060e3bfe879837limpbizkit    assertEquals("HELLO WORLD", m.invoke(testObject));
217d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  }
218d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
219a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit  public void testSystemClassLoaderIsUsedIfProxiedClassUsesIt() {
220d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    ProxyTest testProxy = Guice.createInjector(interceptorModule, new Module() {
221d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      public void configure(Binder binder) {
222d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit        binder.bind(ProxyTest.class).to(ProxyTestImpl.class);
223d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      }
224d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    }).getInstance(ProxyTest.class);
225d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
2263697a672aa70dc38d89270b6ac434cff16c053d8limpbizkit    if (ProxyTest.class.getClassLoader() == systemClassLoader) {
2273697a672aa70dc38d89270b6ac434cff16c053d8limpbizkit      assertSame(testProxy.getClass().getClassLoader(), systemClassLoader);
2283697a672aa70dc38d89270b6ac434cff16c053d8limpbizkit    } else {
2293697a672aa70dc38d89270b6ac434cff16c053d8limpbizkit      assertNotSame(testProxy.getClass().getClassLoader(), systemClassLoader);
2303697a672aa70dc38d89270b6ac434cff16c053d8limpbizkit    }
231a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit  }
2328743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber
233a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit  public void testProxyClassUnloading() {
234a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit    Object testObject = Guice.createInjector(interceptorModule, testModule)
235a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit        .getInstance(proxyTestClass);
236a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit    assertNotNull(testObject.getClass().getClassLoader());
2373697a672aa70dc38d89270b6ac434cff16c053d8limpbizkit    assertNotSame(testObject.getClass().getClassLoader(), systemClassLoader);
238a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit
239d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    // take a weak reference to the generated proxy class
240a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit    Reference<Class<?>> clazzRef = new WeakReference<Class<?>>(testObject.getClass());
241d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
242d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    assertNotNull(clazzRef.get());
243d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
244d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    // null the proxy
245a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit    testObject = null;
246d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
247d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    /*
248d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit     * this should be enough to queue the weak reference
249d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit     * unless something is holding onto it accidentally.
250d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit     */
2518743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber    final int MAX_COUNT = 100;
252f7ac6ea677ccfff6c3bec7db1d3621e6b6cf4097sberlin    String[] buf;
253d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    System.gc();
2548743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber    //TODO(cgruber): Use com.google.common.testing.GcFinalization and a countdown latch to un-flake.
2558743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber    for (int count = 0 ; clazzRef.get() != null ; count++) {
2568743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber      buf = new String[8 * 1024 * 1024];
2578743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber      buf = null;
2588743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber      System.gc();
2598743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber      assertTrue("Timeout waiting for class to be unloaded.  This may be a flaky result.",
2608743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber          count <= MAX_COUNT);
2618743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber    }
262d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
26346db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit    // This test could be somewhat flaky when the GC isn't working.
26446db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit    // If it fails, run the test again to make sure it's failing reliably.
2658743a0bb0fb49f30117c846880a7df2e7b36657eChristian Edward Gruber    assertNull("Proxy class was not unloaded.", clazzRef.get());
266d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  }
267a7184cfac7879bace6ea08d67adad86c21f2a19blimpbizkit
268d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  public void testProxyingPackagePrivateMethods() {
269d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    Injector injector = Guice.createInjector(interceptorModule);
2709da27072fad763a3bc2b869d2fd9b772269bdb45limpbizkit    assertEquals("HI WORLD", injector.getInstance(PackageClassPackageMethod.class).sayHi());
2719da27072fad763a3bc2b869d2fd9b772269bdb45limpbizkit    assertEquals("HI WORLD", injector.getInstance(PublicClassPackageMethod.class).sayHi());
27246db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit    assertEquals("HI WORLD", injector.getInstance(ProtectedClassProtectedMethod.class).sayHi());
273d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  }
274d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit
2759da27072fad763a3bc2b869d2fd9b772269bdb45limpbizkit  static class PackageClassPackageMethod {
2769da27072fad763a3bc2b869d2fd9b772269bdb45limpbizkit    String sayHi() {
2779da27072fad763a3bc2b869d2fd9b772269bdb45limpbizkit      return "HI";
2789da27072fad763a3bc2b869d2fd9b772269bdb45limpbizkit    }
2799da27072fad763a3bc2b869d2fd9b772269bdb45limpbizkit  }
2809da27072fad763a3bc2b869d2fd9b772269bdb45limpbizkit
2819da27072fad763a3bc2b869d2fd9b772269bdb45limpbizkit  public static class PublicClassPackageMethod {
282d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    String sayHi() {
283d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit      return "HI";
284d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit    }
285d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit  }
28646db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit
28746db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit  protected static class ProtectedClassProtectedMethod {
28846db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit    protected String sayHi() {
28946db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit      return "HI";
29046db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit    }
29146db36a3269b4f46528470cf70a8d6a04bcc24e4limpbizkit  }
2921c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
2931c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin  static class Hidden {
2941c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin  }
2951c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
2961c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin  public static class HiddenMethodReturn {
2971c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    public Hidden method() {
2981c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin      return new Hidden();
2991c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    }
3001c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin  }
3011c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
3021c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin  public static class HiddenMethodParameter {
3031c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    public void method(Hidden h) {
3041c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    }
3051c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin  }
3061c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
3071c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin  public void testClassLoaderBridging() throws Exception {
3081c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    ClassLoader testClassLoader = new TestVisibilityClassLoader(false);
3091c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
3101c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    Class hiddenMethodReturnClass = testClassLoader.loadClass(HiddenMethodReturn.class.getName());
3111c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    Class hiddenMethodParameterClass = testClassLoader.loadClass(HiddenMethodParameter.class.getName());
3121c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
3131c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    Injector injector = Guice.createInjector(noopInterceptorModule);
3141c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
3151c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    Class hiddenClass = testClassLoader.loadClass(Hidden.class.getName());
3161c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    Constructor ctor = hiddenClass.getDeclaredConstructor();
3171c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
3181c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    ctor.setAccessible(true);
3191c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
3201c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    // don't use bridging for proxies with private parameters
3211c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    Object o1 = injector.getInstance(hiddenMethodParameterClass);
3221c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    o1.getClass().getDeclaredMethod("method", hiddenClass).invoke(o1, ctor.newInstance());
3231c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin
3241c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    // don't use bridging for proxies with private return types
3251c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    Object o2 = injector.getInstance(hiddenMethodReturnClass);
3261c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin    o2.getClass().getDeclaredMethod("method").invoke(o2);
3271c6ff880b9a83a833c6fc5fb4fc0e3a15bfb1f80sberlin  }
328d8a06a4770ba6f6ea74473c8c03df5d56b5e1d1flimpbizkit}
329