We have really been enjoying writing WebWork actions in Groovy. It is a pleasure, and I had a really nice chat with Rod Johnson about how cool it would be to write beans for Spring in Groovy.
We also talked about maybe allowing other languages to be plugged in. Imagine a config such as:
We also talked a little about having Groovy as a config option, and at then Bing Ran emailed the groovy-dev list with a concrete example of how it would look:
import org.springframework.jndi.JndiObjectFactoryBean
import org.springframework.orm.hibernate.LocalSessionFactoryBean
import net.sf.hibernate.dialect.MySQLDialect
import org.apache.commons.dbcp.BasicDataSource
import product.ProductDaoImpl
DataSource myDataSource = new JndiObjectFactoryBean {
jndiName = “java:comp/env/jdbc/myds”
}
DataSource myDataSource2 = new BasicDataSource(”destroy-method”:”close”) {
driverClassName = “org.hsqldb.jdbcDriver”
url = “jdbc:hsqldb:hsql://localhost:9001″
username = “sa”
password = “”
}
SessionFactory mySessionFactory = new LocalSessionFactoryBean {
mappingResources = ["product.hbm.xml"]
hibernateProperties = [hibernate.dialect : MySQLDialect.class]
dataSource = myDataSource2
}
Dao myProductDao = new ProductDaoImpl {
sessionFactory = mySessionFactory
}
The general idea is to use a constructor like structure to describe the wiring of objects.
1. implicit property setting: since we know that an assignment in the Groovy constructor call is to set the property, we save <property> pair, my mind doesn’t need to use any extra energy to interpret it.
2. better list/handling. Groovy list/map construct really shines here, instead of saying:
<property name=”mappingResources”>
<list>
<value>product.hbm.xml</value>
</list>
<list>
<value>customer.hbm.xml</value>
</list>
</property>
I used:
mappingResources = ["product.hbm.xml", "customer.hbm.xml"]
Instead of:
<property name=”hibernateProperties”>
<props>
<prop key=”hibernate.dialect”>net.sf.hibernate.dialect.MySQLDialect</prop>
</props>
<props>
<prop key=”hibernate.someotherkey”>some other value</prop>
</props>
</property>
I did:
hibernateProperties = [
"hibernate.dialect" : MySQLDialect.class,
"hibernate.someotherkey" : "some other value"
]
3. Possible strong type checking: the interpreter, when compile the groovy config , can check if the property settings is match the types. In the xml file, everything is just a bean, and I have to read the class name to “infer” what type of beans they are: a data source, transaction manager, a DAO, an Interceptor, etc. This makes reading the config quite a whirl.
4. Possible tree like structure: instead of:
<bean id=”myHibernateInterceptor” class=”org.springframework.orm.hibernate.HibernateInterceptor”>
<property name=”sessionFactory”>
<ref bean=”mySessionFactory”/>
</property>
</bean>
<bean id=”myProductDaoTarget” class=”product.ProductDaoImpl”>
<property name=”sessionFactory”>
<ref bean=”mySessionFactory”/>
</property>
</bean>
<bean id=”myProductDao” class=”org.springframework.aop.framework.ProxyFactoryBean”>
<property name=”proxyInterfaces”>
<value>product.ProductDao</value>
</property>
<property name=”interceptorNames”>
<list>
<value>myHibernateInterceptor</value>
<value>myProductDaoTarget</value>
</list>
</property>
</bean>
I can do something like this:
ProxyFactory myProductDaoFactory = new org.springframework.aop.framework.ProxyFactoryBean {
proxyInterfaces = product.ProductDao.class
interceptors = [
new HibernateInterceptor {sessionFactory = mySessionFactory},
new product.ProductDaoImpl {sessionFactory = mySessionFactory}
]
}
After we have macros in Groovy we can build configurations that configure huge number of otherwise similarly configured beans such as DAOs:
#def_dao ["dao1", dao1Impl]
#def_dao ["dao2", dao2Impl]
#def_dao ["dao3", dao3Impl]
#def_dao ["dao4", dao4Impl]
The possibility is unlimited.
Now, a good binding of Groovy will not only simplify the config, but probably more importantly, simplify writing Spring beans.
Here is an example:
public class ProductDaoImpl implements ProductDao {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public List loadProductsByCategory(final String category) {
HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
return (List) hibernateTemplate.execute(
new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
List result = session.find(”from test.Product product where product.category=?”, category, Hibernate.STRING);
return result;
}
}
);
}
}
Here is the same Dao impl in Groovy:
class ProductDaoImpl implements ProductDao {
property SessionFactory sessionFactory;
List loadProductsByCategory(String category) {
ht = new HibernateTemplate(sessionFactory);
return ht.execute {|session|
session.find(”from test.Product product where product.category= ${category} “)
}
}
}
The property and the Closure features make it look a lot cleaner. Groovy could well suited to writing Spring beans: each unit is small and clearly intended. We don’t need too much compiler help to make it work and there is no compile and deploy cycle.
Further down the road, I imagine that macros/annotations can help us build a groovy data access layer that sits on top of the Spring JDBC templates to implement a mean and clean persistent mechanism: no XML mapping files, auto-interfacing (defining the interfaces and impls in the same file), etc.. Would that be cool?
Now we have a strong use case for Groovy!
-bing