1

I have an aspect intercepting the logging method. That logging method is a simple method taking one object as an argument:

logMessage(Object message)

How can I modify that object in my aspect and log a new one? Following does not work:

void around() : execution(* com.test.logMessage(..)) {
    String message = thisJoinPoint.getArgs()[0].toString();
    String pattern = "abc";
    String replacement = "xyz";

    message = message.replaceAll(pattern, replacement);
    proceed(message);
}

I'm getting ajc: too many arguments to proceed, expected 0 error.

tkruse
  • 10,222
  • 7
  • 53
  • 80
CorrieSparrow
  • 521
  • 1
  • 6
  • 23

3 Answers3

1

The proceed method takes an object array as argument. You should be able to resolve your issue by calling it like this :

Object[] args = new Object[] { message };
proceed(args);
XGouchet
  • 10,002
  • 10
  • 48
  • 83
  • This answer does not make sense in the context of AspectJ which I guess you have never used, have you? – kriegaex Sep 03 '16 at 08:37
  • Hummm excuse me but first, U have used AspectJ a lot, although just with annotation style, and not .aj files. And second, there are two methods named proceed in the ProceedingJoinPoint class, one of which takes an object array as argument, the other taking no argument. Sorry if I annoyed you while trying to help. – XGouchet Sep 03 '16 at 09:04
  • Sorry if I was offensive, but you as a user with 6k reputation you should not write untested answers which create more problems for an obvious newbie asking a question. What you suggest can never work because `proceed()` in native syntax works different than in annotation-style syntax. You cannot provide parameters to `proceed()` if none are bound via `args()`, `this()`, `target()` or similar. – kriegaex Sep 03 '16 at 09:09
  • Coming to think of it, also in @AspectJ syntax you need to bind arguments first before using them in `proceed()`. So your answer is wrong in any case, sorry. – kriegaex Sep 03 '16 at 09:11
  • 1
    Sorry to contradict you, but I just tested the following aspect https://gist.github.com/xgouchet/b5c4593945a93b0076d458be11eb3170 and it does work (when I use logMessage("Hello world"), it actually logs "Bye world"). But you're the expert and I must surely be wrong. – XGouchet Sep 03 '16 at 09:28
  • You are right and I apologise. That this really works even though canonically the number of arguments to `proceed()` should match the number of bound parameters is rather a surprise to me even in annotation-style aspects because in native syntax this would not work. So my first comment was correct, the second one not. _(to be continued)_ – kriegaex Sep 03 '16 at 11:44
  • But even in @AspectJ syntax I would write this and thus avoid reflection: `@Around("execution(* *.logMessage(..)) && args(message)") public void adviceAround(ProceedingJoinPoint pjp, Object message) throws Throwable { pjp.proceed(new Object[] { message.toString().replaceAll("Hello", "Bye") }); }` – kriegaex Sep 03 '16 at 11:44
  • 1
    If you take a look at the bytecode generated, your solution doesn't prevent reflection, is just hidden, but it effectively does the same thing. It just avoids a cast to String. – XGouchet Sep 03 '16 at 11:53
  • Actually I prefer not to look at bytecode, but, being a clean coder, express myself clearly in source code. This is why I prefer the more expressive, concise and strongly typed native syntax. But even in @AspectJ style I try to bind parameters to typed and named variables whenever possible instead of parsing Object arrays. – kriegaex Sep 03 '16 at 13:15
-1

You may be able use like below:

@Before("execution(* com.package.package.*(..)) && args(token,..)")
public void getAllAdvice(JoinPoint joinPoint, String token) throws Throwable {
    authorizationService.authorizeToken(token);
}
Nimesh
  • 794
  • 3
  • 8
  • 18
  • Where is the relevance to the question? I cannot see any. And besides: You cannot manipulate method parameters from a `@Before` advice, you need `@Around`. – kriegaex Sep 03 '16 at 08:39
-1

I assume your class name is not a lower-case test in package com but rather a real class name like Logger in package com.test, okay?

Sample logger class with main method:

package com.test;

public class Logger {
    public void logMessage(Object message) {
        System.out.println(message);
    }

    public static void main(String[] args) {
        new Logger().logMessage("Hello abc!");
    }
}

Aspect:

The easiest way to access and manipulate a method parameter is to bind it to an argument via args().

package de.scrum_master.aspect;

import com.test.Logger;

public aspect LogManipulator {
    void around(Object message) : execution(* Logger.logMessage(*)) && args(message) {
        proceed(message.toString().replaceAll("abc", "xyz"));
    }
}

Console log:

Hello xyz!

Et voilà!

kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • What was the downvote for, pray tell? The answer was accepted as correct and contains a full [MCVE](https://stackoverflow.com/help/mcve) including console log. – kriegaex Aug 01 '20 at 12:17