Author: mbenson Date: Thu Sep 23 03:20:41 2010 New Revision: 1000298 URL: http://svn.apache.org/viewvc?rev=1000298&view=rev Log: (re-)add notion of a special Annotation-specific StubConfigurer subclass, AnnotationConfigurer. Not required for use, but if used, provides methods to simplify the creation of nested annotations a bit
Added: commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/AnnotationConfigurer.java (with props) 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 Added: commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/AnnotationConfigurer.java URL: http://svn.apache.org/viewvc/commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/AnnotationConfigurer.java?rev=1000298&view=auto ============================================================================== --- commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/AnnotationConfigurer.java (added) +++ commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/AnnotationConfigurer.java Thu Sep 23 03:20:41 2010 @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.proxy2.stub; + +import java.lang.annotation.Annotation; + +/** + * Special {...@link StubConfigurer} subclass that makes creating nested annotations (somewhat more) convenient. + * + * @param <A> + */ +public abstract class AnnotationConfigurer<A extends Annotation> extends StubConfigurer<A> { + AnnotationFactory annotationFactory; + + /** + * Create a child annotation of the specified type using a StubConfigurer. + * @param <T> + * @param configurer, should not be <code>this</code> + * @return T + * @throws IllegalStateException if called other than when an {...@link AnnotationFactory} is executing {...@link #configure(Object)} + * @throws IllegalArgumentException if <code>configurer == this</code> + */ + protected final <T extends Annotation> T child(StubConfigurer<T> configurer) { + if (configurer == this) { + throw new IllegalArgumentException("An AnnotationConfigurer cannot configure its own child annotation"); + } + return requireAnnotationFactory().create(configurer); + } + + /** + * Create a child annotation of the specified type with default behavior. + * @param <T> + * @param annotationType + * @return T + * @throws IllegalStateException if called other than when an {...@link AnnotationFactory} is executing {...@link #configure(Object)} + */ + protected final <T extends Annotation> T child(Class<T> annotationType) { + return requireAnnotationFactory().create(annotationType); + } + + /** + * Get the registered annotationFactory. + * @return AnnotationFactory + * @throws IllegalStateException if no ongoing annotation stubbing could be detected + */ + synchronized AnnotationFactory requireAnnotationFactory() throws IllegalStateException { + if (annotationFactory == null) { + throw new IllegalStateException("Could not detect ongoing annotation stubbing"); + } + return annotationFactory; + } +} \ No newline at end of file Propchange: commons/proper/proxy/branches/version-2.0-work/stub/src/main/java/org/apache/commons/proxy2/stub/AnnotationConfigurer.java ------------------------------------------------------------------------------ svn:eol-style = native 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=1000298&r1=1000297&r2=1000298&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 03:20:41 2010 @@ -155,7 +155,7 @@ public class AnnotationFactory { private static final ThreadLocal<Object> CONFIGURER = new ThreadLocal<Object>(); - private static final StubConfigurer<Annotation> SHARED_CONFIGURER = new StubConfigurer<Annotation>() { + private final StubConfigurer<Annotation> sharedConfigurer = new StubConfigurer<Annotation>() { /** * {...@inheritdoc} @@ -175,7 +175,21 @@ public class AnnotationFactory { if (o instanceof StubConfigurer<?>) { @SuppressWarnings("unchecked") final StubConfigurer<Annotation> configurer = (StubConfigurer<Annotation>) o; - configurer.configure(requireStubInterceptor(), stub); + boolean deregisterFactory = false; + synchronized (configurer) { + try { + if (configurer instanceof AnnotationConfigurer<?>) { + AnnotationConfigurer<?> annotationConfigurer = (AnnotationConfigurer<?>) configurer; + deregisterFactory = true; + annotationConfigurer.annotationFactory = AnnotationFactory.this; + } + configurer.configure(requireStubInterceptor(), stub); + } finally { + if (deregisterFactory) { + ((AnnotationConfigurer<?>) configurer).annotationFactory = null; + } + } + } } } }; @@ -186,7 +200,7 @@ public class AnnotationFactory { * Create a new AnnotationFactory instance. */ public AnnotationFactory() { - this.proxyFactory = new StubProxyFactory(PROXY_FACTORY, SHARED_CONFIGURER); + this.proxyFactory = new StubProxyFactory(PROXY_FACTORY, sharedConfigurer); } /** 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=1000298&r1=1000297&r2=1000298&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 03:20:41 2010 @@ -19,6 +19,8 @@ package org.apache.commons.proxy2.stub; import static org.junit.Assert.*; +import java.lang.annotation.Annotation; + import org.junit.Before; import org.junit.Test; @@ -36,11 +38,11 @@ public class AnnotationFactoryTest { @Test 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()); - } @Test @@ -54,6 +56,7 @@ public class AnnotationFactoryTest { } }); + assertNotNull(customAnnotation); assertEquals(CustomAnnotation.class, customAnnotation.annotationType()); assertEquals("hey", customAnnotation.annString()); assertArrayEquals(new FiniteValues[] { FiniteValues.ONE, FiniteValues.THREE }, customAnnotation.finiteValues()); @@ -61,21 +64,103 @@ public class AnnotationFactoryTest { } @Test - public void testNestedStubbedAnnotation() { + public void testStubbedAnnotationWithDefaultChild() { NestingAnnotation nestingAnnotation = - annotationFactory.create(new StubConfigurer<NestingAnnotation>() { + annotationFactory.create(new AnnotationConfigurer<NestingAnnotation>() { @Override protected void configure(NestingAnnotation stub) { - when(stub.child()).thenReturn(annotationFactory.create(CustomAnnotation.class)) + 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 + protected void configure(NestingAnnotation stub) { + when(stub.child()).thenReturn(child(new StubConfigurer<CustomAnnotation>() { + + @Override + protected void configure(CustomAnnotation stub) { + when(stub.annString()).thenReturn("wow").when(stub.finiteValues()) + .thenReturn(FiniteValues.values()).when(stub.someType()).thenReturn(Class.class); + } + })).when(stub.somethingElse()).thenReturn("somethingElse"); + } + }); + assertNotNull(nestingAnnotation); + assertNotNull(nestingAnnotation.child()); + assertEquals("wow", nestingAnnotation.child().annString()); + assertEquals(3, nestingAnnotation.child().finiteValues().length); + assertEquals(Class.class, nestingAnnotation.child().someType()); + assertEquals("somethingElse", nestingAnnotation.somethingElse()); + } + + @Test + public void testStubbedAnnotationWithDoubleNesting() { + OuterContainer outerContainer = annotationFactory.create(new AnnotationConfigurer<OuterContainer>() { + + @Override + protected void configure(OuterContainer stub) { + when(stub.nest()).thenReturn(child(new AnnotationConfigurer<NestingAnnotation>() { + + @Override + protected void configure(NestingAnnotation stub) { + when(stub.child()).thenReturn(child(new AnnotationConfigurer<CustomAnnotation>() { + + @Override + protected void configure(CustomAnnotation stub) { + when(stub.annString()).thenReturn("wow").when(stub.finiteValues()) + .thenReturn(FiniteValues.values()).when(stub.someType()).thenReturn(Class.class); + } + + })).when(stub.somethingElse()).thenReturn("somethingElse"); + } + })); + } + }); + assertNotNull(outerContainer); + NestingAnnotation nestingAnnotation = outerContainer.nest(); + assertNotNull(nestingAnnotation); + assertNotNull(nestingAnnotation.child()); + 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) + public void testCannotConfigureOwnChild() { + annotationFactory.create(new AnnotationConfigurer<NestingAnnotation>() { + + @Override + protected void configure(NestingAnnotation stub) { + child(this); + } + }); + } + + @Test(expected=IllegalStateException.class) + public void testChildRequiresOngoingStubbing() { + new AnnotationConfigurer<Annotation>() { + { + child(CustomAnnotation.class); + } + + @Override + protected void configure(Annotation stub) { + } + }; + } + public @interface NestingAnnotation { CustomAnnotation child(); @@ -90,6 +175,10 @@ public class AnnotationFactoryTest { Class<?> someType(); } + public @interface OuterContainer { + NestingAnnotation nest(); + } + public enum FiniteValues { ONE, TWO, THREE; }