From 0c23f613d6dad54b00e0ef4df8db509ba72bca36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Wed, 16 Sep 2015 11:10:54 +0200 Subject: [PATCH] Improved component naming * Setting a component information record's name to null will lead to an anonymous component, while setting it to an empty string will lead to an component whose name is that of its class. * New Anonymous annotation to indicate that a component is meant to be anonymous (conflicts with ParametricComponent or valued Component annotations). --- TODO | 1 - .../java/info/ebenoit/ebul/cmp/Anonymous.java | 21 ++++ .../info/ebenoit/ebul/cmp/ComponentState.java | 2 +- .../ebenoit/ebul/cmp/NewComponentInfo.java | 21 +++- .../ebenoit/ebul/cmp/TestComponentState.java | 26 +++- .../ebul/cmp/TestNewComponentInfo.java | 114 +++++++++++++++--- 6 files changed, 158 insertions(+), 27 deletions(-) create mode 100644 src/main/java/info/ebenoit/ebul/cmp/Anonymous.java diff --git a/TODO b/TODO index bf0ef94..701fbd3 100644 --- a/TODO +++ b/TODO @@ -2,7 +2,6 @@ To Do: * Implement "DriverFor" support * Scanning packages for annotated components * General usage documentation - * Easier anonymous components * Uncouple component-provided names from the library Other ideas (maybe later if needed): diff --git a/src/main/java/info/ebenoit/ebul/cmp/Anonymous.java b/src/main/java/info/ebenoit/ebul/cmp/Anonymous.java new file mode 100644 index 0000000..a13e421 --- /dev/null +++ b/src/main/java/info/ebenoit/ebul/cmp/Anonymous.java @@ -0,0 +1,21 @@ +package info.ebenoit.ebul.cmp; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + + +/** + * Annotation indicating that a component will not have a name. + * + * @author E. BenoƮt + */ +@Retention( RetentionPolicy.RUNTIME ) +@Target( ElementType.TYPE ) +public @interface Anonymous +{ + // EMPTY +} diff --git a/src/main/java/info/ebenoit/ebul/cmp/ComponentState.java b/src/main/java/info/ebenoit/ebul/cmp/ComponentState.java index a78e17a..0f94658 100644 --- a/src/main/java/info/ebenoit/ebul/cmp/ComponentState.java +++ b/src/main/java/info/ebenoit/ebul/cmp/ComponentState.java @@ -84,7 +84,7 @@ public final class ComponentState name = ( (ParametricComponent) component ).getComponentName( ); } else { name = ci.getName( ); - if ( name == null ) { + if ( "".equals( name ) ) { name = component.getClass( ).getSimpleName( ); } } diff --git a/src/main/java/info/ebenoit/ebul/cmp/NewComponentInfo.java b/src/main/java/info/ebenoit/ebul/cmp/NewComponentInfo.java index 5f59bfb..7078bad 100644 --- a/src/main/java/info/ebenoit/ebul/cmp/NewComponentInfo.java +++ b/src/main/java/info/ebenoit/ebul/cmp/NewComponentInfo.java @@ -75,15 +75,22 @@ public final class NewComponentInfo< T > // Sets the new component's name final Component aComp = klass.getAnnotation( Component.class ); - if ( aComp != null && !"".equals( aComp.value( ) ) ) { + final boolean isAnon = klass.isAnnotationPresent( Anonymous.class ); + if ( isAnon ) { if ( ParametricComponent.class.isAssignableFrom( klass ) ) { + throw new ComponentDefinitionException( "parametric component can't be anonymous" ); + } + if ( aComp != null && !"".equals( aComp.value( ) ) ) { + throw new ComponentDefinitionException( "named component can't be anonymous" ); + } + info.setName( null ); + } else if ( aComp != null ) { + if ( !"".equals( aComp.value( ) ) && ParametricComponent.class.isAssignableFrom( klass ) ) { throw new ComponentDefinitionException( "parametric component can't be named" ); } info.setName( aComp.value( ) ); - } else if ( !ParametricComponent.class.isAssignableFrom( klass ) ) { - info.setName( klass.getSimpleName( ) ); } else { - info.setName( null ); + info.setName( "" ); } // Autostart flag @@ -365,7 +372,8 @@ public final class NewComponentInfo< T > * Sets the new component's name * * @param name - * the new component's name + * the new component's name. May be null for an anonymous component or {@code ""} for a + * component whose class name will serve as its name. * @return the current object */ public NewComponentInfo< T > setName( final String name ) @@ -376,7 +384,8 @@ public final class NewComponentInfo< T > /** - * @return the name of the new component + * @return the name of the new component. May be null for an anonymous component or {@code ""} for a + * component whose class name will serve as its name. */ public String getName( ) { diff --git a/src/test/java/info/ebenoit/ebul/cmp/TestComponentState.java b/src/test/java/info/ebenoit/ebul/cmp/TestComponentState.java index c1ecda3..610b230 100644 --- a/src/test/java/info/ebenoit/ebul/cmp/TestComponentState.java +++ b/src/test/java/info/ebenoit/ebul/cmp/TestComponentState.java @@ -71,6 +71,7 @@ public class TestComponentState { private ComponentRegistry registry; + @Override public void setComponentRegistry( ComponentRegistry registry ) { @@ -138,7 +139,6 @@ public class TestComponentState final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( object ); final ComponentState cs = new ComponentState( this.reg , ci ); Assert.assertSame( object , cs.getComponent( ) ); - Assert.assertEquals( "Object" , cs.getName( ) ); } @@ -150,7 +150,6 @@ public class TestComponentState final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( ( ) -> object ); final ComponentState cs = new ComponentState( this.reg , ci ); Assert.assertSame( object , cs.getComponent( ) ); - Assert.assertEquals( "Object" , cs.getName( ) ); } @@ -168,6 +167,29 @@ public class TestComponentState } + /** Test: initialising a {@link ComponentState} with a null name */ + @Test + public void testInitialiseNullName( ) + { + final Object object = new Object( ); + final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( object ); + final ComponentState cs = new ComponentState( this.reg , ci ); + Assert.assertNull( cs.getName( ) ); + } + + + /** Test: initialising a {@link ComponentState} with an automatic name */ + @Test + public void testInitialiseAutoName( ) + { + final Object object = new Object( ); + final NewComponentInfo< Object > ci = new NewComponentInfo< Object >( object ) // + .setName( "" ); + final ComponentState cs = new ComponentState( this.reg , ci ); + Assert.assertEquals( "Object" , cs.getName( ) ); + } + + /** Test: initialising a {@link ComponentState} with a supplied name */ @Test public void testInitialiseWithName( ) diff --git a/src/test/java/info/ebenoit/ebul/cmp/TestNewComponentInfo.java b/src/test/java/info/ebenoit/ebul/cmp/TestNewComponentInfo.java index e534b22..5206ae8 100644 --- a/src/test/java/info/ebenoit/ebul/cmp/TestNewComponentInfo.java +++ b/src/test/java/info/ebenoit/ebul/cmp/TestNewComponentInfo.java @@ -62,6 +62,50 @@ public class TestNewComponentInfo // EMPTY } + /** Test anonymous component */ + @Anonymous + private static class TestCmpAnon + { + // EMPTY + } + + /** Test anonymous component with empty {@link Component} annotation */ + @Anonymous + @Component + private static class TestCmpAnonComponent + { + // EMPTY + } + + /** Test anonymous component that implements {@link ParametricComponent} (invalid!) */ + @Anonymous + private static class TestCmpAnonPN + implements ParametricComponent + { + + @Override + public String getComponentName( ) + { + return null; + } + + } + + /** Test anonymous component that has a specified name (invalid!) */ + @Component( "Fail!" ) + @Anonymous + private static class TestCmpAnonNamed + implements ParametricComponent + { + + @Override + public String getComponentName( ) + { + return null; + } + + } + /** Test component with a parametric name */ private static class TestCmpPN implements ParametricComponent @@ -372,7 +416,7 @@ public class TestNewComponentInfo public void testFromClass1( ) { NewComponentInfo< ? > nci = NewComponentInfo.fromClass( TestCmp1.class ); - assertEquals( "TestCmp1" , nci.getName( ) ); + assertEquals( "" , nci.getName( ) ); assertFalse( nci.getAutostart( ) ); assertTrue( nci.getDependencies( ).isEmpty( ) ); assertNull( nci.getDriverFor( ) ); @@ -412,7 +456,7 @@ public class TestNewComponentInfo public void testFromClass4( ) { NewComponentInfo< ? > nci = NewComponentInfo.fromClass( TestCmp4.class ); - assertEquals( "component name was inherited!" , "TestCmp4" , nci.getName( ) ); + assertNotEquals( "component name was inherited!" , "Test component" , nci.getName( ) ); assertFalse( "autostart state was inherited!" , nci.getAutostart( ) ); HashSet< DependencyInfo > deps = nci.getDependencies( ); assertEquals( 3 , deps.size( ) ); @@ -422,6 +466,49 @@ public class TestNewComponentInfo } + /** Test: {@link NewComponentInfo#fromClass(Class)} on a component class with the {@link Anonymous} annotation */ + @Test + public void testFromClassAnon( ) + { + NewComponentInfo< ? > nci = NewComponentInfo.fromClass( TestCmpAnon.class ); + assertNull( nci.getName( ) ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class with the {@link Anonymous} annotation and an + * empty {@link Component} annotation + */ + @Test + public void testFromClassAnonComponent( ) + { + NewComponentInfo< ? > nci = NewComponentInfo.fromClass( TestCmpAnonComponent.class ); + assertNull( nci.getName( ) ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class with the {@link Anonymous} annotation that + * implements {@link ParametricComponent} + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassAnonPN( ) + { + NewComponentInfo.fromClass( TestCmpAnonPN.class ); + } + + + /** + * Test: {@link NewComponentInfo#fromClass(Class)} on a component class with the {@link Anonymous} annotation and a + * {@link Component} annotation carrying a value + */ + @Test( expected = ComponentDefinitionException.class ) + public void testFromClassAnonNamed( ) + { + NewComponentInfo.fromClass( TestCmpAnonNamed.class ); + } + + /** * Test: {@link NewComponentInfo#fromClass(Class)} on a component class that implements {@link ParametricComponent} */ @@ -429,7 +516,7 @@ public class TestNewComponentInfo public void testFromClassPN1( ) { NewComponentInfo< ? > nci = NewComponentInfo.fromClass( TestCmpPN.class ); - assertNull( nci.getName( ) ); + assertEquals( "" , nci.getName( ) ); } @@ -527,8 +614,7 @@ public class TestNewComponentInfo assertEquals( 1 , deps.size( ) ); assertTrue( deps.contains( expectedDep ) ); - HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci - .getInjectors( ); + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci.getInjectors( ); assertEquals( 1 , injectors.size( ) ); ArrayList< ThrowingBiConsumer< Object , Object > > diList = injectors.get( expectedDep ); assertEquals( 1 , diList.size( ) ); @@ -556,8 +642,7 @@ public class TestNewComponentInfo assertEquals( 1 , deps.size( ) ); assertTrue( deps.contains( expectedDep ) ); - HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci - .getInjectors( ); + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci.getInjectors( ); assertEquals( 1 , injectors.size( ) ); ArrayList< ThrowingBiConsumer< Object , Object > > diList = injectors.get( expectedDep ); assertEquals( 1 , diList.size( ) ); @@ -626,8 +711,7 @@ public class TestNewComponentInfo assertEquals( 1 , deps.size( ) ); assertTrue( deps.contains( expectedDep ) ); - HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci - .getInjectors( ); + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci.getInjectors( ); assertEquals( 1 , injectors.size( ) ); ArrayList< ThrowingBiConsumer< Object , Object > > diList = injectors.get( expectedDep ); assertEquals( 1 , diList.size( ) ); @@ -655,8 +739,7 @@ public class TestNewComponentInfo assertEquals( 1 , deps.size( ) ); assertTrue( deps.contains( expectedDep ) ); - HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci - .getInjectors( ); + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci.getInjectors( ); assertEquals( 1 , injectors.size( ) ); ArrayList< ThrowingBiConsumer< Object , Object > > diList = injectors.get( expectedDep ); assertEquals( 1 , diList.size( ) ); @@ -739,8 +822,7 @@ public class TestNewComponentInfo assertEquals( 1 , deps.size( ) ); assertTrue( deps.contains( expectedDep ) ); - HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci - .getInjectors( ); + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci.getInjectors( ); assertEquals( 1 , injectors.size( ) ); ArrayList< ThrowingBiConsumer< Object , Object > > diList = injectors.get( expectedDep ); assertEquals( 1 , diList.size( ) ); @@ -767,8 +849,7 @@ public class TestNewComponentInfo assertEquals( 1 , deps.size( ) ); assertTrue( deps.contains( expectedDep ) ); - HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci - .getInjectors( ); + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci.getInjectors( ); assertEquals( 1 , injectors.size( ) ); ArrayList< ThrowingBiConsumer< Object , Object > > diList = injectors.get( expectedDep ); assertEquals( 1 , diList.size( ) ); @@ -796,8 +877,7 @@ public class TestNewComponentInfo assertEquals( 1 , deps.size( ) ); assertTrue( deps.contains( expectedDep ) ); - HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci - .getInjectors( ); + HashMap< DependencyInfo , ArrayList< ThrowingBiConsumer< Object , Object > > > injectors = nci.getInjectors( ); assertEquals( 1 , injectors.size( ) ); ArrayList< ThrowingBiConsumer< Object , Object > > diList = injectors.get( expectedDep ); assertEquals( 1 , diList.size( ) );