Reputation: 2311
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
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