6cef
6cef

Reputation: 682

Class getName() behavior in aspect vs instance method

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

Answers (2)

6cef
6cef

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

Kevin Bowersox
Kevin Bowersox

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

Related Questions