Reputation: 682
In a Spring 3 webapp, I have a DAO that looks something like this:
public class BaseDAOImpl<T extends AbstractEntity> implements BaseDAO<T> {
...
public void doSomething(Class<T> clazz) {
log.debug("class name: " + clazz.getName());
...
}
...
}
That log prints what I'm looking for, let's say com.xyz.Customer.
But that logging line above is just for illustration. In the app, I'm using an aspect to handle logging. And in that aspect, I'm recording arguments. So in my @Before
advice, I have some code like this:
...
Object[] args = joinPoint.getArgs();
for (Object o : args) {
...
log.debug("class name: " + o.getClass().getName());
...
And when that runs against clazz
in BaseDAOImlp's doSomething()
, it logs as java.lang.Class.
So, while understanding that generics are implemented via type erasure, I don't understand why I see com.xyz.Customer with the getName()
call in doSomething()
, but java.lang.Class in the aspect.
Upvotes: 2
Views: 398
Reputation: 682
To log the information I wanted, I use two different pointcuts. One of the pointcuts recognizes when java.lang.Class
is the first argument to a method in our DAOs, and passes the argument to the advice.
(Luckily, by convention in our codebase, when a DAO takes a class argument it always comes first. This is not a terrifically general solution.)
Here's what the pointcuts look like:
@Pointcut("execution(* com.xyz.dao..*.*(..)) && args(clazz,..)")
public void classyDAOMethods(Class<?> clazz) { ... }
@Pointcut("execution(* com.xyz.dao..*.*(..)) && !args(java.lang.Class,..)")
public void unclassyDAOMethods() { ... }
And this advice handles each cut slightly differently:
@Before("classyDAOMethods(clazz)")
public void classyAdvice(JoinPoint joinPoint, Class<?> clazz) {
logMethodEntry(joinPoint, clazz);
}
@Before("unclassyDAOMethods()")
public void logMethodEntry(JoinPoint joinPoint) {
logMethodEntry(joinPoint, null);
}
That clazz
passed in the first @Before
has the class name I need for the logs.
Upvotes: 0
Reputation: 94499
In the second example the instance has been upcasted to an Object
, while in your first example the actual Class
is provided. During that upcast the fact that o
was some other type is lost.
The generics parameters are not considered when calling clazz.getName()
since the code prints the actual type of the class.
List<String> list
is still a List
no matter what genric type arguments the parameterized type contains. The fact that we cannot determine List
has a generic argument of type String
supplied demonstrates the concept of type erause. Regardless of type erasure calling list.getClass().getName()
returns the raw type java.util.List
regardless of the generic parameters supplied.
Upvotes: 1