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 2011/02/24 01:03:06 UTC

svn commit: r1073993 - 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: Thu Feb 24 00:03:06 2011
New Revision: 1073993

URL: http://svn.apache.org/viewvc?rev=1073993&view=rev
Log:
acknowledge the invalidity of null annotation members

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/main/java/org/apache/commons/proxy2/stub/StubInterceptor.java
    commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/StubProxyFactory.java
    commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AbstractStubProxyFactoryTest.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=1073993&r1=1073992&r2=1073993&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 Feb 24 00:03:06 2011
@@ -171,7 +171,8 @@ public class AnnotationFactory {
                 try {
                     m = getStubType().getDeclaredMethod(attr.getKey());
                 } catch (Exception e1) {
-                    throw new IllegalArgumentException(String.format("Could not detect annotation attribute %1$s", attr.getKey()));
+                    throw new IllegalArgumentException(String.format("Could not detect annotation attribute %1$s",
+                        attr.getKey()));
                 }
                 try {
                     bud = dy.when(m.invoke(stub));
@@ -191,8 +192,12 @@ public class AnnotationFactory {
 
         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;
+            if (result == null) {
+                if (method.getReturnType().isPrimitive()) {
+                    return ProxyUtils.nullValue(method.getReturnType());
+                }
+            }
+            return result;
         }
     };
 
@@ -229,7 +234,14 @@ public class AnnotationFactory {
      * Create a new AnnotationFactory instance.
      */
     public AnnotationFactory() {
-        this.proxyFactory = new StubProxyFactory(PROXY_FACTORY, sharedConfigurer);
+        this.proxyFactory = new StubProxyFactory(PROXY_FACTORY, sharedConfigurer) {
+            /**
+             * {@inheritDoc}
+             */
+            protected boolean acceptsValue(Method m, Object o) {
+                return !(m.getDeclaringClass().isAnnotation() && o == null);
+            }
+        };
     }
 
     /**
@@ -304,7 +316,8 @@ public class AnnotationFactory {
      * @param attributes
      * @return stubbed annotation proxy
      */
-    public <A extends Annotation> A create(ClassLoader classLoader, Class<A> annotationType, Map<String, Object> attributes) {
+    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));
     }
@@ -319,7 +332,7 @@ public class AnnotationFactory {
             }
             @SuppressWarnings("unchecked")
             final A result = (A) proxyFactory.createInvokerProxy(classLoader, ANNOTATION_INVOKER, getStubType());
-            return result;
+            return validate(result);
         } finally {
             if (existingConfigurer == null) {
                 CONFIGURER.remove();
@@ -332,6 +345,24 @@ public class AnnotationFactory {
         }
     }
 
+    private <A extends Annotation> A validate(A annotation) {
+        Class<?> annotationType = annotation.annotationType();
+        for (Method m : annotationType.getDeclaredMethods()) {
+            Object value = null;
+            Exception caught = null;
+            try {
+                value = m.invoke(annotation);
+            } catch (Exception e) {
+                caught = e;
+            }
+            if (value == null) {
+                throw new IllegalStateException(String.format("annotation %s is missing %s", annotationType,
+                    m.getName()), caught);
+            }
+        }
+        return annotation;
+    }
+
     private static <A extends Annotation> Class<? extends A> getStubType() {
         Object o = CONFIGURER.get();
         if (o instanceof Class<?>) {

Modified: commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/StubInterceptor.java
URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/StubInterceptor.java?rev=1073993&r1=1073992&r2=1073993&view=diff
==============================================================================
--- commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/StubInterceptor.java (original)
+++ commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/StubInterceptor.java Thu Feb 24 00:03:06 2011
@@ -69,9 +69,7 @@ abstract class StubInterceptor implement
          * @return Object
          */
         public Object getResult() throws Throwable {
-            return answer instanceof ObjectProvider<?> ? ((ObjectProvider<?>) answer)
-                    .getObject()
-                    : answer;
+            return answer instanceof ObjectProvider<?> ? ((ObjectProvider<?>) answer).getObject() : answer;
         }
     }
 
@@ -82,8 +80,7 @@ abstract class StubInterceptor implement
          * Create a new Throw instance.
          * @param invocationMatcher
          */
-        Throw(InvocationMatcher invocationMatcher,
-                ObjectProvider<? extends Throwable> throwableProvider) {
+        Throw(InvocationMatcher invocationMatcher, ObjectProvider<? extends Throwable> throwableProvider) {
             super(invocationMatcher);
             this.throwableProvider = throwableProvider;
         }
@@ -120,46 +117,48 @@ abstract class StubInterceptor implement
             }
             return interceptFallback(invocation);
         }
-        RecordedInvocation incoming = new RecordedInvocation(invocation
-                .getMethod(), invocation.getArguments());
+        RecordedInvocation incoming = new RecordedInvocation(invocation.getMethod(), invocation.getArguments());
         synchronized (this) {
             if (currentInvocation == null) {
                 currentInvocation = incoming;
             } else {
-                throw new IllegalStateException("Called " + incoming
-                        + " while stubbing of " + currentInvocation
-                        + " is incomplete.");
+                throw new IllegalStateException("Called " + incoming + " while stubbing of " + currentInvocation
+                    + " is incomplete.");
             }
         }
         return ProxyUtils.nullValue(invocation.getMethod().getReturnType());
     }
 
+    /**
+     * Provide a return value to the currently stubbed method.
+     * @param o {@link ObjectProvider} or hard value
+     */
     void addAnswer(Object o) {
         resultStack.push(validAnswer(o));
     }
 
+    /**
+     * Respond to the currently stubbed method with a thrown exception. 
+     * @param throwableProvider
+     */
     void addThrow(ObjectProvider<? extends Throwable> throwableProvider) {
         resultStack.push(new Throw(currentMatcher(), throwableProvider));
     }
 
     private synchronized InvocationMatcher currentMatcher() {
         if (complete) {
-            throw new IllegalStateException(
-                    "Answers not permitted; stubbing already marked as complete.");
+            throw new IllegalStateException("Answers not permitted; stubbing already marked as complete.");
         }
         if (currentInvocation == null) {
-            throw new IllegalStateException(
-                    "No ongoing stubbing found for any method");
+            throw new IllegalStateException("No ongoing stubbing found for any method");
         }
         try {
             final RecordedInvocation recordedInvocation = currentInvocation;
             return new InvocationMatcher() {
 
                 public boolean matches(Invocation invocation) {
-                    return invocation.getMethod().getName().equals(
-                            recordedInvocation.getInvokedMethod().getName())
-                            && Arrays.equals(invocation.getArguments(),
-                                    recordedInvocation.getArguments());
+                    return invocation.getMethod().getName().equals(recordedInvocation.getInvokedMethod().getName())
+                        && Arrays.equals(invocation.getArguments(), recordedInvocation.getArguments());
                 }
 
             };
@@ -176,11 +175,16 @@ abstract class StubInterceptor implement
     synchronized Answer validAnswer(Object o) {
         if (currentInvocation == null) {
             //fall through and let currentMatcher() throw the exception
-        } else if (o instanceof ObjectProvider<?>) {
-            // give ObjectProviders the benefit of the doubt?
         } else {
             Method m = currentInvocation.getInvokedMethod();
-            if (!TypeUtils.isInstance(o, m.getReturnType())) {
+            boolean valid;
+            if (o instanceof ObjectProvider<?>) {
+                //compiler checked:
+                valid = true;
+            } else {
+                valid = acceptsValue(m, o);
+            }
+            if (!valid) {
                 throw new IllegalArgumentException(String.format("%s does not specify a valid return value for %s", o,
                     m));
             }
@@ -188,6 +192,9 @@ abstract class StubInterceptor implement
         return new Answer(currentMatcher(), o);
     }
 
+    /**
+     * Mark stubbing as complete.
+     */
     void complete() {
         this.complete = true;
     }
@@ -198,6 +205,16 @@ abstract class StubInterceptor implement
      * @return result
      * @throws Throwable
      */
-    protected abstract Object interceptFallback(Invocation invocation)
-            throws Throwable;
+    protected abstract Object interceptFallback(Invocation invocation) throws Throwable;
+
+    /**
+     * Learn whether the specified method accepts the specified return value.
+     * Default implementation defers to {@link TypeUtils#isInstance(Object, java.lang.reflect.Type)}.
+     * @param m
+     * @param o
+     * @return result of compatibility comparison
+     */
+    protected boolean acceptsValue(Method m, Object o) {
+        return TypeUtils.isInstance(o, m.getReturnType());
+    }
 }
\ No newline at end of file

Modified: commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/StubProxyFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/StubProxyFactory.java?rev=1073993&r1=1073992&r2=1073993&view=diff
==============================================================================
--- commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/StubProxyFactory.java (original)
+++ commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/StubProxyFactory.java Thu Feb 24 00:03:06 2011
@@ -17,6 +17,8 @@
 
 package org.apache.commons.proxy2.stub;
 
+import java.lang.reflect.Method;
+
 import org.apache.commons.proxy2.Interceptor;
 import org.apache.commons.proxy2.Invocation;
 import org.apache.commons.proxy2.Invoker;
@@ -166,13 +168,46 @@ public class StubProxyFactory implements
 
     }
 
-    private static class DelegatorInterceptor extends StubInterceptor {
+    /**
+     * Centralize validation of method/return value.  Noop in this implementation.
+     * @param m
+     * @param o
+     * @return <code>true</code>
+     */
+    protected boolean acceptsValue(Method m, Object o) {
+        return true;
+    }    
+
+    private abstract class CentralizedAnswerValidatingStubInterceptor extends StubInterceptor {
+
+        /** Serialization version */
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        protected boolean acceptsValue(Method m, Object o) {
+            return super.acceptsValue(m, o) && StubProxyFactory.this.acceptsValue(m, o);
+        }    
+    }
+
+    /**
+     * {@link StubInterceptor} that wraps an {@link ObjectProvider}.
+     */
+    private class DelegatorInterceptor extends CentralizedAnswerValidatingStubInterceptor {
+
         /** Serialization version */
         private static final long serialVersionUID = 1L;
 
         private ObjectProvider<?> delegateProvider;
 
-        private DelegatorInterceptor(ObjectProvider<?> delegateProvider) {
+        /**
+         * Create a new DelegatorInterceptor instance.
+         *
+         * @param delegateProvider
+         */
+        protected DelegatorInterceptor(ObjectProvider<?> delegateProvider) {
             super();
             this.delegateProvider = delegateProvider;
         }
@@ -185,13 +220,22 @@ public class StubProxyFactory implements
         }
     }
 
-    private static class InterceptorInterceptor extends StubInterceptor {
+    /**
+     * {@link StubInterceptor} that wraps an {@link Interceptor}.
+     */
+    private class InterceptorInterceptor extends CentralizedAnswerValidatingStubInterceptor {
+
         /** Serialization version */
         private static final long serialVersionUID = 1L;
 
         private Interceptor interceptor;
 
-        private InterceptorInterceptor(Interceptor interceptor) {
+        /**
+         * Create a new InterceptorInterceptor instance.
+         *
+         * @param interceptor
+         */
+        protected InterceptorInterceptor(Interceptor interceptor) {
             super();
             this.interceptor = interceptor;
         }
@@ -203,13 +247,22 @@ public class StubProxyFactory implements
         }
     }
 
-    private static class InvokerInterceptor extends StubInterceptor {
+    /**
+     * {@link StubInterceptor} that wraps an {@link Invoker}.
+     */
+    private class InvokerInterceptor extends CentralizedAnswerValidatingStubInterceptor {
+
         /** Serialization version */
         private static final long serialVersionUID = 1L;
 
         private Invoker invoker;
 
-        private InvokerInterceptor(Invoker invoker) {
+        /**
+         * Create a new InvokerInterceptor instance.
+         *
+         * @param invoker
+         */
+        protected InvokerInterceptor(Invoker invoker) {
             super();
             this.invoker = invoker;
         }

Modified: commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AbstractStubProxyFactoryTest.java
URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AbstractStubProxyFactoryTest.java?rev=1073993&r1=1073992&r2=1073993&view=diff
==============================================================================
--- commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AbstractStubProxyFactoryTest.java (original)
+++ commons/proper/proxy/branches/version-2.0-work/stub/src/test/java/org/apache/commons/proxy2/stub/AbstractStubProxyFactoryTest.java Thu Feb 24 00:03:06 2011
@@ -31,6 +31,7 @@ import org.apache.commons.proxy2.ObjectP
 import org.apache.commons.proxy2.ProxyFactory;
 import org.apache.commons.proxy2.invoker.NullInvoker;
 import org.apache.commons.proxy2.provider.BeanProvider;
+import org.apache.commons.proxy2.provider.ConstantProvider;
 import org.apache.commons.proxy2.stub.StubConfigurer;
 import org.apache.commons.proxy2.stub.StubProxyFactory;
 import org.junit.Before;
@@ -281,6 +282,22 @@ public abstract class AbstractStubProxyF
         assertIterator(strings.iterator(), "foo", "bar", "baz");
     }
 
+    @Test
+    public void testDeferredGenericResult() {
+        final ObjectProvider<Iterator<String>> provider =
+            new ConstantProvider<Iterator<String>>(Arrays.asList("foo", "bar", "baz").iterator());
+        ProxyFactory iterableStubFactory = new StubProxyFactory(createParent(), new StubConfigurer<Iterable<String>>() {
+
+            @Override
+            protected void configure(Iterable<String> stub) {
+                when(stub.iterator()).thenAnswer(provider);
+            }
+
+        });
+        Iterable<String> strings = iterableStubFactory.createInvokerProxy(NullInvoker.INSTANCE, Iterable.class);
+        assertIterator(strings.iterator(), "foo", "bar", "baz");
+    }
+
     @Test(expected=IllegalArgumentException.class)
     public void testBadReturnValue() {
         StubProxyFactory factory = new StubProxyFactory(createParent(), new StubConfigurer<AcceptArguments>() {

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=1073993&r1=1073992&r2=1073993&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 Feb 24 00:03:06 2011
@@ -17,7 +17,9 @@
 
 package org.apache.commons.proxy2.stub;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import java.lang.annotation.Annotation;
 import java.util.HashMap;
@@ -37,14 +39,9 @@ public class AnnotationFactoryTest {
         annotationFactory = new AnnotationFactory();
     }
 
-    @Test
+    @Test(expected = IllegalStateException.class)
     public void testDefaultAnnotation() {
-        CustomAnnotation customAnnotation = annotationFactory.create(CustomAnnotation.class);
-        assertNotNull(customAnnotation);
-        assertEquals(CustomAnnotation.class, customAnnotation.annotationType());
-        assertEquals("", customAnnotation.annString());
-        assertEquals(0, customAnnotation.finiteValues().length);
-        assertNull(customAnnotation.someType());
+        annotationFactory.create(CustomAnnotation.class);
     }
 
     @Test
@@ -66,24 +63,6 @@ public class AnnotationFactoryTest {
     }
 
     @Test
-    public void testStubbedAnnotationWithDefaultChild() {
-        NestingAnnotation nestingAnnotation =
-            annotationFactory.create(new AnnotationConfigurer<NestingAnnotation>() {
-                @Override
-                protected void configure(NestingAnnotation stub) {
-                    when(stub.child()).thenReturn(child(CustomAnnotation.class))
-                        .when(stub.somethingElse()).thenReturn("somethingElse");
-                }
-            });
-        assertNotNull(nestingAnnotation);
-        assertNotNull(nestingAnnotation.child());
-        assertEquals("", nestingAnnotation.child().annString());
-        assertEquals(0, nestingAnnotation.child().finiteValues().length);
-        assertEquals(null, nestingAnnotation.child().someType());
-        assertEquals("somethingElse", nestingAnnotation.somethingElse());
-    }
-
-    @Test
     public void testStubbedAnnotationWithConfiguredChild() {
         NestingAnnotation nestingAnnotation = annotationFactory.create(new AnnotationConfigurer<NestingAnnotation>() {
             @Override
@@ -99,7 +78,9 @@ public class AnnotationFactoryTest {
             }
         });
         assertNotNull(nestingAnnotation);
+        assertEquals(NestingAnnotation.class, nestingAnnotation.annotationType());
         assertNotNull(nestingAnnotation.child());
+        assertEquals(CustomAnnotation.class, nestingAnnotation.child().annotationType());
         assertEquals("wow", nestingAnnotation.child().annString());
         assertEquals(3, nestingAnnotation.child().finiteValues().length);
         assertEquals(Class.class, nestingAnnotation.child().someType());
@@ -121,7 +102,7 @@ public class AnnotationFactoryTest {
                             @Override
                             protected void configure(CustomAnnotation stub) {
                                 when(stub.annString()).thenReturn("wow").when(stub.finiteValues())
-                                .thenReturn(FiniteValues.values()).when(stub.someType()).thenReturn(Class.class);
+                                    .thenReturn(FiniteValues.values()).when(stub.someType()).thenReturn(Class.class);
                             }
 
                         })).when(stub.somethingElse()).thenReturn("somethingElse");
@@ -132,14 +113,16 @@ public class AnnotationFactoryTest {
         assertNotNull(outerContainer);
         NestingAnnotation nestingAnnotation = outerContainer.nest();
         assertNotNull(nestingAnnotation);
+        assertEquals(NestingAnnotation.class, nestingAnnotation.annotationType());
         assertNotNull(nestingAnnotation.child());
+        assertEquals(CustomAnnotation.class, nestingAnnotation.child().annotationType());
         assertEquals("wow", nestingAnnotation.child().annString());
         assertEquals(3, nestingAnnotation.child().finiteValues().length);
         assertEquals(Class.class, nestingAnnotation.child().someType());
         assertEquals("somethingElse", nestingAnnotation.somethingElse());
     }
 
-    @Test(expected=IllegalArgumentException.class)
+    @Test(expected = IllegalArgumentException.class)
     public void testCannotConfigureOwnChild() {
         annotationFactory.create(new AnnotationConfigurer<NestingAnnotation>() {
 
@@ -150,7 +133,7 @@ public class AnnotationFactoryTest {
         });
     }
 
-    @Test(expected=IllegalStateException.class)
+    @Test(expected = IllegalStateException.class)
     public void testChildRequiresOngoingStubbing() {
         new AnnotationConfigurer<Annotation>() {
             {
@@ -171,18 +154,19 @@ public class AnnotationFactoryTest {
         attributes.put("someType", Object.class);
         CustomAnnotation customAnnotation = annotationFactory.create(CustomAnnotation.class, attributes);
         assertNotNull(customAnnotation);
+        assertEquals(CustomAnnotation.class, customAnnotation.annotationType());
         assertEquals("foo", customAnnotation.annString());
         assertEquals(3, customAnnotation.finiteValues().length);
         assertEquals(Object.class, customAnnotation.someType());
     }
 
-    @Test(expected=IllegalArgumentException.class)
+    @Test(expected = IllegalArgumentException.class)
     public void testBadAttributes() {
         Map<String, Object> attributes = new HashMap<String, Object>();
         attributes.put("annString", 100);
         annotationFactory.create(CustomAnnotation.class, attributes);
     }
-    
+
     public @interface NestingAnnotation {
         CustomAnnotation child();