Friday, August 17, 2012

Autobind All Tapestry5 services!

Norman Franke, Dmitry Gusev and a bunch of other guys in the Tapestry5 mailing list show us a very cool way to bind services via package traversal. No more binder declarations for DAO services several miles long.

The technique they showed made me want to smack my older self - Why didn't you think of that!? This autobind technique basically just needs a bit of planning - a "convention" if you will. The idea is to put the "implementation" package as a folder below your DAO interfaces. Typically, you would append an "Impl" tag to your DAO interfaces so for example: UserDAO = UserDAOImpl and then place them in the correct packages: com.myapp.dao for the DAO interfaces and then com.myapp.dao.impl for the DAO implementations. The rest is done in the AppModule of Tapestry5.

...
public static void Bind(ServiceBinder binder) throws ClassNotFoundException  
{  
   autoBindServices(binder, ProjectDAO.class.getPackage());  
   .....  
}  
private static void autoBindServices(ServiceBinder binder, Package interfacePackage) throws ClassNotFoundException  
{  
  List<Class<?>> interfaces = Utils.getClassesForPackage(interfacePackage.getName());  
  for(Class intf : interfaces)  
  {  
     String className = interfacesPackage.getName() + ".impl." + intf.getSimpleName() + "Impl";  
     try  
     {  
         Class impl = Class.forName(className);  
         binder.bind(intf, impl);  
     }  
     catch(ClassNotFoundException e)  
     {  
         logger.warn("Class not found during autobinding: {}", className);  
     }  
  }  
}
Very cool stuff.

2 comments:

  1. Hi, Jay!

    There's a typo in the code snippet, should be:

    String className = interfacesPackage.getName() + ".impl." + intf.getSimpleName() + "Impl";

    We need just package name, not its toString() presentation which is "package com.x.y.z"

    Will post this to mailing list also.

    ReplyDelete