Search code examples
javaaopaspectjspring-aop

Is it possible to use AOP/AspectJ to affect StringBuilder


Could I use AOP to enforce that every time a StringBuilder is used the first inserted sign would be !!.

So if the code below is anywhere in my project:

String sb = new StringBuilder().append("22").toString();

sb would actually be !!22

The example I have is more concerned with logging:

@Component
@Aspect
class LoggingAspect {
    private final Log log = LogFactory.getLog(getClass());

    @Around("execution( * com.example..*.*(..) )")
    public Object log(ProceedingJoinPoint pjp) throws Throwable {
        this.log.info("before " + pjp.toString());
        Object object = pjp.proceed();
        this.log.info("after " + pjp.toString());
    }
}

The problem I have is if it is even possible to define such a joinpoint for my problem?


Solution

  • Yes, you can. I am not familiar with the syntax that you are currently using. But with AspectJ would be something like:

    public aspect InterceptStringBuilders {
    
        StringBuilder around(StringBuilder target) :
                      call(public StringBuilder append(String)) &&
                      !within(InterceptStringBuilders) &&
                      target(target)
                      {
                          if(target.length() == 0)
                          {
                             target.append("!!");
                          }
                          else if(target.length() == 1 || target.charAt(0) != '!' || target.charAt(1) != '!')
                          {
                             target.insert(0, "!!");
                          }
         
                          return proceed(target);
                     }
    }  
    

    The join point is public StringBuilder append(String) and you need the pointcut target to expose the StringBuilder so that you can enforce that it starts with "!!". Furthermore, you also need the pointcut !within(interceptStringBuilders) to ensure that you do not intercept the calls to the Stringbuilder from the aspect itself.

    I guess with the syntax that you are using would be something similar to :

    "call(public StringBuilder append(String) && !within(LoggingAspect) && target(StringBuilder)"
    

    A running Example:

    Main.java :

    public class Main {
        public static void main(String[] args) {
        System.out.println(new StringBuilder().append("22").toString());
        System.out.println(new StringBuilder().append("!2").append("!2").toString());
        System.out.println(new StringBuilder().append("!!2").append("!!2").toString());
        }
    }
    

    InterceptStringBuilders.aj:

    public aspect InterceptStringBuilders {
    
        StringBuilder around(StringBuilder target) :
                      call(public StringBuilder append(String)) &&
                      !within(InterceptStringBuilders) &&
                      target(target){
                          if(target.length() == 0){
                             target.append("!!");
                          }
                          else if(target.length() == 1 || target.charAt(0) != '!' || target.charAt(1) != '!')
                          {
                             target.insert(0, "!!");
                          }
                          return proceed(target);
                     }
    }  
    

    Output:

    !!22
    !!!2!2
    !!!!2!!2