Java 8: convert lambda to a Method instance with closure included - reflection

(This is difficult to search because results are all about "method reference")
I want to get a Method instance for a lambda expression for use with a legacy reflection-based API. The clousure should be included, so calling thatMethod.invoke(null, ...) should have the same effect as calling the lambda.
I have looked at MethodHandles.Lookup, but it only seems to be relevant for the reverse transform. But I guess the bind method may help to include the clousure?
Edit:
Say I have am lambda experssion:
Function<String, String> sayHello = name -> "Hello, " + name;
and I have a legacy framework (SpEL) that has an API like
registerFunction(String name, Method method)
which will call the given Method with no this argument (i.e. Method assumed to be static). So I'll need to get a special Method instance that includes the lambda logic + the clousure data.

In case you don't find an elegant way, here is the ugly way (Ideone). Usual warning when reflection is involved: may break in future releases etc.
public static void main(String[] args) throws Exception {
Function<String, String> sayHello = name -> "Hello, " + name;
Method m = getMethodFromLambda(sayHello);
registerFunction("World", m);
}
static void registerFunction(String name, Method method) throws Exception {
String result = (String) method.invoke(null, name);
System.out.println("result = " + result);
}
private static Method getMethodFromLambda(Function<String, String> lambda) throws Exception {
Constructor<?> c = Method.class.getDeclaredConstructors()[0];
c.setAccessible(true);
Method m = (Method) c.newInstance(null, null, null, null, null, 0, 0, null, null, null, null);
m.setAccessible(true); //sets override field to true
//m.methodAccessor = new LambdaAccessor(...)
Field ma = Method.class.getDeclaredField("methodAccessor");
ma.setAccessible(true);
ma.set(m, new LambdaAccessor(array -> lambda.apply((String) array[0])));
return m;
}
static class LambdaAccessor implements MethodAccessor {
private final Function<Object[], Object> lambda;
public LambdaAccessor(Function<Object[], Object> lambda) {
this.lambda = lambda;
}
#Override public Object invoke(Object o, Object[] os) {
return lambda.apply(os);
}
}

Well, lambda expressions are desugared into methods during compilation and as long as they don’t capture this (don’t access non-static members), these methods will be static. The tricky part is to get to these methods as there is no inspectable connection between the functional interface instance and its target method.
To illustrate this, here the simplest case:
public class LambdaToMethod {
public static void legacyCaller(Object arg, Method m) {
System.out.println("calling Method \""+m.getName()+"\" reflectively");
try {
m.invoke(null, arg);
} catch(ReflectiveOperationException ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) throws URISyntaxException
{
Consumer<String> consumer=s -> System.out.println("lambda called with "+s);
for(Method m: LambdaToMethod.class.getDeclaredMethods())
if(m.isSynthetic() && m.getName().contains("lambda")) {
legacyCaller("a string", m);
break;
}
}
}
This works smoothly as there is only one lambda expression and hence, one candidate method. The name of that method is compiler specific and may contain some serial numbers or hash codes, etc.
On kludge is to make the lambda expression serializable and inspect its serialized form:
static Method lambdaToMethod(Serializable lambda) {
for(Class<?> cl=lambda.getClass(); cl!=null; cl=cl.getSuperclass()) try {
Method m=cl.getDeclaredMethod("writeReplace");
m.setAccessible(true);
try {
SerializedLambda sl=(SerializedLambda)m.invoke(lambda);
return LambdaToMethod.class.getDeclaredMethod(sl.getImplMethodName(),
MethodType.fromMethodDescriptorString(sl.getImplMethodSignature(),
LambdaToMethod.class.getClassLoader()).parameterArray());
} catch(ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
} catch(NoSuchMethodException ex){}
throw new AssertionError();
}
public static void main(String[] args)
{
legacyCaller("a string", lambdaToMethod((Consumer<String>&Serializable)
s -> System.out.println("first lambda called with "+s)));
legacyCaller("a string", lambdaToMethod((Consumer<String>&Serializable)
s -> System.out.println("second lambda called with "+s)));
}
This works, however, serializable lambdas come at a high price.
The simplest solution would be to add an annotation to a parameter of the lambda expression to be found when iterating over the methods, however, currently, javac doesn’t store the annotation properly, see also this question about this topic.
But you may also consider just creating ordinary static methods holding the code instead of a lambda expression. Getting a Method object for a method is straight-forward and you still can create a functional interface instance out of them using method references…

Since the question mentions SpEL specifically (and I found the question when also working with SpEL), an alternative way to add a custom function to the evaluation context without using Method references is to add a custom MethodResolver (javadoc, GitHub) to the StandardEvaluationContext. A benefit of this approach is that one can add both static and non-static methods to the evaluation context using it, where only static methods could be added using the registerFunction approach.
The code to add a custom MethodResolver to the StandardEvaluationContext is fairly straightforward. Below is an executable example showing how to do so:
public static void main(String[] args) throws Exception {
Function<String, String> sayHello = name -> "Hello, " + name;
// The evaluation context must have a root object, which can be set in the StandardEvaluationContext
// constructor or in the getValue method of the Expression class. Without a root object, the custom
// MethodResolver will not be called to resolve the function.
Object rootObject = new Object();
StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext(rootObject);
// Add the custom MethodResolver to the evaluation context that will return a MethodExecutor that
// Spring can use to execute the sayHello function when an expression contains "sayHello('<any string>')".
standardEvaluationContext.addMethodResolver((context, targetObject, methodName, argumentTypes) -> {
MethodExecutor methodExecutor = null;
if (methodName.equals("sayHello")
&& argumentTypes.size() == 1
&& String.class.isAssignableFrom(argumentTypes.get(0).getObjectType())
) {
methodExecutor = (innerContext, target, arguments) -> {
final String name = arguments[0].toString();
return new TypedValue(sayHello.apply(name));
};
}
return methodExecutor;
});
// Create an expression parser, parser the expression, and get the evaluated value of the expression.
SpelExpressionParser expressionParser = new SpelExpressionParser();
Expression expression = expressionParser.parseExpression("sayHello('World!')");
String expressionValue = expression.getValue(standardEvaluationContext, String.class);
// Output the expression value, "Hello, World!", to the console.
System.out.println(expressionValue);
}
The value of the expression that was output to the console by executing the above code was:
Hello, World!
Note that when using a MethodResolver to add a function to the evaluation conext, the function should not be prefixed with a # in the expression string. This is a major difference between using the MethodResolver and using the registerFunction method to add a function to the evaluation context.
sayHello('World!') // will work!
#sayHello('World!') // will not work!
Keep this in mind if you are considering migrating an existing solution from using the registerFunction approach to using the MethodResolver approach.

Related

powermock running with MockitToRunner - getting matchers error

#RunWith(MockitoJUnitRunner.class)
public class MessageDataTest {
#InjectMocks
MessageData messageData;
#Test
public void testingMethod() throws Exception {
MessageData data = PowerMockito.spy(messageData); //passing the mocked object for spy
PowerMockito.when(data,"isMessageContains",anyString(),any()).thenReturn(true); // throwing exception here
MessageDataResponse response = messageFormatterData.constructData(messageItems);
assertNotNull(response);
}
}
MessageData.java
private boolean isMessageContains(String name, MessageResponse messageResponse) {
for (::) {
some logic
return true;
}
}
return false;
}
when I run the test case, I'm getting the below error,
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Misplaced argument matcher detected here
You cannot use argument matchers outside of verification or stubbing. Examples of correct usage of argument matchers: when(mock.get(anyInt())).thenReturn(null); doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject()); verify(mock).someMethod(contains("foo"))
Also, this error might show up because you use argument matchers with methods that cannot be mocked. Following methods cannot be stubbed/verified: final/private/equals()/hashCode(). Mocking methods declared on non-public parent classes is not supported
I want to mock this private "isMessageContains" to return always true.

Mock logger giving me error for ASP.NET Core

I was trying to verify whether my log warning message is written via NUnit mocking. I am getting this error message :
An exception of type 'System.NotSupportedException' occurred in Moq.dll but was not handled in user code
Additional information: Invalid verify on a non-virtual (overridable in VB) member: m => m.LogWarning(String.Format("comments not found for part number :{0}", (Object)0), new[] { "111" })
code:
mockLogger.Verify(m => m.LogWarning($"comments not found for part number :{0}", "111"), Times.Exactly(1));
This is happening because NUnit mocking framework does not support extension methods. A few people on stack overflow have suggested to use Log method instead of level wise methods.
What am I missing?
Firstly, you don't need the $ at the start of the string. That's for string interpolation. The LogWarning message is doing a string.format, hence the {0}
Mock frameworks cannot directly mock static methods. The problem in your case is the LogWarning method - that is the static (extension) method.
The simplest way of overcoming this issue is by using a wrapper class. Here's how I got it, in your case.
Firstly I created an interface
public interface IMyLogWarning
{
void LogWarning(string msg, params object[] args);
}
Then I created a class which implements that interface
public class MyLogWarning<T> : IMyLogWarning where T : class
{
private readonly ILogger _logger;
public MyLogWarning(ILogger<T> logger)
{
// Using constructor for DI
_logger = logger;
}
public void LogWarning(string msg, params object[] args)
{
_logger.LogWarning(msg, args);
}
}
The reason for these two is that I'll use these in my code as well as the unit test.
The constructor in the class is setup so it can be populated using dependency injection, something like this in your ConfigureServices method. Feel free to change this; was a quick stab at it on my part.
services.AddTransient<IMyLogWarning, MyLogWarning<MyViewModel>>();
You can then create a unit test that's roughly like this
[Test]
public void LoggingTest_LogAMessage_ConfirmedLogWasRun()
{
// TODO - add the rest of your test code
// Arrange
var warningMsg = "comments not found for part number :{0}";
var partNumber = "111";
var mockLogger = new Mock<IMyLogWarning>();
// Act
mockLogger.Object.LogWarning(warningMsg, partNumber);
// Assert
mockLogger.Verify(m => m.LogWarning(warningMsg, partNumber), Times.Exactly(1));
}

FakeMessageContext throws NullReferenceException

I'm trying to write unit test for my saga. I have used SagaFixture to host my Saga and using FakeBus. I have also used FakeMessageContext because, in a Saga exectution I'm using MessageContext to get return address.
Now, when I'm trying to call Handle method on Fixture, it throws exception of type NullReferenceException.
Pasting code below:
SearchSaga
public class SearchSaga : Saga<SearchSagaData>, IAmInitiatedBy<PersonRequested>, IHandleMessages<PersonSearchCompleted>
{
public void Handle(PersonRequested message)
{
Data.Id = new Guid(message.MessageId);
Data.ReturnAddress = MessageContext.GetCurrent().ReturnAddress;
Bus.Publish(message);
}
}
SagaUnitTest
[Test]
public void PublishResponseOfTypeSearchPersonRequest()
{
var bus = new FakeBus();
var saga = new SearchSaga(bus);
var fixture = new SagaFixture<SearchSagaData>(saga);
FakeMessageContext.Reset();
var fakeContext = MockRepository.GenerateMock<IMessageContext>();
fakeContext.Stub(s => s.ReturnAddress).Return("queuename");
fakeContext.Stub(s => s.Headers).Return(new Dictionary<string, object>());
// act
using (FakeMessageContext.Establish(fakeContext))
{
fixture.Handle(new PersonRequested {MessageId = Guid.NewGuid().ToString(), Query = "Abc"});
}
var sentRequests = bus.PublishedMessages.OfType<SearchPersonRequest>().ToList();
Assert.That(sentRequests.Count, Is.EqualTo(1));
}
Error Stacktrace:
at Rebus.SagaContext..ctor(Guid id)
at Rebus.Bus.Dispatcher.DispatchToHandler[TMessage](TMessage message, IHandleMessages1 handler) at Rebus.Testing.SagaFixture1.Handle[TMessage](TMessage message)
The exception is caused by the fact that your IMessageContext mock has a null value on the Items property. The thrown exception is just pretty bad, but I'll make sure that the reported error gets better in the future.
For now, you can fix the situation by setting up a an items dictionary like so:
fakeContext.Stub(s => s.Items).Return(new Dictionary<string, object>());
Moreover, instead of using MessageContext.GetCurrent() to get to the message context inside your handler, you should take advantage of the fact that all Rebus' IoC container adapters ensure that you can have an IMessageContext injected into all of your handler instances.
This way, there's no need to use FakeMessageContext in your unit tests.

Find out a method's name in Groovy

Is there a way in Groovy to find out the name of the called method?
def myMethod() {
println "This method is called method " + methodName
}
This, in combination with duck typing would allow for quite concise (and probably hard to read) code.
Groovy supports the ability to intercept all methods through the invokeMethod mechanism of GroovyObject.
You can override invokeMethod which will essentially intercept all method calls (to intercept calls to existing methods, the class additionally has to implement the GroovyInterceptable interface).
class MyClass implements GroovyInterceptable {
def invokeMethod(String name, args) {
System.out.println("This method is called method $name")
def metaMethod = metaClass.getMetaMethod(name, args)
metaMethod.invoke(this, args)
}
def myMethod() {
"Hi!"
}
}
def instance = new MyClass()
instance.myMethod()
Also, you can add this functionality to an existing class:
Integer.metaClass.invokeMethod = { String name, args ->
println("This method is called method $name")
def metaMethod = delegate.metaClass.getMetaMethod(name, args)
metaMethod.invoke(delegate, args)
}
1.toString()
No, as with Java there's no native way of doing this.
You could write an AST transform so that you could annotate the method and this could set a local variable inside the method.
Or you can do it the good old Java way of generating a stackTrace, and finding the correct StackTraceElement with something like:
import static org.codehaus.groovy.runtime.StackTraceUtils.sanitize
def myMethod() {
def name = sanitize( new Exception().fillInStackTrace() ).stackTrace.find {
!( it.className ==~ /^java_.*|^org.codehaus.*/ )
}?.methodName
println "In method $name"
}
myMethod()

Building a single entry point to a WCF service: need unified approach to return objects and collections

Subject says it all: I'm creating a secure and generic wrapper to access a WCF service transparently.
A little background:
what I have done is that I've created similar business classes definition both on server and client. The server-side contains the actual logic while the client side contains only method definitions. Additionally, the client-side classes derive from a SecureFactory which implements a Call method. The body of every method of each derived class contains only a call to Call method. This Call method is responsible for invoking the server service passing such things as to the type of business class and which of its method to invoke to perform the requested operation.
This approach is being designed in order to simplify security checks by restricting passing of security information to only between SecureFactory and Server service. There are tuns of other benefits which you most of already aware of.
Now here's the issue: I'm stuck at as to how to return objects (especially arrays of objects) from Server to Call method?
The server may return a single business object (DataContract applied) as well as list of such objects. Since it's a generic approach, I have only Object to be used as return type. Following is the Call method
public object Call(params object[] parameters)
{
var mb = (new StackFrame(1).GetMethod());
using (Proxy.ServerClient server = new Security.BO.Proxy.ServerClient())
{
try
{
if (((MethodInfo)mb).ReturnType.IsGenericType)
{
var response = server.InvokeForList(SecurityManager.Current.SID, SecurityManager.Current.Token, mb.DeclaringType.ToString(), mb.Name, parameters);
return response.Result.ToList();
}
else
{
var response = server.Invoke(SecurityManager.Current.SID, SecurityManager.Current.Token, mb.DeclaringType.ToString(), mb.Name, parameters);
return response.Result;
}
}
catch (Exception ex)
{
System.Diagnostics.Debugger.Break();
}
}
return null;
}
server methods:
public CollectionResponse InvokeForList(string SID, string token, string type, string method, object[] parameters)
{
// Validation here
var t = assemblyBO.GetType(type, true);
object BO = Activator.CreateInstance(t);
var mi = t.GetMethod(method);
if (mi == null)
throw new MethodNotImplementedException("Method " + method + " could not be found on type " + t.ToString());
object res = mi.Invoke(BO, parameters);
// Convert list to t[]
object list = res.GetType().GetMethod("ToArray").Invoke(res, new object[0]);
// Error here! cannot convert t[] into object[]
return new CollectionResponse((object[])list);
}
The other method Invoke(...) is similar accept it returns Response object instead of CollectionResponse.
Here's the CollectionResponse class: (Response is similar:just it takes only one object)
[DataContract]
public class CollectionResponse
{
[DataMember]
private Object[] _result;
public Object[] Result
{
get
{
return _result;
}
}
public CollectionResponse(Object[] result)
{
this._result = result;
}
}
Initially I was thinking to have only one Invoke for both lists and singleton – but failed with "Connection was closed unexpectedly." still I'm not able to achieve – how can I convert T[] into object[].
Do you have any suggestion to improve it, or any other way of achieving the same?
Thanks
I can see an immediate problem here. You are using reflection which is far less perfromant than the direct call.
For me, that is enough not to follow this route.

Resources