0

I Want to get the value of the modified objects using spring AOP (@Before). I have the below class:

package com.mypack;
public class Person {
    private String id;
    private String firstName;
    private String lastName;

    public String getId() { return id; }
    public String getFirstName() { return firstName; }
    public String getLastName() { return lastName; }

    public void setId(String id) { this.id = id; }
    public void setFirstName(String firstName) { this.firstName = firstName; }
    public void setLastName(String lastName) { this.lastName = lastName; }
    public String toString() { return "Person[" + id + ",  
   + firstName + ", " + lastName+ "]"; }
}

Details class:

package com.mypack;
public class Details extends Person{

    private String address;
    private String contactNum;
    //getters and setters
    public String toString() { return "Details[" + address + ", 
    " + contactNum+ "]"; }

}

AspectSetterInterceptor class:

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AspectSetterInterceptor {
     @Before("execution(* com.mypack.Details.set*(*))")
        public void before(JoinPoint joinPoint) throws Throwable {
        Object[] signatureArgs = joinPoint.getArgs();
            for (Object signatureArg : signatureArgs) {
                Person obj = (Person) signatureArg;
                System.out.println("Before : " + obj.getFirstName() + " ---- "
                        + obj.getId());

            }

        }
}

Test class:

public class ChangeTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register(AspectConfig.class);
        ctx.refresh();
        //Details userService = ctx.getBean(Details.class);
        Details obj1 = new Details();
        obj1.setAddress("xx 202");
        obj1.setContactNum("2124551234");
        obj1.setId("242");
        obj1.setFirstName("John");
        obj1.setLastName("John");

        Details obj2 = new Details();
        obj2.setAddress("ASDf 202");
        obj2.setContactNum("234544565656");
        obj2.setId("23689");
        obj2.setFirstName("Sam");
        obj2.setLastName("S");

        System.out.println("obj1 : " + obj1);
        System.out.println("obj2 : " + obj2);

        obj2.setFirstName("Samuel");
    }

}

Tried as mentioned here too Spring AOP - get old field value before calling the setter

--EDITED--- When ChangeTest class is executed, it is printing the values of obj1 and obj2 (toString() method overridden in the class). It is not hitting the method before(..) mentioned in the AspectSetterInterceptor . Please advice.

PS: My scenario is to hit the @Before aspect when ever some one is using set*(..) methods. Here in the above example i gave one simple class Details which extend Person class, so anytime the set*(..) method is invoked in those classes the aspect @before should be called, similarly i want in my application any set**(..) method is invoked i want to call the @Before. Is there any better approach to follow.TIA.

user222
  • 587
  • 3
  • 10
  • 31

2 Answers2

0

You take in an int for the method setId(int i), but in the main method you pass a String. obj1.setId("242"); What you have to do is pass an int obj1.setId(242); Just as a side note, override the toString() method, since you're doing System.out.println("obj1 : " + obj1);, but printing obj just prints it address (bunch of random numbers and letters).

nishantc1527
  • 376
  • 1
  • 12
  • True. The test should not even compile. Or maybe the OP messed up something during copy & paste. So please, dear OP, fix the sample code first, then I can answer your AOP-related question if there are still problems. – kriegaex Aug 15 '19 at 02:47
  • @kriegaex - Yes, as you mentioned it is by mistake i have given int in place of String(copy & paste problem). Please see my edited post above, added more details for clarity..Now when ChangeTest class is executed, it is not calling the Before aspect, it is simply printing the objects (No exceptions..). Please advice. – user222 Aug 15 '19 at 04:14
  • Can someone advice , what changes need to be done to ChangeTest to make it call Aspect Before. – user222 Aug 15 '19 at 14:18
0

Your pointcut definition @Before("execution(* com.mypack.set*(*))") means that it triggers on all setters for a class mypack.

What you want is probably

@Before("execution(* com.mypack.Person.set*(*))") // all setters on person

Or

@Before("execution(* com.mypack.*.set*(*))") // all setters on all classes in package

or

@Before("execution(* com.mypack..set*(*))") // all setters in all classes in all subpackages
daniu
  • 14,137
  • 4
  • 32
  • 53
  • While your explanation is correct, the second pointcut is incorrect, the syntax `**` is undefined in AspectJ. It should be `execution(* com.mypack..set*(*))` instead. BTW, this one also works for classes in all sub-packages. – kriegaex Aug 15 '19 at 06:41
  • @user222 Nope. Aspects only trigger for beans; they won't register for the `Detail`s created via `new` (due to that, in general, aspects don't really work well for data classes IMO). – daniu Aug 15 '19 at 13:34
  • @daniu , So do i need to say Details userService = ctx.getBean(Details.class); in order to make it work? but then how can i allow for all my bean classes whenever set*(..) is called it should call the Aspect before.. – user222 Aug 15 '19 at 13:44
  • @user222 In Spring AOP at least, you can't. Aspects are triggered only on public methods for calls between beans. – daniu Aug 15 '19 at 13:46
  • all the set*(..) methods are public. – user222 Aug 15 '19 at 13:54
  • @user222 well that's one out of the two conditions met. – daniu Aug 15 '19 at 13:55
  • Then how it got worked in the link shown here https://stackoverflow.com/questions/31503041/spring-aop-get-old-field-value-before-calling-the-setter. I was looking in the same manner..any updates are helpful. – user222 Aug 15 '19 at 15:33