Author: mbenson
Date: Thu Jun  7 15:26:56 2012
New Revision: 1347680

URL: http://svn.apache.org/viewvc?rev=1347680&view=rev
Log:
delegating annotation stubs

Modified:
    
commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/AnnotationFactory.java
    
commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AnnotationFactoryTest.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=1347680&r1=1347679&r2=1347680&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
 Thu Jun  7 15:26:56 2012
@@ -26,6 +26,7 @@ import java.lang.reflect.Proxy;
 import java.util.Map;
 
 import org.apache.commons.lang3.AnnotationUtils;
+import org.apache.commons.lang3.Validate;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.proxy2.Interceptor;
 import org.apache.commons.proxy2.Invocation;
@@ -34,6 +35,7 @@ import org.apache.commons.proxy2.ObjectP
 import org.apache.commons.proxy2.ProxyFactory;
 import org.apache.commons.proxy2.ProxyUtils;
 import org.apache.commons.proxy2.impl.AbstractProxyFactory;
+import org.apache.commons.proxy2.provider.ConstantProvider;
 
 /**
  * {@link AnnotationFactory} provides a simplified API over {@link 
StubProxyFactory}
@@ -164,6 +166,9 @@ public class AnnotationFactory {
 
         @Override
         protected void configure(A stub) {
+            if (attributes == null) {
+                return;
+            }
             When<Object> bud;
             StubConfiguration dy = this;
             for (Map.Entry<String, Object> attr : attributes.entrySet()) {
@@ -251,61 +256,100 @@ public class AnnotationFactory {
      * @return stubbed annotation proxy
      */
     public <A extends Annotation> A create(StubConfigurer<A> configurer) {
-        @SuppressWarnings("unchecked")
-        final A result = (A) 
createInternal(Thread.currentThread().getContextClassLoader(), configurer);
-        return result;
+        return create(Thread.currentThread().getContextClassLoader(), 
Validate.notNull(configurer, "null configurer"));
+    }
+
+    /**
+     * Create a delegating annotation of the type supported by 
<code>configurer</code>.
+     * @param <A>
+     * @param target not {@code null}
+     * @param configurer not {@code null}
+     * @return stubbed annotation proxy
+     */
+    public <A extends Annotation> A createDelegator(A target, 
StubConfigurer<A> configurer) {
+        return createInternal(Thread.currentThread().getContextClassLoader(),
+            Validate.notNull(target, "null target"), 
Validate.notNull(configurer, "null configurer"));
     }
 
     /**
      * Create an annotation of the type supported by <code>configurer</code> 
in the specified classpath.
      * @param <A>
-     * @param classLoader
-     * @param configurer
+     * @param classLoader not {@code null}
+     * @param configurer not {@code null}
      * @return stubbed annotation proxy
      */
     public <A extends Annotation> A create(ClassLoader classLoader, 
StubConfigurer<A> configurer) {
-        @SuppressWarnings("unchecked")
-        final A result = (A) createInternal(classLoader, configurer);
-        return result;
+        return createInternal(Validate.notNull(classLoader, "null 
classLoader"),
+            null, Validate.notNull(configurer, "null configurer"));
+    }
+
+    /**
+     * Create a delegating annotation of the type supported by 
<code>configurer</code> in the specified classpath.
+     * @param <A>
+     * @param classLoader not {@code null}
+     * @param target not {@code null}
+     * @param configurer not {@code null}
+     * @return stubbed annotation proxy
+     */
+    public <A extends Annotation> A createDelegator(ClassLoader classLoader, A 
target, StubConfigurer<A> configurer) {
+        return createInternal(Validate.notNull(classLoader, "null 
classLoader"),
+            Validate.notNull(target, "null target"), 
Validate.notNull(configurer, "null configurer"));
     }
 
     /**
      * Create an annotation of <code>annotationType</code> with fully default 
behavior.
      * @param <A>
-     * @param classLoader
-     * @param annotationType
+     * @param annotationType not {@code null}
      * @return stubbed annotation proxy
      */
     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(),
+                Validate.notNull(annotationType, "null annotationType"));
         return result;
     }
 
     /**
      * Create an annotation of <code>annotationType</code> with fully default 
behavior.
      * @param <A>
-     * @param classLoader
-     * @param annotationType
+     * @param classLoader not {@code null}
+     * @param annotationType not {@code null}
      * @return stubbed annotation proxy
      */
     public <A extends Annotation> A create(ClassLoader classLoader, Class<A> 
annotationType) {
         @SuppressWarnings("unchecked")
-        final A result = (A) createInternal(classLoader, annotationType);
+        final A result =
+            (A) createInternal(Validate.notNull(classLoader, "null 
classLoader"),
+                Validate.notNull(annotationType, "null annotationType"));
         return result;
     }
 
     /**
      * Create an annotation of <code>annotationType</code> with behavior 
specified by a {@link String}-keyed {@link Map}.
      * @param <A>
-     * @param classLoader
-     * @param annotationType
+     * @param annotationType not {@code null}
      * @param attributes
      * @return stubbed annotation proxy
      */
     public <A extends Annotation> A create(Class<A> annotationType, 
Map<String, Object> attributes) {
-        return attributes == null || attributes.isEmpty() ? 
create(annotationType)
-            : create(new MapBasedAnnotationConfigurer<A>(annotationType, 
attributes));
+        if (attributes == null || attributes.isEmpty()) {
+            return create(annotationType);
+        }
+        return create(new MapBasedAnnotationConfigurer<A>(annotationType, 
attributes));
+    }
+
+    /**
+     * Create a delegating annotation of <code>annotationType</code> with 
behavior specified by a {@link String}-keyed {@link Map}.
+     * @param <A>
+     * @param target not {@code null}
+     * @param attributes
+     * @return stubbed annotation proxy
+     */
+    public <A extends Annotation> A createDelegator(A target, Map<String, 
Object> attributes) {
+        @SuppressWarnings("unchecked")
+        final Class<A> annotationType = (Class<A>) Validate.notNull(target, 
"null target").annotationType();
+        return createDelegator(target, new 
MapBasedAnnotationConfigurer<A>(annotationType, attributes));
     }
 
     /**
@@ -318,11 +362,28 @@ public class AnnotationFactory {
      */
     public <A extends Annotation> A create(ClassLoader classLoader, Class<A> 
annotationType,
         Map<String, Object> attributes) {
-        return attributes == null || attributes.isEmpty() ? 
create(classLoader, annotationType) : create(classLoader,
-            new MapBasedAnnotationConfigurer<A>(annotationType, attributes));
+        return create(classLoader, new 
MapBasedAnnotationConfigurer<A>(annotationType, attributes));
+    }
+
+    /**
+     * Create a delegating annotation of <code>annotationType</code> with 
behavior specified by a {@link String}-keyed {@link Map}.
+     * @param <A>
+     * @param classLoader
+     * @param target
+     * @param attributes
+     * @return stubbed annotation proxy
+     */
+    public <A extends Annotation> A createDelegator(ClassLoader classLoader, A 
target, Map<String, Object> attributes) {
+        @SuppressWarnings("unchecked")
+        final Class<A> annotationType = (Class<A>) Validate.notNull(target, 
"null target").annotationType();
+        return createDelegator(classLoader, target, new 
MapBasedAnnotationConfigurer<A>(annotationType, attributes));
     }
 
     private <A extends Annotation> A createInternal(ClassLoader classLoader, 
Object configurer) {
+        return createInternal(classLoader, null, configurer);
+    }
+
+    private <A extends Annotation> A createInternal(ClassLoader classLoader, A 
target, Object configurer) {
         final Object existingConfigurer = CONFIGURER.get();
         final boolean outerContext = CONTEXT.get() == null;
         try {
@@ -330,8 +391,17 @@ public class AnnotationFactory {
             if (outerContext) {
                 CONTEXT.set(ImmutablePair.of(this, classLoader));
             }
-            @SuppressWarnings("unchecked")
-            final A result = (A) proxyFactory.createInvokerProxy(classLoader, 
ANNOTATION_INVOKER, getStubType());
+            final A result;
+            if (target == null) {
+                @SuppressWarnings("unchecked")
+                A invoker = (A) proxyFactory.createInvokerProxy(classLoader, 
ANNOTATION_INVOKER, getStubType());
+                result = invoker;
+            } else {
+                @SuppressWarnings("unchecked")
+                A delegator =
+                    (A) proxyFactory.createDelegatorProxy(classLoader, new 
ConstantProvider<A>(target), getStubType());
+                result = delegator;
+            }
             return validate(result);
         } finally {
             if (existingConfigurer == null) {

Modified: 
commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AnnotationFactoryTest.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?rev=1347680&r1=1347679&r2=1347680&view=diff
==============================================================================
--- 
commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AnnotationFactoryTest.java
 (original)
+++ 
commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AnnotationFactoryTest.java
 Thu Jun  7 15:26:56 2012
@@ -22,9 +22,13 @@ import static org.junit.Assert.assertEqu
 import static org.junit.Assert.assertNotNull;
 
 import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.commons.lang3.reflect.FieldUtils;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -32,6 +36,7 @@ import org.junit.Test;
  * Test {@link AnnotationFactory}.
  */
 public class AnnotationFactoryTest {
+    @CustomAnnotation(annString = "FOO", finiteValues = { FiniteValues.ONE, 
FiniteValues.TWO, FiniteValues.THREE }, someType = Object.class)
     private AnnotationFactory annotationFactory;
 
     @Before
@@ -167,12 +172,65 @@ public class AnnotationFactoryTest {
         annotationFactory.create(CustomAnnotation.class, attributes);
     }
 
+    @Test
+    public void testDelegator() {
+        final boolean forceAccess = true;
+        final CustomAnnotation sourceAnnotation =
+            FieldUtils.getDeclaredField(AnnotationFactoryTest.class, 
"annotationFactory", forceAccess).getAnnotation(
+                CustomAnnotation.class);
+        assertNotNull(sourceAnnotation);
+        CustomAnnotation stub =
+            annotationFactory.createDelegator(sourceAnnotation, new 
AnnotationConfigurer<CustomAnnotation>() {
+
+                @Override
+                protected void configure(CustomAnnotation stub) {
+                    when(stub.finiteValues()).thenReturn(FiniteValues.ONE);
+                }
+            });
+        assertEquals(CustomAnnotation.class, stub.annotationType());
+        assertEquals(Object.class, stub.someType());
+        assertEquals("FOO", stub.annString());
+        assertArrayEquals(new FiniteValues[] { FiniteValues.ONE }, 
stub.finiteValues());
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testDelegatorMissingTarget() {
+        annotationFactory.createDelegator(null, new 
StubConfigurer<CustomAnnotation>() {
+
+            @Override
+            protected void configure(CustomAnnotation stub) {
+            }
+        });
+    }
+
+    @Test
+    public void testDelegatorWithAttributes() {
+        final boolean forceAccess = true;
+        final CustomAnnotation sourceAnnotation =
+            FieldUtils.getDeclaredField(AnnotationFactoryTest.class, 
"annotationFactory", forceAccess).getAnnotation(
+                CustomAnnotation.class);
+        assertNotNull(sourceAnnotation);
+        Map<String, Object> attributes =
+            Collections.<String, Object> singletonMap("finiteValues", new 
FiniteValues[] { FiniteValues.ONE });
+        CustomAnnotation stub = 
annotationFactory.createDelegator(sourceAnnotation, attributes);
+        assertEquals(CustomAnnotation.class, stub.annotationType());
+        assertEquals(Object.class, stub.someType());
+        assertEquals("FOO", stub.annString());
+        assertArrayEquals(new FiniteValues[] { FiniteValues.ONE }, 
stub.finiteValues());
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testDelegatorWithAttributesMissingTarget() {
+        annotationFactory.createDelegator(null, Collections.<String, Object> 
emptyMap());
+    }
+
     public @interface NestingAnnotation {
         CustomAnnotation child();
 
         String somethingElse();
     }
 
+    @Retention(RetentionPolicy.RUNTIME)
     public @interface CustomAnnotation {
         String annString() default "";
 


Reply via email to