In the StrongAspectJ paper, the authors consider this example as a case for separate “proceed signatures”:

Integer around(): //(1)
  call((Integer || Number) *()):
  Number proceed() { //(2)
  return new Integer(proceed().intValue()); //(3)
}

In this example, the advice declares an “advice signature” (1) that returns Integer objects but a “proceed signature” (2) that returns any Number objects. This allows the advice to be applied to any method returning *any* type of Number while at the same time guaranteeing that only Integers are returned.

What could this look like in JPIs?

One could capture this semantics with a syntax such as:

jpi A Number()-> Integer();

Here, Number() is the “expected interface”, i.e., the proceed interface, while Integer() is the provided interface.

Generic Advice

Another example given in the StrongAspectJ paper is the following:

<N extends Number>
N around():
call((Integer || Float) *(..)):
N proceed() {
  N n = proceed();
  while(n.intValue() > 100)
    n = proceed();
  return n;
}

Here the generic type parameter N is used to refer to any concrete return type (here Integer or Float of Number). Using the type parameter instead of just directly using Number has the advantage that one knows that the advice *will* return an Integer if a method call returning an Integer is advised but also *will* return a Float if a method call returning an Float is advised.

In JPIs one could model this as:

jpi <N extends Number> A N()-> N();

Such a jpi could then be applied to calls such as…

Long l = System.currentTimeMillis();

… while the jpi jpi A Number()→ Number() could only be applied in cases where the method returns a value of type Number.