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).
This commit is contained in:
Emmanuel BENOîT 2015-09-16 11:10:54 +02:00
parent 36887ae759
commit 0c23f613d6
6 changed files with 158 additions and 27 deletions

1
TODO
View file

@ -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):

View file

@ -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 <a href="mailto:ebenoit@ebenoit.info">E. Benoît</a>
*/
@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.TYPE )
public @interface Anonymous
{
// EMPTY
}

View file

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

View file

@ -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 <code>null</code> 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 <code>null</code> for an anonymous component or {@code ""} for a
* component whose class name will serve as its name.
*/
public String getName( )
{

View file

@ -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 <code>null</code> 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( )

View file

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