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