Kilokahn
Kilokahn

Reputation: 2311

Access to lambda arguments via Function/Supplier

I wanted to write a utility that does (relatively) non-intrusive logging of request and responses for a set of invocations and I was hoping to use the java-8 lambda/functional interfaces to get it done.

Let's say the sample client invocation code is:

SomeReturn retVal = someObject.doSomething(arg1, arg2);

I was hoping to write a Recorder utility that can be invoked as:

SomeReturn retVal = Recorder.withRecording(() -> someObject.doSomething(arg1, arg2))

The Recorder will look something like:

public static <R> R withRecording(Supplier<R> call) {
    R response = call.get();
    // Record the response
    return response;
}

However, I was not able to identify a way to capture the request arguments (and request object) from the Supplier (and rightly so - Supplier is not concerned with it). I think even java.util.function.Function will not help us here, since they do not deal with state themselves.

Without resorting to things like

Object withRecording(Object target, Method method, Object[] arguments)

what other options do we have? I know we can use AOP as a solution, but wanted to see if we can do without it.

Thanks in advance!

Upvotes: 2

Views: 287

Answers (1)

Holger
Holger

Reputation: 298163

This only works if you operate with a known, finite set of functional signatures, e.g.

public static <T,U,R> R withRecording(BiFunction<T,U,R> func, T arg1, U arg2) {
    R response = func.apply(arg1, arg2);
    // Record arg1, arg2 and the response
    return response;
}

usable as

SomeReturn retVal = withRecording(someObject::doSomething, arg1, arg2);

This does not only imply that you have to create one overload for every supported signature, i.e. distinct number of arguments, you also have to create an appropriate interface for each function with more than two arguments, as there are no predefined interfaces for these cases.

Further, note that the function object itself will not reveal anything about the actual function, so all you are going to record is that some function has been invoked with particular arguments and result, but not which function…


A better solution would be to have doSomething declared as an interface method, allowing to replace someObject with a reference to another implementation, which delegates to someObject and records all invocations. This functionality could be implemented in a general way using proxies, but well, it is overlapping with AOP solutions…

Upvotes: 4

Related Questions