Author: mbenson Date: Thu Sep 23 18:23:21 2010 New Revision: 1000566 URL: http://svn.apache.org/viewvc?rev=1000566&view=rev Log: add the ability to program an annotation from (ugh) a string-keyed attribute map
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=1000566&r1=1000565&r2=1000566&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 Sep 23 18:23:21 2010 @@ -23,6 +23,7 @@ import java.lang.reflect.InvocationHandl import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.util.Map; import org.apache.commons.lang3.AnnotationUtils; import org.apache.commons.lang3.Pair; @@ -148,6 +149,41 @@ public class AnnotationFactory { } } + private static class MapBasedAnnotationConfigurer<A extends Annotation> extends StubConfigurer<A> { + final Map<String, Object> attributes; + + /** + * Create a new {...@link MapBasedAnnotationConfigurer} instance. + * @param stubType + * @param attributes + */ + public MapBasedAnnotationConfigurer(Class<A> stubType, Map<String, Object> attributes) { + super(stubType); + this.attributes = attributes; + } + + @Override + protected void configure(A stub) { + When<Object> bud; + StubConfiguration dy = this; + for (Map.Entry<String, Object> attr : attributes.entrySet()) { + Method m; + try { + m = getStubType().getDeclaredMethod(attr.getKey()); + } catch (Exception e1) { + throw new IllegalArgumentException(String.format("Could not detect annotation attribute %1$s", attr.getKey())); + } + try { + bud = dy.when(m.invoke(stub)); + } catch (Exception e) { + //it must have happened on the invoke, so we didn't call when... it shouldn't happen, but we'll simply skip: + continue; + } + dy = bud.thenReturn(attr.getValue()); + } + } + } + private static final Invoker ANNOTATION_INVOKER = new Invoker() { /** Serialization version */ @@ -247,6 +283,32 @@ public class AnnotationFactory { 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 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)); + } + + /** + * Create an annotation of <code>annotationType</code> with behavior specified by a {...@link String}-keyed {...@link Map}. + * @param <A> + * @param classLoader + * @param annotationType + * @param attributes + * @return stubbed annotation proxy + */ + 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)); + } + private <A extends Annotation> A createInternal(ClassLoader classLoader, Object configurer) { final Object existingConfigurer = CONFIGURER.get(); final boolean outerContext = CONTEXT.get() == 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=1000566&r1=1000565&r2=1000566&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 Sep 23 18:23:21 2010 @@ -20,6 +20,8 @@ package org.apache.commons.proxy2.stub; import static org.junit.Assert.*; import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.Map; import org.junit.Before; import org.junit.Test; @@ -161,6 +163,26 @@ public class AnnotationFactoryTest { }; } + @Test + public void testAttributes() { + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put("annString", "foo"); + attributes.put("finiteValues", FiniteValues.values()); + attributes.put("someType", Object.class); + CustomAnnotation customAnnotation = annotationFactory.create(CustomAnnotation.class, attributes); + assertNotNull(customAnnotation); + assertEquals("foo", customAnnotation.annString()); + assertEquals(3, customAnnotation.finiteValues().length); + assertEquals(Object.class, customAnnotation.someType()); + } + + @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();