/* | |
* Licensed to the Apache Software Foundation (ASF) under one or more | |
* contributor license agreements. See the NOTICE file distributed with | |
* this work for additional information regarding copyright ownership. | |
* The ASF licenses this file to You 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.apache.commons.proxy2; | |
import org.apache.commons.proxy2.provider.BeanProvider; | |
import org.apache.commons.proxy2.provider.ConstantProvider; | |
import org.apache.commons.proxy2.provider.SingletonProvider; | |
import org.apache.commons.proxy2.util.*; | |
import org.junit.Test; | |
import java.io.IOException; | |
import java.io.Serializable; | |
import java.lang.reflect.Method; | |
import java.util.*; | |
import static org.junit.Assert.*; | |
/** | |
* @author James Carman | |
* @since 1.0 | |
*/ | |
@SuppressWarnings("serial") | |
public abstract class AbstractProxyFactoryTestCase extends AbstractTestCase | |
{ | |
//********************************************************************************************************************** | |
// Fields | |
//********************************************************************************************************************** | |
private static final Class<?>[] ECHO_ONLY = new Class[]{Echo.class}; | |
protected final ProxyFactory factory; | |
private static final Class<?>[] COMPARABLE_ONLY = new Class[]{Comparable.class}; | |
//********************************************************************************************************************** | |
// Constructors | |
//********************************************************************************************************************** | |
protected AbstractProxyFactoryTestCase() | |
{ | |
final ServiceLoader<ProxyFactory> serviceLoader = ServiceLoader.load(ProxyFactory.class); | |
Iterator<ProxyFactory> iter = serviceLoader.iterator(); | |
if (iter.hasNext()) | |
{ | |
this.factory = iter.next(); | |
} | |
else | |
{ | |
throw new RuntimeException("Unable to find proxy factory implementation."); | |
} | |
} | |
//********************************************************************************************************************** | |
// Other Methods | |
//********************************************************************************************************************** | |
private ObjectProvider<Echo> createSingletonEcho() | |
{ | |
return new SingletonProvider<Echo>(new BeanProvider<Echo>(EchoImpl.class)); | |
} | |
@Test | |
public void testInterceptorHashCode() | |
{ | |
final Echo proxy = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY); | |
assertEquals(proxy.hashCode(), System.identityHashCode(proxy)); | |
} | |
@Test | |
public void testInvokerHashCode() throws Exception | |
{ | |
final Echo proxy = factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY); | |
assertEquals(proxy.hashCode(), System.identityHashCode(proxy)); | |
} | |
@Test | |
public void testDelegatorHashCode() throws Exception | |
{ | |
final Echo proxy = factory.createDelegatorProxy(new ConstantProvider<Echo>(new EchoImpl()), Echo.class); | |
assertEquals(proxy.hashCode(), System.identityHashCode(proxy)); | |
} | |
@Test | |
public void testInterceptorEquals() | |
{ | |
final Date date = new Date(); | |
final Comparable<?> proxy1 = factory.createInterceptorProxy(date, | |
new NoOpMethodInterceptor(), COMPARABLE_ONLY); | |
final Comparable<?> proxy2 = factory.createInterceptorProxy(date, | |
new NoOpMethodInterceptor(), COMPARABLE_ONLY); | |
assertEquals(proxy1, proxy1); | |
assertFalse(proxy1.equals(proxy2)); | |
assertFalse(proxy2.equals(proxy1)); | |
} | |
@Test | |
public void testInvokerEquals() throws Exception | |
{ | |
final Comparable<?> proxy1 = factory.createInvokerProxy(new InvokerTester(), COMPARABLE_ONLY); | |
final Comparable<?> proxy2 = factory.createInvokerProxy(new InvokerTester(), COMPARABLE_ONLY); | |
assertEquals(proxy1, proxy1); | |
assertFalse(proxy1.equals(proxy2)); | |
assertFalse(proxy2.equals(proxy1)); | |
} | |
@Test | |
public void testDelegatorEquals() throws Exception | |
{ | |
final Date date = new Date(); | |
final Comparable<?> proxy1 = factory.createDelegatorProxy(new ConstantProvider<Date>(date), | |
COMPARABLE_ONLY); | |
final Comparable<?> proxy2 = factory.createDelegatorProxy(new ConstantProvider<Date>(date), | |
COMPARABLE_ONLY); | |
assertEquals(proxy1, proxy1); | |
assertFalse(proxy1.equals(proxy2)); | |
assertFalse(proxy2.equals(proxy1)); | |
} | |
@Test | |
public void testBooleanInterceptorParameter() | |
{ | |
final Echo echo = factory.createInterceptorProxy(new EchoImpl(), new InterceptorTester(), ECHO_ONLY); | |
assertFalse(echo.echoBack(false)); | |
assertTrue(echo.echoBack(true)); | |
} | |
@Test | |
public void testCanProxy() | |
{ | |
assertTrue(factory.canProxy(Echo.class)); | |
assertFalse(factory.canProxy(EchoImpl.class)); | |
} | |
@Test | |
public void testChangingArguments() | |
{ | |
final Echo proxy = factory.createInterceptorProxy(new EchoImpl(), new ChangeArgumentInterceptor(), ECHO_ONLY); | |
assertEquals("something different", proxy.echoBack("whatever")); | |
} | |
@Test | |
public void testCreateDelegatingProxy() | |
{ | |
final Echo echo = factory.createDelegatorProxy(createSingletonEcho(), ECHO_ONLY); | |
echo.echo(); | |
assertEquals("message", echo.echoBack("message")); | |
assertEquals("ab", echo.echoBack("a", "b")); | |
} | |
@Test | |
public void testCreateInterceptorProxy() | |
{ | |
final Echo target = factory.createDelegatorProxy(createSingletonEcho(), ECHO_ONLY); | |
final Echo proxy = factory.createInterceptorProxy(target, new SuffixInterceptor(" suffix"), ECHO_ONLY); | |
proxy.echo(); | |
assertEquals("message suffix", proxy.echoBack("message")); | |
} | |
@Test | |
public void testDelegatingProxyClassCaching() throws Exception | |
{ | |
final Echo proxy1 = factory.createDelegatorProxy(new ConstantProvider<Echo>(new EchoImpl()), Echo.class); | |
final Echo proxy2 = factory.createDelegatorProxy(new ConstantProvider<Echo>(new EchoImpl()), Echo.class); | |
assertNotSame(proxy1, proxy2); | |
assertSame(proxy1.getClass(), proxy2.getClass()); | |
} | |
@Test | |
public void testDelegatingProxyInterfaceOrder() | |
{ | |
final Echo echo = factory.createDelegatorProxy(createSingletonEcho(), Echo.class, DuplicateEcho.class); | |
final List<Class<?>> expected = new LinkedList<Class<?>>(Arrays.<Class<?>>asList(Echo.class, DuplicateEcho.class)); | |
final List<Class<?>> actual = new LinkedList<Class<?>>(Arrays.asList(echo.getClass().getInterfaces())); | |
actual.retainAll(expected); // Doesn't alter order! | |
assertEquals(expected, actual); | |
} | |
@Test | |
public void testDelegatingProxySerializable() throws Exception | |
{ | |
final Echo proxy = factory.createDelegatorProxy(new ConstantProvider<Echo>(new EchoImpl()), Echo.class); | |
assertSerializable(proxy); | |
} | |
@Test | |
public void testInterceptingProxyClassCaching() throws Exception | |
{ | |
final Echo proxy1 = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY); | |
final Echo proxy2 = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY); | |
assertNotSame(proxy1, proxy2); | |
assertSame(proxy1.getClass(), proxy2.getClass()); | |
} | |
@Test | |
public void testInterceptingProxySerializable() throws Exception | |
{ | |
final Echo proxy = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY); | |
assertSerializable(proxy); | |
} | |
@Test(expected = IOException.class) | |
public void testInterceptorProxyWithCheckedException() throws Exception | |
{ | |
final Echo proxy = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY); | |
proxy.ioException(); | |
} | |
@Test(expected = IllegalArgumentException.class) | |
public void testInterceptorProxyWithUncheckedException() throws Exception | |
{ | |
final Echo proxy = factory.createInterceptorProxy(new EchoImpl(), new NoOpMethodInterceptor(), ECHO_ONLY); | |
proxy.illegalArgument(); | |
} | |
@Test | |
public void testInterfaceHierarchies() | |
{ | |
final SortedSet<String> set = factory.createDelegatorProxy(new ConstantProvider<SortedSet<String>>(new TreeSet<String>()), SortedSet.class); | |
set.add("Hello"); | |
} | |
@Test | |
public void testInvokerProxy() throws Exception | |
{ | |
final InvokerTester tester = new InvokerTester(); | |
final Echo echo = factory.createInvokerProxy(tester, ECHO_ONLY); | |
echo.echoBack("hello"); | |
assertEquals(Echo.class.getMethod("echoBack", String.class), tester.method); | |
assertSame(echo, tester.proxy); | |
assertNotNull(tester.args); | |
assertEquals(1, tester.args.length); | |
assertEquals("hello", tester.args[0]); | |
} | |
@Test | |
public void testInvokerProxyClassCaching() throws Exception | |
{ | |
final Echo proxy1 = factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY); | |
final Echo proxy2 = factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY); | |
assertNotSame(proxy1, proxy2); | |
assertSame(proxy1.getClass(), proxy2.getClass()); | |
} | |
@Test | |
public void testInvokerProxySerializable() throws Exception | |
{ | |
final Echo proxy = factory.createInvokerProxy(new InvokerTester(), ECHO_ONLY); | |
assertSerializable(proxy); | |
} | |
@Test | |
public void testMethodInvocationClassCaching() throws Exception | |
{ | |
final InterceptorTester tester = new InterceptorTester(); | |
final EchoImpl target = new EchoImpl(); | |
final Echo proxy1 = factory.createInterceptorProxy(target, tester, ECHO_ONLY); | |
final Echo proxy2 = factory.createInterceptorProxy(target, tester, Echo.class, DuplicateEcho.class); | |
proxy1.echoBack("hello1"); | |
final Class<?> invocationClass1 = tester.invocationClass; | |
proxy2.echoBack("hello2"); | |
assertSame(invocationClass1, tester.invocationClass); | |
} | |
@Test | |
public void testMethodInvocationDuplicateMethods() throws Exception | |
{ | |
final InterceptorTester tester = new InterceptorTester(); | |
final EchoImpl target = new EchoImpl(); | |
final Echo proxy = factory.createInterceptorProxy(target, tester, Echo.class, DuplicateEcho.class); | |
proxy.echoBack("hello"); | |
assertEquals(Echo.class.getMethod("echoBack", String.class), tester.method); | |
} | |
@Test | |
public void testMethodInvocationImplementation() throws Exception | |
{ | |
final InterceptorTester tester = new InterceptorTester(); | |
final EchoImpl target = new EchoImpl(); | |
final Echo proxy = factory.createInterceptorProxy(target, tester, ECHO_ONLY); | |
proxy.echo(); | |
assertNotNull(tester.arguments); | |
assertEquals(0, tester.arguments.length); | |
assertEquals(Echo.class.getMethod("echo"), tester.method); | |
assertSame(proxy, tester.proxy); | |
proxy.echoBack("Hello"); | |
assertNotNull(tester.arguments); | |
assertEquals(1, tester.arguments.length); | |
assertEquals("Hello", tester.arguments[0]); | |
assertEquals(Echo.class.getMethod("echoBack", String.class), tester.method); | |
proxy.echoBack("Hello", "World"); | |
assertNotNull(tester.arguments); | |
assertEquals(2, tester.arguments.length); | |
assertEquals("Hello", tester.arguments[0]); | |
assertEquals("World", tester.arguments[1]); | |
assertEquals(Echo.class.getMethod("echoBack", String.class, String.class), tester.method); | |
} | |
@Test | |
public void testPrimitiveParameter() | |
{ | |
final Echo echo = factory.createDelegatorProxy(createSingletonEcho(), ECHO_ONLY); | |
assertEquals(1, echo.echoBack(1)); | |
} | |
@Test(expected = IOException.class) | |
public void testProxyWithCheckedException() throws Exception | |
{ | |
final Echo proxy = factory.createDelegatorProxy(new ConstantProvider<Echo>(new EchoImpl()), Echo.class); | |
proxy.ioException(); | |
} | |
@Test(expected = IllegalArgumentException.class) | |
public void testProxyWithUncheckedException() throws Exception | |
{ | |
final Echo proxy = factory.createDelegatorProxy(new ConstantProvider<Echo>(new EchoImpl()), Echo.class); | |
proxy.illegalArgument(); | |
} | |
@Test | |
public void testWithNonAccessibleTargetType() | |
{ | |
final Echo proxy = factory.createInterceptorProxy(new PrivateEcho(), new NoOpMethodInterceptor(), ECHO_ONLY); | |
proxy.echo(); | |
} | |
//********************************************************************************************************************** | |
// Inner Classes | |
//********************************************************************************************************************** | |
private static class ChangeArgumentInterceptor implements Interceptor | |
{ | |
public Object intercept(Invocation methodInvocation) throws Throwable | |
{ | |
methodInvocation.getArguments()[0] = "something different"; | |
return methodInvocation.proceed(); | |
} | |
} | |
protected static class InterceptorTester implements Interceptor | |
{ | |
private Object[] arguments; | |
private Method method; | |
private Object proxy; | |
private Class<?> invocationClass; | |
public Object intercept(Invocation methodInvocation) throws Throwable | |
{ | |
arguments = methodInvocation.getArguments(); | |
method = methodInvocation.getMethod(); | |
proxy = methodInvocation.getProxy(); | |
invocationClass = methodInvocation.getClass(); | |
return methodInvocation.proceed(); | |
} | |
} | |
protected static class InvokerTester implements Invoker | |
{ | |
private Object method; | |
private Object[] args; | |
private Object proxy; | |
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable | |
{ | |
this.proxy = proxy; | |
this.method = method; | |
this.args = args; | |
return null; | |
} | |
} | |
protected static class NoOpMethodInterceptor implements Interceptor, Serializable | |
{ | |
public Object intercept(Invocation methodInvocation) throws Throwable | |
{ | |
return methodInvocation.proceed(); | |
} | |
} | |
private static class PrivateEcho extends EchoImpl | |
{ | |
} | |
} |