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();