/* * Copyright 2002-2007 the original author or authors. * * 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 org.springframework.aop.framework; import java.io.Serializable; import java.lang.reflect.Modifier; import net.sf.cglib.core.CodeGenerationException; import org.aopalliance.intercept.MethodInterceptor; import org.springframework.aop.ClassFilter; import org.springframework.aop.MethodMatcher; import org.springframework.aop.Pointcut; import org.springframework.aop.interceptor.NopInterceptor; import org.springframework.aop.support.AopUtils; import org.springframework.aop.support.DefaultPointcutAdvisor; import org.springframework.beans.ITestBean; import org.springframework.beans.TestBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Additional and overridden tests for the CGLIB proxy. * * @author Rod Johnson * @author Juergen Hoeller * @author Rob Harrop * @author Ramnivas Laddad */ public class CglibProxyTests extends AbstractAopProxyTests { protected Object createProxy(ProxyCreatorSupport as) { as.setProxyTargetClass(true); Object proxy = as.createAopProxy().getProxy(); assertTrue(AopUtils.isCglibProxy(proxy)); return proxy; } protected AopProxy createAopProxy(AdvisedSupport as) { as.setProxyTargetClass(true); return new Cglib2AopProxy(as); } protected boolean requiresTarget() { return true; } public void testNullConfig() { try { AopProxy aop = new Cglib2AopProxy(null); fail("Shouldn't allow null interceptors"); } catch (IllegalArgumentException ex) { // Ok } } public void testNoTarget() { AdvisedSupport pc = new AdvisedSupport(new Class[]{ITestBean.class}); pc.addAdvice(new NopInterceptor()); try { AopProxy aop = createAopProxy(pc); aop.getProxy(); fail("Shouldn't allow no target with CGLIB proxy"); } catch (AopConfigException ex) { // Ok } } public void testProtectedMethodInvocation() { ProtectedMethodTestBean bean = new ProtectedMethodTestBean(); mockTargetSource.setTarget(bean); AdvisedSupport as = new AdvisedSupport(new Class[]{}); as.setTargetSource(mockTargetSource); as.addAdvice(new NopInterceptor()); AopProxy aop = new Cglib2AopProxy(as); Object proxy = aop.getProxy(); assertTrue(AopUtils.isCglibProxy(proxy)); } public void testProxyCanBeClassNotInterface() throws Exception { TestBean raw = new TestBean(); raw.setAge(32); mockTargetSource.setTarget(raw); AdvisedSupport pc = new AdvisedSupport(); pc.setTargetSource(mockTargetSource); AopProxy aop = new Cglib2AopProxy(pc); Object proxy = aop.getProxy(); assertTrue(AopUtils.isCglibProxy(proxy)); assertTrue(proxy instanceof ITestBean); assertTrue(proxy instanceof TestBean); TestBean tb = (TestBean) proxy; assertEquals(32, tb.getAge()); } public void testCglibProxyingGivesMeaningfulExceptionIfAskedToProxyNonvisibleClass() { class YouCantSeeThis { void hidden() { } } YouCantSeeThis mine = new YouCantSeeThis(); try { ProxyFactory pf = new ProxyFactory(mine); pf.getProxy(); fail("Shouldn't be able to proxy non-visible class with CGLIB"); } catch (AopConfigException ex) { // Check that stack trace is preserved assertTrue(ex.getCause() instanceof CodeGenerationException || ex.getCause() instanceof IllegalArgumentException); // Check that error message is helpful assertTrue(ex.getMessage().indexOf("final") != -1); assertTrue(ex.getMessage().indexOf("visible") != -1); } } public void testMethodInvocationDuringConstructor() { CglibTestBean bean = new CglibTestBean(); bean.setName("Rob Harrop"); AdvisedSupport as = new AdvisedSupport(new Class[]{}); as.setTarget(bean); as.addAdvice(new NopInterceptor()); AopProxy aop = new Cglib2AopProxy(as); CglibTestBean proxy = (CglibTestBean) aop.getProxy(); assertEquals("The name property has been overwritten by the constructor", "Rob Harrop", proxy.getName()); } public void testUnadvisedProxyCreationWithCallDuringConstructor() throws Exception { CglibTestBean target = new CglibTestBean(); target.setName("Rob Harrop"); AdvisedSupport pc = new AdvisedSupport(new Class[]{}); pc.setFrozen(true); pc.setTarget(target); Cglib2AopProxy aop = new Cglib2AopProxy(pc); CglibTestBean proxy = (CglibTestBean) aop.getProxy(); assertNotNull("Proxy should not be null", proxy); assertEquals("Constructor overrode the value of name", "Rob Harrop", proxy.getName()); } public void testMultipleProxies() { TestBean target = new TestBean(); target.setAge(20); TestBean target2 = new TestBean(); target2.setAge(21); ITestBean proxy1 = getAdvisedProxy(target); ITestBean proxy2 = getAdvisedProxy(target2); assertTrue(proxy1.getClass() == proxy2.getClass()); assertEquals(target.getAge(), proxy1.getAge()); assertEquals(target2.getAge(), proxy2.getAge()); } private ITestBean getAdvisedProxy(TestBean target) { ProxyFactory pf = new ProxyFactory(new Class[]{ITestBean.class}); pf.setProxyTargetClass(true); MethodInterceptor advice = new NopInterceptor(); Pointcut pointcut = new Pointcut() { public ClassFilter getClassFilter() { return ClassFilter.TRUE; } public MethodMatcher getMethodMatcher() { return MethodMatcher.TRUE; } public boolean equals(Object obj) { return true; } }; pf.addAdvisor(new DefaultPointcutAdvisor(pointcut, advice)); pf.setTarget(target); pf.setFrozen(true); pf.setExposeProxy(false); return (ITestBean) pf.getProxy(); } public void testMultipleProxiesForIntroductionAdvisor() { TestBean target = new TestBean(); target.setAge(20); TestBean target2 = new TestBean(); target2.setAge(21); ITestBean proxy1 = getIntroductionAdvisorProxy(target); ITestBean proxy2 = getIntroductionAdvisorProxy(target2); assertTrue("Incorrect duplicate creation of proxy classes", proxy1.getClass() == proxy2.getClass()); } private ITestBean getIntroductionAdvisorProxy(TestBean target) { ProxyFactory pf = new ProxyFactory(new Class[]{ITestBean.class}); pf.setProxyTargetClass(true); pf.addAdvisor(new LockMixinAdvisor()); pf.setTarget(target); pf.setFrozen(true); pf.setExposeProxy(false); return (ITestBean) pf.getProxy(); } public void testWithNoArgConstructor() { NoArgCtorTestBean target = new NoArgCtorTestBean("b", 1); target.reset(); mockTargetSource.setTarget(target); AdvisedSupport pc = new AdvisedSupport(new Class[]{}); pc.setTargetSource(mockTargetSource); Cglib2AopProxy aop = new Cglib2AopProxy(pc); aop.setConstructorArguments(new Object[] {"Rob Harrop", new Integer(22)}, new Class[] {String.class, int.class}); NoArgCtorTestBean proxy = (NoArgCtorTestBean) aop.getProxy(); proxy = (NoArgCtorTestBean) aop.getProxy(); assertNotNull("Proxy should be null", proxy); } public void testProxyAProxy() { ITestBean target = new TestBean(); mockTargetSource.setTarget(target); AdvisedSupport as = new AdvisedSupport(new Class[]{}); as.setTargetSource(mockTargetSource); as.addAdvice(new NopInterceptor()); Cglib2AopProxy cglib = new Cglib2AopProxy(as); ITestBean proxy1 = (ITestBean) cglib.getProxy(); mockTargetSource.setTarget(proxy1); as = new AdvisedSupport(new Class[]{}); as.setTargetSource(mockTargetSource); as.addAdvice(new NopInterceptor()); cglib = new Cglib2AopProxy(as); ITestBean proxy2 = (ITestBean) cglib.getProxy(); } public void testProxyAProxyWithAdditionalInterface() { ITestBean target = new TestBean(); mockTargetSource.setTarget(target); AdvisedSupport as = new AdvisedSupport(new Class[]{}); as.setTargetSource(mockTargetSource); as.addAdvice(new NopInterceptor()); as.addInterface(Serializable.class); Cglib2AopProxy cglib = new Cglib2AopProxy(as); ITestBean proxy1 = (ITestBean) cglib.getProxy(); mockTargetSource.setTarget(proxy1); as = new AdvisedSupport(new Class[]{}); as.setTargetSource(mockTargetSource); as.addAdvice(new NopInterceptor()); cglib = new Cglib2AopProxy(as); ITestBean proxy2 = (ITestBean) cglib.getProxy(); assertTrue(proxy2 instanceof Serializable); } public void testExceptionHandling() { ExceptionThrower bean = new ExceptionThrower(); mockTargetSource.setTarget(bean); AdvisedSupport as = new AdvisedSupport(new Class[]{}); as.setTargetSource(mockTargetSource); as.addAdvice(new NopInterceptor()); AopProxy aop = new Cglib2AopProxy(as); ExceptionThrower proxy = (ExceptionThrower) aop.getProxy(); try { proxy.doTest(); } catch (Exception ex) { assertTrue("Invalid exception class", ex instanceof ApplicationContextException); } assertTrue("Catch was not invoked", proxy.isCatchInvoked()); assertTrue("Finally was not invoked", proxy.isFinallyInvoked()); } public void testWithDependencyChecking() { ApplicationContext ctx = new ClassPathXmlApplicationContext("org/springframework/aop/framework/withDependencyChecking.xml"); ctx.getBean("testBean"); } public void testAddAdviceAtRuntime() { TestBean bean = new TestBean(); CountingBeforeAdvice cba = new CountingBeforeAdvice(); ProxyFactory pf = new ProxyFactory(); pf.setTarget(bean); pf.setFrozen(false); pf.setOpaque(false); pf.setProxyTargetClass(true); TestBean proxy = (TestBean) pf.getProxy(); assertTrue(AopUtils.isCglibProxy(proxy)); proxy.getAge(); assertEquals(0, cba.getCalls()); ((Advised) proxy).addAdvice(cba); proxy.getAge(); assertEquals(1, cba.getCalls()); } public void testProxyProtectedMethod() throws Exception { CountingBeforeAdvice advice = new CountingBeforeAdvice(); ProxyFactory proxyFactory = new ProxyFactory(new MyBean()); proxyFactory.addAdvice(advice); proxyFactory.setProxyTargetClass(true); MyBean proxy = (MyBean) proxyFactory.getProxy(); assertEquals(4, proxy.add(1, 3)); assertEquals(1, advice.getCalls("add")); } public static class MyBean { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } protected int add(int x, int y) { return x + y; } } public static class ExceptionThrower { private boolean catchInvoked; private boolean finallyInvoked; public boolean isCatchInvoked() { return catchInvoked; } public boolean isFinallyInvoked() { return finallyInvoked; } public void doTest() throws Exception { try { throw new ApplicationContextException("foo"); } catch (Exception ex) { catchInvoked = true; throw ex; } finally { finallyInvoked = true; } } } public static class HasFinalMethod { public final void foo() { } } }