PageRenderTime 1465ms CodeModel.GetById 27ms RepoModel.GetById 11ms app.codeStats 1ms

/spice-inject/guice-patches/vanilla.test/com/googlecode/guice/BytecodeGenTest.java

https://github.com/peterlynch/spice
Java | 262 lines | 165 code | 39 blank | 58 comment | 11 complexity | b36d476bfc1b10dcfeb0d6830822ad29 MD5 | raw file
  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. package com.googlecode.guice;
  17. import com.google.inject.AbstractModule;
  18. import com.google.inject.Binder;
  19. import com.google.inject.Guice;
  20. import com.google.inject.Injector;
  21. import com.google.inject.Module;
  22. import static com.google.inject.matcher.Matchers.any;
  23. import com.googlecode.guice.PackageVisibilityTestModule.PublicUserOfPackagePrivate;
  24. import java.io.File;
  25. import java.lang.ref.Reference;
  26. import java.lang.ref.WeakReference;
  27. import java.lang.reflect.Method;
  28. import java.net.MalformedURLException;
  29. import java.net.URL;
  30. import java.net.URLClassLoader;
  31. import junit.framework.TestCase;
  32. import org.aopalliance.intercept.MethodInterceptor;
  33. import org.aopalliance.intercept.MethodInvocation;
  34. /**
  35. * This test is in a separate package so we can test package-level visibility
  36. * with confidence.
  37. *
  38. * @author mcculls@gmail.com (Stuart McCulloch)
  39. */
  40. public class BytecodeGenTest extends TestCase {
  41. private final ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
  42. private final Module interceptorModule = new AbstractModule() {
  43. protected void configure() {
  44. bindInterceptor(any(), any(), new MethodInterceptor() {
  45. public Object invoke(MethodInvocation chain)
  46. throws Throwable {
  47. return chain.proceed() + " WORLD";
  48. }
  49. });
  50. }
  51. };
  52. public void testPackageVisibility() {
  53. Injector injector = Guice.createInjector(new PackageVisibilityTestModule());
  54. injector.getInstance(PublicUserOfPackagePrivate.class); // This must pass.
  55. }
  56. public void testInterceptedPackageVisibility() {
  57. Injector injector = Guice.createInjector(interceptorModule, new PackageVisibilityTestModule());
  58. injector.getInstance(PublicUserOfPackagePrivate.class); // This must pass.
  59. }
  60. /**
  61. * Custom URL classloader with basic visibility rules
  62. */
  63. static class TestVisibilityClassLoader
  64. extends URLClassLoader {
  65. public TestVisibilityClassLoader() {
  66. super(new URL[0]);
  67. final String[] classpath = System.getProperty("java.class.path").split(File.pathSeparator);
  68. for (final String element : classpath) {
  69. try {
  70. // is it a remote/local URL?
  71. addURL(new URL(element));
  72. } catch (final MalformedURLException e1) {
  73. try {
  74. // nope - perhaps it's a filename?
  75. addURL(new File(element).toURI().toURL());
  76. } catch (final MalformedURLException e2) {
  77. throw new RuntimeException(e1);
  78. }
  79. }
  80. }
  81. }
  82. /**
  83. * Classic parent-delegating classloaders are meant to override findClass.
  84. * However, non-delegating classloaders (as used in OSGi) instead override
  85. * loadClass to provide support for "class-space" separation.
  86. */
  87. @Override
  88. protected Class<?> loadClass(final String name, final boolean resolve)
  89. throws ClassNotFoundException {
  90. synchronized (this) {
  91. // check our local cache to avoid duplicates
  92. final Class<?> clazz = findLoadedClass(name);
  93. if (clazz != null) {
  94. return clazz;
  95. }
  96. }
  97. if (name.startsWith("java.")) {
  98. // standard bootdelegation of java.*
  99. return super.loadClass(name, resolve);
  100. } else if (!name.contains(".internal.") && !name.contains(".cglib.")) {
  101. /*
  102. * load public and test classes directly from the classpath - we don't
  103. * delegate to our parent because then the loaded classes would also be
  104. * able to see private internal Guice classes, as they are also loaded
  105. * by the parent classloader.
  106. */
  107. final Class<?> clazz = findClass(name);
  108. if (resolve) {
  109. resolveClass(clazz);
  110. }
  111. return clazz;
  112. }
  113. // hide internal non-test classes
  114. throw new ClassNotFoundException();
  115. }
  116. }
  117. /** as loaded by another class loader */
  118. private Class<ProxyTest> proxyTestClass;
  119. private Class<ProxyTestImpl> realClass;
  120. private Module testModule;
  121. @SuppressWarnings("unchecked")
  122. protected void setUp() throws Exception {
  123. super.setUp();
  124. ClassLoader testClassLoader = new TestVisibilityClassLoader();
  125. proxyTestClass = (Class<ProxyTest>) testClassLoader.loadClass(ProxyTest.class.getName());
  126. realClass = (Class<ProxyTestImpl>) testClassLoader.loadClass(ProxyTestImpl.class.getName());
  127. testModule = new AbstractModule() {
  128. public void configure() {
  129. bind(proxyTestClass).to(realClass);
  130. }
  131. };
  132. }
  133. interface ProxyTest {
  134. String sayHello();
  135. }
  136. /**
  137. * Note: this class must be marked as public or protected so that the Guice
  138. * custom classloader will intercept it. Private and implementation classes
  139. * are not intercepted by the custom classloader.
  140. *
  141. * @see com.google.inject.internal.BytecodeGen.Visibility
  142. */
  143. public static class ProxyTestImpl implements ProxyTest {
  144. static {
  145. //System.out.println(ProxyTestImpl.class.getClassLoader());
  146. }
  147. public String sayHello() {
  148. return "HELLO";
  149. }
  150. }
  151. public void testProxyClassLoading() throws Exception {
  152. Object testObject = Guice.createInjector(interceptorModule, testModule)
  153. .getInstance(proxyTestClass);
  154. // verify method interception still works
  155. Method m = realClass.getMethod("sayHello");
  156. assertEquals("HELLO WORLD", m.invoke(testObject));
  157. }
  158. public void testSystemClassLoaderIsUsedIfProxiedClassUsesIt() {
  159. ProxyTest testProxy = Guice.createInjector(interceptorModule, new Module() {
  160. public void configure(Binder binder) {
  161. binder.bind(ProxyTest.class).to(ProxyTestImpl.class);
  162. }
  163. }).getInstance(ProxyTest.class);
  164. if (ProxyTest.class.getClassLoader() == systemClassLoader) {
  165. assertSame(testProxy.getClass().getClassLoader(), systemClassLoader);
  166. } else {
  167. assertNotSame(testProxy.getClass().getClassLoader(), systemClassLoader);
  168. }
  169. }
  170. public void testProxyClassUnloading() {
  171. Object testObject = Guice.createInjector(interceptorModule, testModule)
  172. .getInstance(proxyTestClass);
  173. assertNotNull(testObject.getClass().getClassLoader());
  174. assertNotSame(testObject.getClass().getClassLoader(), systemClassLoader);
  175. // take a weak reference to the generated proxy class
  176. Reference<Class<?>> clazzRef = new WeakReference<Class<?>>(testObject.getClass());
  177. assertNotNull(clazzRef.get());
  178. // null the proxy
  179. testObject = null;
  180. /*
  181. * this should be enough to queue the weak reference
  182. * unless something is holding onto it accidentally.
  183. */
  184. String[] buf;
  185. System.gc();
  186. buf = new String[8 * 1024 * 1024];
  187. buf = null;
  188. System.gc();
  189. buf = new String[8 * 1024 * 1024];
  190. buf = null;
  191. System.gc();
  192. buf = new String[8 * 1024 * 1024];
  193. buf = null;
  194. System.gc();
  195. buf = new String[8 * 1024 * 1024];
  196. buf = null;
  197. System.gc();
  198. // This test could be somewhat flaky when the GC isn't working.
  199. // If it fails, run the test again to make sure it's failing reliably.
  200. assertNull(clazzRef.get());
  201. }
  202. public void testProxyingPackagePrivateMethods() {
  203. Injector injector = Guice.createInjector(interceptorModule);
  204. assertEquals("HI WORLD", injector.getInstance(PackageClassPackageMethod.class).sayHi());
  205. assertEquals("HI WORLD", injector.getInstance(PublicClassPackageMethod.class).sayHi());
  206. assertEquals("HI WORLD", injector.getInstance(ProtectedClassProtectedMethod.class).sayHi());
  207. }
  208. static class PackageClassPackageMethod {
  209. String sayHi() {
  210. return "HI";
  211. }
  212. }
  213. public static class PublicClassPackageMethod {
  214. String sayHi() {
  215. return "HI";
  216. }
  217. }
  218. protected static class ProtectedClassProtectedMethod {
  219. protected String sayHi() {
  220. return "HI";
  221. }
  222. }
  223. }