You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mb...@apache.org on 2010/09/21 18:03:32 UTC
svn commit: r999477 - in
/commons/proper/proxy/branches/version-2.0-work/stub/src:
main/java/org/apache/commons/proxy2/stub/
test/java/org/apache/commons/proxy2/stub/
Author: mbenson
Date: Tue Sep 21 16:03:31 2010
New Revision: 999477
URL: http://svn.apache.org/viewvc?rev=999477&view=rev
Log:
refactor AnnotationFactory to always use a custom java.lang.reflect.Proxy-based ProxyFactory implementation that ensures generated annotation proxies correctly implement equals/hashCode/toString
Added:
commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AnnotationFactoryTest.java
- copied, changed from r997852, commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AbstractAnnotationFactoryTest.java
Removed:
commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AbstractAnnotationFactoryTest.java
commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/CglibAnnotationFactoryTest.java
commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/JavassistAnnotationFactoryTest.java
commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/JdkAnnotationFactoryTest.java
Modified:
commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/AnnotationFactory.java
Modified: commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/AnnotationFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/AnnotationFactory.java?rev=999477&r1=999476&r2=999477&view=diff
==============================================================================
--- commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/AnnotationFactory.java (original)
+++ commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/AnnotationFactory.java Tue Sep 21 16:03:31 2010
@@ -17,40 +17,140 @@
package org.apache.commons.proxy2.stub;
+import java.io.Serializable;
import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import org.apache.commons.lang3.AnnotationUtils;
+import org.apache.commons.proxy2.Interceptor;
+import org.apache.commons.proxy2.Invocation;
import org.apache.commons.proxy2.Invoker;
+import org.apache.commons.proxy2.ObjectProvider;
import org.apache.commons.proxy2.ProxyFactory;
import org.apache.commons.proxy2.ProxyUtils;
+import org.apache.commons.proxy2.impl.AbstractProxyFactory;
/**
* {@link AnnotationFactory} provides a simplified API over {@link StubProxyFactory}
- * to stub a Java {@link Annotation}. Non-stubbed methods including
- * {@link Annotation#annotationType()} will return the values that would have been
+ * to stub a Java {@link Annotation}. Like "real" runtime proxies, instances created via
+ * {@link AnnotationFactory} are {@link Proxy}-based. Non-stubbed methods including
+ * {@link Annotation#annotationType()} will return methods' default values and
+ * {@link Annotation#equals(Object)}/{@link Annotation#hashCode()}/{@link Annotation#toString()}
+ * return values consistent with those methods' documented expectations.
+ *
+ * that would have been
* returned from a "real" annotation whose methods' values were unspecified.
*
* @author Matt Benson
*/
public class AnnotationFactory {
+ //underlying proxyfactory implementation based on org.apache.commons.proxy2.jdk.JdkProxyFactory
+
+ private static class InterceptorInvocationHandler implements InvocationHandler, Serializable {
+ /** Serialization version */
+ private static final long serialVersionUID = 1L;
+
+ private final Object target;
+ private final Interceptor methodInterceptor;
+
+ public InterceptorInvocationHandler(Object target, Interceptor methodInterceptor) {
+ this.target = target;
+ this.methodInterceptor = methodInterceptor;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if (ProxyUtils.isHashCode(method)) {
+ return AnnotationUtils.hashCode((Annotation) proxy);
+ }
+ if (ProxyUtils.isEqualsMethod(method)) {
+ return args[0] instanceof Annotation
+ && AnnotationUtils.equals((Annotation) proxy, (Annotation) args[0]);
+ }
+ if ("toString".equals(method.getName()) && method.getParameterTypes().length == 0) {
+ return AnnotationUtils.toString((Annotation) proxy);
+ }
+ final ReflectionInvocation invocation = new ReflectionInvocation(target, method, args);
+ return methodInterceptor.intercept(invocation);
+ }
+
+ }
+
+ private static class ReflectionInvocation implements Invocation, Serializable {
+ /** Serialization version */
+ private static final long serialVersionUID = 1L;
+
+ private final Method method;
+ private final Object[] arguments;
+ private final Object target;
+
+ public ReflectionInvocation(Object target, Method method, Object[] arguments) {
+ this.method = method;
+ this.arguments = (arguments == null ? ProxyUtils.EMPTY_ARGUMENTS : arguments);
+ this.target = target;
+ }
+
+ public Object[] getArguments() {
+ return arguments;
+ }
+
+ public Method getMethod() {
+ return method;
+ }
+
+ public Object getProxy() {
+ return target;
+ }
+
+ public Object proceed() throws Throwable {
+ try {
+ return method.invoke(target, arguments);
+ } catch (InvocationTargetException e) {
+ throw e.getTargetException();
+ }
+ }
+ }
+
+ private static final ProxyFactory PROXY_FACTORY = new AbstractProxyFactory() {
+
+ public <T> T createInvokerProxy(ClassLoader classLoader, final Invoker invoker, Class<?>... proxyClasses) {
+ throw new UnsupportedOperationException();
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T createInterceptorProxy(ClassLoader classLoader, Object target, Interceptor interceptor,
+ Class<?>... proxyClasses) {
+ return (T) Proxy.newProxyInstance(classLoader, proxyClasses, new InterceptorInvocationHandler(target,
+ interceptor));
+ }
+
+ public <T> T createDelegatorProxy(ClassLoader classLoader, ObjectProvider<?> delegateProvider,
+ Class<?>... proxyClasses) {
+ throw new UnsupportedOperationException();
+ }
+ };
+
private static final Invoker ANNOTATION_INVOKER = new Invoker() {
/** Serialization version */
private static final long serialVersionUID = 1L;
- public Object invoke(Object proxy, Method method, Object[] arguments)
- throws Throwable {
+ public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
Object result = method.getDefaultValue();
return result == null && method.getReturnType().isPrimitive() ? ProxyUtils
- .nullValue(method.getReturnType())
- : result;
+ .nullValue(method.getReturnType()) : result;
}
};
private static final ThreadLocal<Object> CONFIGURER = new ThreadLocal<Object>();
private static final StubConfigurer<Annotation> SHARED_CONFIGURER = new StubConfigurer<Annotation>() {
-
+
/**
* {@inheritDoc}
*/
@@ -80,17 +180,7 @@ public class AnnotationFactory {
* Create a new AnnotationFactory instance.
*/
public AnnotationFactory() {
- this(ProxyUtils.proxyFactory());
- }
-
- /**
- * Create a new AnnotationFactory instance.
- * @param proxyFactory
- */
- public AnnotationFactory(ProxyFactory proxyFactory) {
- super();
- this.proxyFactory = new StubProxyFactory(proxyFactory,
- SHARED_CONFIGURER);
+ this.proxyFactory = new StubProxyFactory(PROXY_FACTORY, SHARED_CONFIGURER);
}
/**
@@ -99,14 +189,12 @@ public class AnnotationFactory {
* @param configurer
* @return stubbed annotation proxy
*/
- public <A extends Annotation> A create(
- StubConfigurer<A> configurer) {
+ public <A extends Annotation> A create(StubConfigurer<A> configurer) {
@SuppressWarnings("unchecked")
- final A result = (A) createInternal(Thread.currentThread()
- .getContextClassLoader(), configurer);
+ final A result = (A) createInternal(Thread.currentThread().getContextClassLoader(), configurer);
return result;
}
-
+
/**
* Create an annotation of the type supported by <code>configurer</code> in the specified classpath.
* @param <A>
@@ -114,13 +202,12 @@ public class AnnotationFactory {
* @param configurer
* @return stubbed annotation proxy
*/
- public <A extends Annotation> A create(ClassLoader classLoader,
- StubConfigurer<A> configurer) {
+ public <A extends Annotation> A create(ClassLoader classLoader, StubConfigurer<A> configurer) {
@SuppressWarnings("unchecked")
final A result = (A) createInternal(classLoader, configurer);
return result;
}
-
+
/**
* Create an annotation of <code>annotationType</code> with fully default behavior.
* @param <A>
@@ -130,8 +217,7 @@ public class AnnotationFactory {
*/
public <A extends Annotation> A create(Class<A> annotationType) {
@SuppressWarnings("unchecked")
- final A result = (A) createInternal(Thread.currentThread().getContextClassLoader(),
- annotationType);
+ final A result = (A) createInternal(Thread.currentThread().getContextClassLoader(), annotationType);
return result;
}
@@ -142,21 +228,18 @@ public class AnnotationFactory {
* @param annotationType
* @return stubbed annotation proxy
*/
- public <A extends Annotation> A create(ClassLoader classLoader,
- Class<A> annotationType) {
+ public <A extends Annotation> A create(ClassLoader classLoader, Class<A> annotationType) {
@SuppressWarnings("unchecked")
final A result = (A) createInternal(classLoader, annotationType);
return result;
}
- private <A extends Annotation> A createInternal(ClassLoader classLoader,
- Object configurer) {
+ private <A extends Annotation> A createInternal(ClassLoader classLoader, Object configurer) {
final Object existingConfigurer = CONFIGURER.get();
try {
CONFIGURER.set(configurer);
@SuppressWarnings("unchecked")
- final A result = (A) proxyFactory.createInvokerProxy(classLoader,
- ANNOTATION_INVOKER, getStubType());
+ final A result = (A) proxyFactory.createInvokerProxy(classLoader, ANNOTATION_INVOKER, getStubType());
return result;
} finally {
if (existingConfigurer == null) {
Copied: commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AnnotationFactoryTest.java (from r997852, commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AbstractAnnotationFactoryTest.java)
URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AnnotationFactoryTest.java?p2=commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AnnotationFactoryTest.java&p1=commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AbstractAnnotationFactoryTest.java&r1=997852&r2=999477&rev=999477&view=diff
==============================================================================
--- commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AbstractAnnotationFactoryTest.java (original)
+++ commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AnnotationFactoryTest.java Tue Sep 21 16:03:31 2010
@@ -19,23 +19,20 @@ package org.apache.commons.proxy2.stub;
import static org.junit.Assert.*;
-import org.apache.commons.proxy2.ProxyFactory;
import org.junit.Before;
import org.junit.Test;
/**
* Test {@link AnnotationFactory}.
*/
-public abstract class AbstractAnnotationFactoryTest {
+public class AnnotationFactoryTest {
private AnnotationFactory annotationFactory;
@Before
public void setUp() {
- annotationFactory = new AnnotationFactory(createProxyFactory());
+ annotationFactory = new AnnotationFactory();
}
- protected abstract ProxyFactory createProxyFactory();
-
@Test
public void testDefaultAnnotation() {
CustomAnnotation customAnnotation = annotationFactory.create(CustomAnnotation.class);