/** * Return an introduction advisor mixin that allows the AOP proxy to be * cast to ThreadLocalInvokerStats. */ public IntroductionAdvisor getStatsMixin() { DelegatingIntroductionInterceptor dii = new DelegatingIntroductionInterceptor(this); return new DefaultIntroductionAdvisor(dii, ThreadLocalTargetSourceStats.class); }
/** * Return an IntroductionAdvisor that providing a mixin * exposing statistics about the pool maintained by this object. */ public DefaultIntroductionAdvisor getPoolingConfigMixin() { DelegatingIntroductionInterceptor dii = new DelegatingIntroductionInterceptor(this); return new DefaultIntroductionAdvisor(dii, PoolingConfig.class); }
/** * Create a new advisor that will expose the given bean name, introducing * the NamedBean interface to make the bean name accessible without forcing * the target object to be aware of this Spring IoC concept. * @param beanName the bean name to expose */ public static Advisor createAdvisorIntroducingNamedBean(String beanName) { return new DefaultIntroductionAdvisor(new ExposeBeanNameIntroduction(beanName)); }
/** * Cannot add introductions this way unless the advice implements IntroductionInfo. */ @Override public void addAdvice(int pos, Advice advice) throws AopConfigException { Assert.notNull(advice, "Advice must not be null"); if (advice instanceof IntroductionInfo) { // We don't need an IntroductionAdvisor for this kind of introduction: // It's fully self-describing. addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice)); } else if (advice instanceof DynamicIntroductionAdvice) { // We need an IntroductionAdvisor for this kind of introduction. throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor"); } else { addAdvisor(pos, new DefaultPointcutAdvisor(advice)); } }
public DynamicAsyncInterfaceBean() { ProxyFactory pf = new ProxyFactory(new HashMap<>()); DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); if (Future.class.equals(invocation.getMethod().getReturnType())) { return new AsyncResult<>(invocation.getArguments()[0].toString()); } return null; } }); advisor.addInterface(AsyncInterface.class); pf.addAdvisor(advisor); this.proxy = (AsyncInterface) pf.getProxy(); }
public DynamicAsyncMethodsInterfaceBean() { ProxyFactory pf = new ProxyFactory(new HashMap<>()); DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(new MethodInterceptor() { @Override public Object invoke(MethodInvocation invocation) throws Throwable { assertTrue(!Thread.currentThread().getName().equals(originalThreadName)); if (Future.class.equals(invocation.getMethod().getReturnType())) { return new AsyncResult<>(invocation.getArguments()[0].toString()); } return null; } }); advisor.addInterface(AsyncMethodsInterface.class); pf.addAdvisor(advisor); this.proxy = (AsyncMethodsInterface) pf.getProxy(); }
@Test public void testIntroductionMasksTargetImplementation() throws Exception { final long t = 1001L; @SuppressWarnings("serial") class TestII extends DelegatingIntroductionInterceptor implements TimeStamped { @Override public long getTimeStamp() { return t; } } DelegatingIntroductionInterceptor ii = new TestII(); // != t TestBean target = new TargetClass(t + 1); ProxyFactory pf = new ProxyFactory(target); pf.addAdvisor(0, new DefaultIntroductionAdvisor(ii)); TimeStamped ts = (TimeStamped) pf.getProxy(); // From introduction interceptor, not target assertTrue(ts.getTimeStamp() == t); }
@Test public void testUseAsHashKey() { TestBean target1 = new TestBean(); ProxyFactory pf1 = new ProxyFactory(target1); pf1.addAdvice(new NopInterceptor()); ITestBean proxy1 = (ITestBean) createProxy(pf1); TestBean target2 = new TestBean(); ProxyFactory pf2 = new ProxyFactory(target2); pf2.addAdvisor(new DefaultIntroductionAdvisor(new TimestampIntroductionInterceptor())); ITestBean proxy2 = (ITestBean) createProxy(pf2); HashMap<ITestBean, Object> h = new HashMap<>(); Object value1 = "foo"; Object value2 = "bar"; assertNull(h.get(proxy1)); h.put(proxy1, value1); h.put(proxy2, value2); assertEquals(h.get(proxy1), value1); assertEquals(h.get(proxy2), value2); }
@SuppressWarnings("serial") @Test public void testIntroductionInterceptorDoesntReplaceToString() throws Exception { TestBean raw = new TestBean(); assertTrue(! (raw instanceof TimeStamped)); ProxyFactory factory = new ProxyFactory(raw); TimeStamped ts = new SerializableTimeStamped(0); factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts) { @Override public String toString() { throw new UnsupportedOperationException("Shouldn't be invoked"); } })); TimeStamped tsp = (TimeStamped) factory.getProxy(); assertEquals(0, tsp.getTimeStamp()); assertEquals(raw.toString(), tsp.toString()); }
@Test public void testAutomaticInterfaceRecognitionInDelegate() throws Exception { final long t = 1001L; class Tester implements TimeStamped, ITester { @Override public void foo() throws Exception { } @Override public long getTimeStamp() { return t; } } DelegatingIntroductionInterceptor ii = new DelegatingIntroductionInterceptor(new Tester()); TestBean target = new TestBean(); ProxyFactory pf = new ProxyFactory(target); pf.addAdvisor(0, new DefaultIntroductionAdvisor(ii)); //assertTrue(Arrays.binarySearch(pf.getProxiedInterfaces(), TimeStamped.class) != -1); TimeStamped ts = (TimeStamped) pf.getProxy(); assertTrue(ts.getTimeStamp() == t); ((ITester) ts).foo(); ((ITestBean) ts).getAge(); }
/** * Should only be able to introduce interfaces, not classes. */ @Test public void testCannotAddIntroductionAdviceToIntroduceClass() throws Throwable { TestBean target = new TestBean(); target.setAge(21); ProxyFactory pc = new ProxyFactory(target); try { pc.addAdvisor(0, new DefaultIntroductionAdvisor(new TimestampIntroductionInterceptor(), TestBean.class)); fail("Shouldn't be able to add introduction advice that introduces a class, rather than an interface"); } catch (IllegalArgumentException ex) { assertTrue(ex.getMessage().contains("interface")); } // Check it still works: proxy factory state shouldn't have been corrupted ITestBean proxied = (ITestBean) createProxy(pc); assertEquals(target.getAge(), proxied.getAge()); }
@Test public void testIntroductionInterceptorWithDelegation() throws Exception { TestBean raw = new TestBean(); assertTrue(! (raw instanceof TimeStamped)); ProxyFactory factory = new ProxyFactory(raw); TimeStamped ts = mock(TimeStamped.class); long timestamp = 111L; given(ts.getTimeStamp()).willReturn(timestamp); factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts))); TimeStamped tsp = (TimeStamped) factory.getProxy(); assertTrue(tsp.getTimeStamp() == timestamp); }
IntroductionAdvisor ia = new DefaultIntroductionAdvisor(ii); assertTrue(ia.isPerInstance()); pf.addAdvisor(0, ia); pf.addAdvisor(0, new DefaultIntroductionAdvisor(ii)); Object o = pf.getProxy(); assertTrue(!(o instanceof TimeStamped));
@Test public void testIntroductionInterceptorWithInterfaceHierarchy() throws Exception { TestBean raw = new TestBean(); assertTrue(! (raw instanceof SubTimeStamped)); ProxyFactory factory = new ProxyFactory(raw); TimeStamped ts = mock(SubTimeStamped.class); long timestamp = 111L; given(ts.getTimeStamp()).willReturn(timestamp); factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts), SubTimeStamped.class)); SubTimeStamped tsp = (SubTimeStamped) factory.getProxy(); assertTrue(tsp.getTimeStamp() == timestamp); }
@Test public void testIntroductionInterceptorWithSuperInterface() throws Exception { TestBean raw = new TestBean(); assertTrue(! (raw instanceof TimeStamped)); ProxyFactory factory = new ProxyFactory(raw); TimeStamped ts = mock(SubTimeStamped.class); long timestamp = 111L; given(ts.getTimeStamp()).willReturn(timestamp); factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts), TimeStamped.class)); TimeStamped tsp = (TimeStamped) factory.getProxy(); assertTrue(!(tsp instanceof SubTimeStamped)); assertTrue(tsp.getTimeStamp() == timestamp); }
@Test public void testGetsAllInterfaces() throws Exception { // Extend to get new interface class TestBeanSubclass extends TestBean implements Comparable<Object> { @Override public int compareTo(Object arg0) { throw new UnsupportedOperationException("compareTo"); } } TestBeanSubclass raw = new TestBeanSubclass(); ProxyFactory factory = new ProxyFactory(raw); //System.out.println("Proxied interfaces are " + StringUtils.arrayToDelimitedString(factory.getProxiedInterfaces(), ",")); assertEquals("Found correct number of interfaces", 5, factory.getProxiedInterfaces().length); ITestBean tb = (ITestBean) factory.getProxy(); assertThat("Picked up secondary interface", tb, instanceOf(IOther.class)); raw.setAge(25); assertTrue(tb.getAge() == raw.getAge()); long t = 555555L; TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(t); Class<?>[] oldProxiedInterfaces = factory.getProxiedInterfaces(); factory.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class)); Class<?>[] newProxiedInterfaces = factory.getProxiedInterfaces(); assertEquals("Advisor proxies one more interface after introduction", oldProxiedInterfaces.length + 1, newProxiedInterfaces.length); TimeStamped ts = (TimeStamped) factory.getProxy(); assertTrue(ts.getTimeStamp() == t); // Shouldn't fail; ((IOther) ts).absquatulate(); }
@Test public void testRejectsBogusDynamicIntroductionAdviceWithNoAdapter() throws Throwable { TestBean target = new TestBean(); target.setAge(21); ProxyFactory pc = new ProxyFactory(target); pc.addAdvisor(new DefaultIntroductionAdvisor(new DummyIntroductionAdviceImpl(), Comparable.class)); try { // TODO May fail on either call: may want to tighten up definition ITestBean proxied = (ITestBean) createProxy(pc); proxied.getName(); fail("Bogus introduction"); } catch (Exception ex) { // TODO used to catch UnknownAdviceTypeException, but // with CGLIB some errors are in proxy creation and are wrapped // in aspect exception. Error message is still fine. //assertTrue(ex.getMessage().indexOf("ntroduction") > -1); } }
/** * Note that an introduction can't throw an unexpected checked exception, * as it's constrained by the interface. */ @Test public void testIntroductionThrowsUncheckedException() throws Throwable { TestBean target = new TestBean(); target.setAge(21); ProxyFactory pc = new ProxyFactory(target); @SuppressWarnings("serial") class MyDi extends DelegatingIntroductionInterceptor implements TimeStamped { /** * @see test.util.TimeStamped#getTimeStamp() */ @Override public long getTimeStamp() { throw new UnsupportedOperationException(); } } pc.addAdvisor(new DefaultIntroductionAdvisor(new MyDi())); TimeStamped ts = (TimeStamped) createProxy(pc); try { ts.getTimeStamp(); fail("Should throw UnsupportedOperationException"); } catch (UnsupportedOperationException ex) { } }
/** * Check that the introduction advice isn't allowed to introduce interfaces * that are unsupported by the IntroductionInterceptor. */ @Test public void testCannotAddIntroductionAdviceWithUnimplementedInterface() throws Throwable { TestBean target = new TestBean(); target.setAge(21); ProxyFactory pc = new ProxyFactory(target); try { pc.addAdvisor(0, new DefaultIntroductionAdvisor(new TimestampIntroductionInterceptor(), ITestBean.class)); fail("Shouldn't be able to add introduction advice introducing an unimplemented interface"); } catch (IllegalArgumentException ex) { //assertTrue(ex.getMessage().indexOf("ntroduction") > -1); } // Check it still works: proxy factory state shouldn't have been corrupted ITestBean proxied = (ITestBean) createProxy(pc); assertEquals(target.getAge(), proxied.getAge()); }
@Test public void testSerializableDelegatingIntroductionInterceptorSerializable() throws Exception { SerializablePerson serializableTarget = new SerializablePerson(); String name = "Tony"; serializableTarget.setName("Tony"); ProxyFactory factory = new ProxyFactory(serializableTarget); factory.addInterface(Person.class); long time = 1000; TimeStamped ts = new SerializableTimeStamped(time); factory.addAdvisor(new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts))); factory.addAdvice(new SerializableNopInterceptor()); Person p = (Person) factory.getProxy(); assertEquals(name, p.getName()); assertEquals(time, ((TimeStamped) p).getTimeStamp()); Person p1 = (Person) SerializationTestUtils.serializeAndDeserialize(p); assertEquals(name, p1.getName()); assertEquals(time, ((TimeStamped) p1).getTimeStamp()); }