David_W (70) [Avatar] Offline
#1
The pointcut
@Pointcut("ajia.jdbc.JDBCPointcuts.jdbcExecution() " +
"|| ajia.spring.SpringPointcuts.jdbcTemplateExecution()")

would require weaving into JDBC and Spring. How is this more suitable to Spring AOP than the previous listing using call pointcuts?
ramnivas (171) [Avatar] Offline
#2
Re: listing 11.18
Since Spring AOP doesn't support call pointcuts, using them is not an option. For Spring's JDBC templates, since they tend to be Spring beans (typically injected into repositories), Spring AOP can detect violations in using them.

JDBC execution will help if there is a bean corresponding to a JDBC type. In a typical Spring application, this is unlikely to help, but won't hurt either. A call join point won't help in any case.

As an aside, when possible, I use a policy to detect direct usages of the JDBC API and suggest using Spring's JDBC template (implementable using the AspectJ weaver only, since call join points are involved).

-Ramnivas
David_W (70) [Avatar] Offline
#3
Re: listing 11.18
But jdbcExecution was defined as
public pointcut jdbcExecution()
: execution(* java.sql..*.*(..))
|| execution(* javax.sql..*.*(..));
and jdbcTemplateExecution was defined as
public pointcut jdbcTemplateExecution()
: execution(* JdbcOperations+.*(..))
|| execution(* SimpleJdbcOperations+.*(..));
I expect that most calls to java.sql and javax.sql occur inside of SimpleJdbcTemplate, not the actual repository class. One exception would probably be a RowMapper, but this is likely an inner class of the repository class. Anyway, the proxy style of Spring's AOP would only pick up the public methods of the repository class, which isn't likely to be in the java.sql or javax.sql package. So, how would Spring deal with this, without doing actual weaving? Wouldn't the jdbcExecution pointcut typically be identifying methods in the runtime library, jdbc drivers, and app server libraries?
As for jdbcTemplateExecution, the JdbcOperations and SimpleJdbcOperations interfaces are usually just implemented by JdbcTemplate, which, for similar reasons as described above, implies that you would need weaving of Spring jars.

For example, I may have a repository class that looks like:
public class TestRepository extends SimpleJdbcDaoSupport {
public Object getOrder(String orderId) {
return getSimpleJdbcTemplate().queryForObject("select * from order where order_id=?", new OrderMapper(), orderId);
}

private static class OrderMapper implements RowMapper<Order> {
public Order mapRow(ResultSet rs, int rowNum) {
String orderId = rs.getString("order_id");
Order order = new Order(orderId);
...
return order;
}
}
}

so, the only exposed joinpoints for Spring AOP is execution of the getOrder method, even though JDBC calls are made inside the jdbc template and inside the order mapper.
ramnivas (171) [Avatar] Offline
#4
Re: listing 11.18
For direct JDBC operations, as I noted in my earlier reply, this aspect is unlikely to help (In a typical Spring application, you won't have beans of raw JDBC types such as Statement). Although selection of methods of raw JDC types wasn't harmful, since it caused confusion, I am making a change related to this (as well as noting limitations of Spring AOP in this regard as discussed next).

For JDBC template, I typically create a bean of SimpleJdbcTemplate and inject it into repositories (I don't use any of the *DaoSupport classes--they don't add much value). So my typical setup is as follows:

<bean class="your.TestRepository">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>

... dataSource etc.

This is conceptually similar to the test case in the book.

With such set up, applying advice to execution(* JdbcOperations+.*(..)) || execution(* SimpleJdbcOperations+.*(..)) will lead to creation of proxy for the jdbcTemplate bean. Therefore, the enforcement works.

Note that enforcement also works with JdbcDaoSupport as long as template is injected into it, instead of injecting a DataSource.