Kontakt

Contribution Methods: Naming Conventions vs Annotations

Posted on Freitag, 5th März, 2010

One of the most powerful concepts of Tapestry IoC is distributed configuration. Every service can have a configuration which can be created across several IoC modules of an application. When a service instance is created all modules are scanned for contribution methods. A contribution method is a module method whose name consists of the prefix contribute and a service id. The service id is used to identify the service to contribute into. There are three different styles of configurations:

  • Unordered Configuration of type java.util.Collection
  • Ordered Configuration of type java.util.List
  • Mapped Configuration of type java.util.Map

When creating a service instance the registry creates an empty configuration and passes it to all the available contribution methods for the service. In the following example you can see a contribution method for the service with the id ApplicationDefaults.

public class AppModule {

   public static void contributeApplicationDefaults(
         MappedConfiguration<String, String> config) {

      config.add(SymbolConstants.PRODUCTION_MODE, "false");
   }
}

This approach works fine because a service id is unique inside the service registry. But identifying services by string ids is often error prone. First if you want to contribute to a configuration of a service you need to know the id of the service. For this purpose you have to look into Tapestry sources or call the ServiceStatus page. Second if you refactor your application and rename an id of a service, your contribution won’t work anymore.

As of version 5.2 (I committed the code today) the annotation @Contribute can be used as an alternative for naming convention for contribution methods. The annotation may be placed on an arbitrary named method of a module to identify this method as a contribution method. The value of the annotation is the type of the service to contribute into. The following example is an alternative for the contribution method above. Note that service with id ApplicationDefaults is of type SymbolProvider.

public class AppModule {

   @Contribute(SymbolProvider.class)
   public static void arbitraryName(
         MappedConfiguration<String, String> config) {

      config.add(SymbolConstants.PRODUCTION_MODE, "false");
   }
}

What if you have several implementations of a service interface? For example Tapestry provides several instance of the service SymbolProvider. In this case you have to disambiguate the service instances with marker annotations. In Tapestry the services ApplicationDefaults and FactoryDefaults are marked with annotations @ApplicationDefaults and @FactoryDefaults. We need to modify our contribution method a little bit in order to identify the service to contribute into. For this purpose the @Marker annotation should be placed on the contributor method. The value of the annotation is the class of a marker annotation which was used to disambiguate the service instance. The following contribution method is meant for the instance of SymbolProvider service marked with the annotation @ApplicationDefaults.

public class AppModule {

   @Contribute(SymbolProvider.class)
   @Marker(ApplicationDefaults.class)
   public static void arbitraryName(
         MappedConfiguration<String, String> config) {

      config.add(SymbolConstants.PRODUCTION_MODE, "false");
   }
}

Enjoy!

 

  1. Igor Drobiazko

 

avatar

Your name

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 

Tapestry 5 Blog - Copyright © 2009 - Eclectic Theme by Your Inspiration Web - Powered by WordPress