I have a method that expects a method reference:
expectsMethodRef(obj::someMethod);
I now only retrieve the method at compiletime with reflection. How do I get the method reference from a Method object?
Method method = obj.class.getMethod(methodNameStr);
expectsMethodRef(<how to input my method here?>);
You just need to use Method.invoke. Here is an example:
public class SomeObject{
public String someMethod(){
return "Test";
}
}
public String expectsMethodRef( Function<SomeObject, String> f ){
SomeObject so = new SomeObject();
return f.apply(so);
}
And here is how you invoke using plain lambda and Method object.
//plain lmbda
expectsMethodRef( SomeObject::someMethod );
//with method object
Method someMethod = SomeObject.class.getMethod("someMethod");
expectsMethodRef( (so) -> {
try {
return (String)someMethod.invoke(so);
} catch (Exception e) {
return null;
}
} );
Related
I want to call method of a reflection of okhttp3.Request. The method to be called is writeTo(okio.BufferedSink).
private String getBody(final Object body){
try {
final BufferedSink buffer = Okio.buffer((Sink) new Buffer());
Method methodWriteTo = findMethod(body.getClass(), "writeTo");
# Not working
methodWriteTo.invoke(body, BufferedSink.class.cast(buffer));
# Not working
methodWriteTo.invoke(body, (BufferedSink)buffer);
String body = buffer.buffer().readUtf8();
return body;
} catch (Exception e) {
...
}
return "";
}
I always got http3.RequestBody$Companion$toRequestBody$1.writeTo argument 1 has type okio.BufferedSink, got okio.RealBufferedSink.
The okio.BufferedSink is interface class, so how can invoke this method with okio.RealBufferedSink ?
public void etisLogAround(ProceedingJoinPoint joinPoint, EtisLog etisLog) throws Throwable {
Object[] args = joinPoint.getArgs();
MethodSignature methodSignature = (MethodSignature) joinPoint.getStaticPart().getSignature();
Method method = methodSignature.getMethod();
String[] paramNames = ((MethodSignature) joinPoint
.getSignature()).getParameterNames();
for(String paramName: paramNames) {
logger.info("paramName:" +paramName);
}
try {
Object result = joinPoint.proceed();
if(methodSignature instanceof MethodSignature) {
final Class<?>[] parameterTypes = methodSignature.getParameterTypes();
for(final Class<?> pt : parameterTypes){
logger.info("Parameter type:" + pt);
}
}
#SuppressWarnings("unchecked")
ResponseEntity<CaseOutlineHeader> returnValue = (ResponseEntity<CaseOutlineHeader>) result;
result = etisLog.trasactionDetail().toString()+" "+returnValue.getBody().getCode().toString();
} catch (IllegalArgumentException e) {
throw e;
}
}
The class CaseOutlineHeader is what I want to be changed. the parameterTypes variable contains the name of the class that I would like to pass inside the tag of the ResponseEntity<>. What if I would like to pass a different class Name. How should I do that to be flexible to accept the different class name?
If i do : ResponseEntity<parameterTypes> returnValue = (ResponseEntity<parameterTypes>) result;
it will say an error parameterTypes cannot be resolved to a type.
The problem is that your AOP method need to cast the result to something in order to get the code value it needs to log. That something must be known in advance, since you can't use type parameters in annotations, and therefore can't pass it to AOP methods. This means that all methods you access in AOP must come from a known interface, like this:
public interface LogCodeProvider {
String getLogCode();
}
public class CaseOutlineHeader implements LogCodeProvider {
#Override
public String getLogCode() {
return "My Code";
}
}
And then in your AOP method you can do like this:
#SuppressWarnings("unchecked")
ResponseEntity<LogCodeProvider> returnValue = ResponseEntity<LogCodeProvider>) result;
result = etisLog.trasactionDetail().toString()+" "+returnValue.getBody().getLogCode();
In my example I have implemented special method getLogCode() which returns a string, so each class can decide exactly what to output.
It does however look confusing to reuse the result variable to store the value returned from etisLog.trasactionDetail().
Below sample code ,
ResponseEntity<?> anyRandomMethod(){
if(any condition){
return new ResponseEntity<Animal>(new Animal(), httpstatus.OK);
}else{
return new ResponseEntity<SpaceShip>(new SpaceShip(), httpstatus.OK);
}
}
I am trying to invoke a static method with a Object[] parameter type. When I debug, the correct method is identified and the parameter type I put in seems to me to be of the correct type.
public String convertToJSFunction(Method method, Object[] params) {
String function = method.getName();
for (Method m : JavaToJS.class.getDeclaredMethods()) {
if (m.getName().equals(function))
try {
return (String) m.invoke(null,params);
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
} catch (InvocationTargetException e) {
e.printStackTrace();
return null;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return null;
}
}
return null;
}
JavaToJS has only static methods. After debugging, the m I am trying to invoke is this method:
public static String setRegionNumber(Object[] params)
This throws an IllegalArgumentException: argument type mismatch. How is this possible?
i guess you are calling
Method setRegionNumber=...; // "setRegionNumber" Method
Object[] params=...; // your Object-Array Parameter
convertToJSFunction(setRegionNumber, params);
but what you need to do is
Method setRegionNumber=...; // "setRegionNumber" Method
Object[] params=...; // your Object-Array Parameter
convertToJSFunction(setRegionNumber, new Object[] { params });
this is because Method.invoke expects the parameter list of the called method as an object Array. So if you pass your object array directly then it interprets that as the parameter list. so if you have an Object[] Parameter you need to wrap it in an Object-Array just like any other parameter.
The objective is simple, I want to create a method which load a class dynamically, access its method and passing their parameters value and getting the return value at run-time.
Class which will be called
class MyClass {
public String sayHello() {
return "Hello";
}
public String sayGoodbye() {
return "Goodbye";
}
public String saySomething(String word){
return word;
}
}
Main Class
public class Main {
public void loadClass() {
try {
Class myclass = Class.forName(getClassName());
//Use reflection to list methods and invoke them
Method[] methods = myclass.getMethods();
Object object = myclass.newInstance();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().startsWith("saySome")) {
String word = "hello world";
//**TODO CALL OBJECT METHOD AND PASS ITS PARAMETER**
} else if (methods[i].getName().startsWith("say")) {
//call method
System.out.println(methods[i].invoke(object));
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
private String getClassName() {
//Do appropriate stuff here to find out the classname
return "com.main.MyClass";
}
public static void main(String[] args) throws Exception {
new Main().loadClass();
}
}
My question is how to invoke method with parameters and passing its value? also getting the return value and its type.
I think you're just missing the fact that you can pass in arguments to invoke, as an Object[]:
Object result = methods[i].invoke(object, new Object[] { word });
Or using varargs, if you prefer:
Object result = methods[i].invoke(object, word);
(The above two calls are equivalent.)
See the documentation for Method.invoke for more details.
simply create the object of MyClass invoke the function like this
MyClass mc = new MyClass();
String word = "hello world";
String returnValue = mc.saySomething(word);
System.out.println(returnValue);//return hello world here
or do this
Class myclass = Class.forName(getClassName());
Method mth = myclass.getDeclaredMethod(methodName, params);
Object obj = myclass.newInstance();
String result = (String)mth.invoke(obj, args);
Try ::
Class c = Class.forName(className);
Method m = c.getDeclaredMethod(methodName, params);
Object i = c.newInstance();
String result = (String)m.invoke(i, args);
I am trying to use mirroring to call a method s1 of my class MyClass, with the parameter s2. Java is complaining that String.TYPE does not exist. I checked the API and it is right: I cannot do the same thing as when I call Integer.TYPE. But how can I solve the problem then? I need partype of type String, or else the method throws an exception.
public void trying(MyClass method, String s1, String s2){
try {
Class cls = Class.forName("MyClass");
Class partype[] = new Class[1];
partype[0] = String.TYPE;
Method meth = cls.getMethod(s1, partype);
meth.invoke(methobj, s2);
}
catch (Throwable e) {
System.err.println(e);
}
}
It's not a type, it's a class:
partype[0] = String.class;