Home > Enterprise >  Why do I get same result with toString() but different result with getClass().getName()
Why do I get same result with toString() but different result with getClass().getName()

Time:11-01

I am learning AOP, in the spring project, I have the following piece of code.

MainDemoApp.java

public class MainDemoApp {

    public static void main(String[] args) {

        // read spring config java class
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(DemoConfig.class);

        // DemoConfig.class is a simple class with just component scanning enabled 
        // and with @EnableAspectJAutoProxy

        // get the bean from spring container
        AccountDAO accountDAO = context.getBean("accountDAO", AccountDAO.class);

        System.out.println(accountDAO.toString()); // line to be modified

        // call the business method
        accountDAO.addAccount();

        // close the context
        context.close();
    }
}

AccountDAO.java

@Component
public class AccountDAO {
    public void addAccount() {
        System.out.println(this.toString()); // line to be modified
    }
}

and my aspect class MyDemoLoggingAspect.java

@Aspect
@Component
public class MyDemoLoggingAspect {

    // this is where we add all our related advices for logging

    // let's start with a @Before advice
    @Before("execution(public void addAccount())")
    public void beforeAddAccountAdvice() {
        System.out.println("\n=======>>> Executing @Before Advice");
    }
}

Now when I run main method in MainDemoApp, I get the following output- Output-

com.luv2code.aopdemo.dao.AccountDAO@3e0e1046

=======>>> Executing @Before Advice
com.luv2code.aopdemo.dao.AccountDAO@3e0e1046

As you can see the lines

System.out.println(accountDAO.toString());

And

System.out.println(this.toString());

give the same result, before advice is also executed successfully. By default toString() is defined as-

this.getClass().getName()   "@"   Integer.toHexString(this.hashCode())

But when I explicitly print out getClass().getName() the results are different

System.out.println(accountDAO.getClass().getName());

And

System.out.println(this.getClass().getName());

Output-

com.luv2code.aopdemo.dao.AccountDAO$$EnhancerBySpringCGLIB$$88eb61b6

=======>>> Executing @Before Advice
com.luv2code.aopdemo.dao.AccountDAO

Both the class names differ, I don't know which type of class name is that. Also when I explicitly print hashCode() the results are different.

I am confused about getting different results with-

  1. toString(), when toString() includes getClass().getName() and hashCode()
  2. getClass().getName()
  3. hashCode()

Why are these differences there, I did not override any of these methods (At my end), does this has something related to AOP proxy?

Kindly help me clarify these doubts.

Edit- I also have a very strange observation that when I modify MainDemoApp.java

AccountDAO accountDAO = context.getBean("accountDAO", AccountDAO.class);

System.out.println(accountDAO.hashCode());
// call the business method
accountDAO.addAccount(accountDAO);

And AccountDAO.java is modified as-

public void addAccount(AccountDAO obj) {
        System.out.println(this.hashCode()   " "   obj.hashCode());
}

NOW the result of hashCode() is the same but if I don't change the method signature and call hashCode() on the previous piece of code, the result is different

Can anyone explain this also?

CodePudding user response:

Welcome to SO. Please note that on this platform, it would be better to ask just one clear question and not lots of them. But we also try to be nice to newbies, so I am trying to answer your questions. While this is somewhat redundant, because others have replied in comments already, I also think that comments are comments and answers are answers, i.e. an answer should be written as such. Probably the other contributors here are too busy to write a comprehensive answer, so I am picking up the ball here.

System.out.println(accountDAO.toString());

And

System.out.println(this.toString());

give the same result

This is because accountDAO is a dynamic proxy and you are applying a Spring AOP aspect to it. It is forwarding method calls to its delegate (the original object it is proxying).

But when I explicitly print out getClass().getName() the results are different

System.out.println(accountDAO.getClass().getName());

And

System.out.println(this.getClass().getName());

Output-

com.luv2code.aopdemo.dao.AccountDAO$$EnhancerBySpringCGLIB$$88eb61b6

=======>>> Executing @Before Advice
com.luv2code.aopdemo.dao.AccountDAO

The former prints the name of the CGLIB proxy class, the latter the target class name.

Also when I explicitly print hashCode() the results are different.

Same reason: You are printing the hash code of the proxy vs. the original object.

Why are these differences there, I did not override any of these methods (At my end), does this has something related to AOP proxy?

Well, in a way you did. You applied an aspect, causing proxy creation. So now the actual Spring bean is a proxy, causing all the effects you described above. Technically, a Spring proxy is a subclass (or interface implementation, depending on your settings and whether you are proxying an interface ot class type). The proxy keeps a reference to the original object (its delegate or target object), decorating it with additional functionality. This is a well-known design pattern. Spring makes heavy use of it throughout the framework. See my explanation here for more details.

As for your follow-up question, the root cause and explanation are the same as above. It is all quite straightforward and logical, once you understand that Spring AOP uses dynamic proxies and same proxies use delegation in order to implement a decorator pattern.

  • Related