15

I want to use Spring Expression Language in a custom Annotation. This annotation will be consumed by a custom Aspect.

Check this out:

@StatisticEventTrigger(value = TestStatisticEvent.class, expression = "#p1")
public void someOtherMethod(String arg1, Long arg2) {

As you can see, i want to use the expression (in this case) to retrieve some specific argument.

When I have my Aspect, triggering an annotated method, i would like to evaluate the spring expression (programmatically) to retrieve a value to use for further business stuff ;)

Any ideas? Google was not my friend so far!

goosefraba
  • 241
  • 1
  • 3
  • 10
  • Let Spring inject `ExpressionParser` to your aspect. Using it is quite straight forward. http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/expression/ExpressionParser.html – Pavel Horal Dec 03 '13 at 12:29
  • And how would the expression look like? Can you might post a short example? – goosefraba Dec 03 '13 at 12:37
  • I have to correct previous comment - just create `SpelExpressionParser` manually and follow detailed "how-to" in reference documentation. There are more than plenty examples. http://docs.spring.io/spring/docs/3.0.x/reference/expressions.html – Pavel Horal Dec 03 '13 at 13:34

1 Answers1

6

I figured it out how to do that with SpEL. I used following expression:

@EventTrigger(value = EventTestModel.class, expression = "new Object[]{arguments[1], arguments[2]}")

and following Java code:

ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext(expressionEvaluationTarget);
Object[] eventPayloadModels = parser.parseExpression(expression).getValue(context);

Works fine ;)

UPDATE

Here is a complete code example now:

import com.example.AbstractEvent;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.log4j.Logger;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;

public class AnnotationEventTriggerAspect implements MethodInterceptor {
private static final Logger LOG = Logger.getLogger(AnnotationEventTriggerAspect.class);

private IEventHandler eventHandler;

@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
    if (LOG.isDebugEnabled()) {
        LOG.debug("Invoking event event trigger for method: " + invocation.getMethod().getDeclaringClass() + "." + invocation.getMethod().getName());
    }

    EventTrigger annotation = invocation.getMethod().getAnnotation(EventTrigger.class);
    Class<? extends AbstractEvent> eventClass = annotation.value();

    if (eventClass == null) {
        throw new IllegalArgumentException("No event class provided for event event trigger annotation at method " + invocation.getMethod().getDeclaringClass() + "." + invocation.getMethod());
    }

    AbstractEvent event = eventClass.newInstance();
    String expression = annotation.expression();

    Object result = invocation.proceed();
    Object expressionEvaluationTarget = invocation;
    Object eventPayloadModels = invocation.getArguments();

    if (annotation.useResult()) {
        expressionEvaluationTarget = result;
        eventPayloadModels = new Object[]{result};
    }

    if (StringUtils.hasText(expression)) {
        ExpressionParser parser = new SpelExpressionParser();
        StandardEvaluationContext context = new StandardEvaluationContext(expressionEvaluationTarget);
        eventPayloadModels = parser.parseExpression(expression).getValue(context);
    }

    if (eventPayloadModels != null) {
        if (eventPayloadModels.getClass().isArray()) {
            for (Object arg : (Object[]) eventPayloadModels) {
                event.addPayloadModel(arg);
            }
        } else {
            event.addPayloadModel(eventPayloadModels);
        }
    }

    eventHandler.post(event);

    return result;
}

public IEventHandler getEventHandler() {
    return eventHandler;
}

public void setEventHandler(IEventHandler eventHandler) {
    this.eventHandler = eventHandler;
}

}

goosefraba
  • 241
  • 1
  • 3
  • 10
  • 1
    Adding to that useful answer, that in order to use it on target objects that are proxied by Spring, you would need to extract the actual target object from the proxy : https://stackoverflow.com/questions/8121551/is-it-possible-to-unproxy-a-spring-bean – Shlomi Uziel Jun 28 '21 at 12:18