英文:
How to pass parameter to invoke method as a vararg of a relfected class in case of Java reflection?
问题
I have a project in which I am using a third party library. However, I need to call methods from the third party only if the user has copied those jars in the project, or else use the existing jars. For this purpose I am using reflection for creating the classes and calling the methods from this third party library.
我有一个项目,其中我使用了一个第三方库。然而,只有在用户将这些JAR文件复制到项目中时,我才需要调用第三方的方法,否则使用现有的JAR文件。为了实现这个目的,我正在使用反射来创建这个第三方库的类并调用方法。
One of the methods from the library expects varargs of another class from the same library as argument. Since both the classes have been created in my main class using reflection and also their corresponding methods have been created using reflection, how do we pass argument as vararg of a class to the methodname. invoke() method?
库中的一个方法需要另一个来自同一库的类的可变参数作为参数。由于这两个类都是在我的主类中使用反射创建的,它们的对应方法也是使用反射创建的,那么我们如何将类的可变参数作为参数传递给**invoke()**方法呢?
Refer the code snippet ahead.
请参考下面的代码片段。
//-------Class A-----------------
package com.demoA;
Class A {
public void methodA(B... b) {
// Contents of methodA...
}
}
//-------Class B-----------------
package com.demoB;
Class B {
// contents of class B here...
}
//-------Class MainClass-------------
package com.mainclass;
Class MainClass {
public static void main(String[] args) {
Class<?> azz = Class.forName("com.demoA.A");
Object aObject = azz.getDeclaredConstructor().newInstance();
Method methodAReflected = null;
for (Method m : azz.getMethods) {
if (m.getName.equals("methodA")) {
methodAReflected = m;
}
}
Class bzz = Class.forName("com.demoB.B");
Object bObject = bzz.getDeclaredConstructor().newInstance();
methodAReflected.invoke(aObject, <how to pass varargs here>);
// Passing only bObject or new Object[] { bObject } result in an IllegalArgumentException : type mismatch
}
}
Also, is there is any better way (rather than iterating through the method names) to use Java reflection's getMethod() method to create the reflected method when the expected parameter is a vararg?
此外,是否有更好的方法(而不是遍历方法名称)来使用Java反射的**getMethod()**方法在期望的参数是可变参数时创建反射方法?
英文:
I have a project in which I am using a third party library. However, I need to call methods from the third party only if the user has copied those jars in the project, or else use the existing jars. For this purpose I am using reflection for creating the classes and calling the methods from this third party library.
One of the methods from the library expects varargs of another class from the same library as argument. Since both the classes have been created in my main class using reflection and also their corresponding methods have been created using reflection, how do we pass argument as vararg of a class to the methodname.invoke() method?
Refer the code snippet ahead.
//-------Class A-----------------
package com.demoA;
Class A {
public void methodA(B... b) {
// Contents of methodA...
}
}
//-------Class B-----------------
package com.demoB;
Class B {
// contents of class B here...
}
//-------Class MainClass-------------
package com.mainclass;
Class MainClass {
public static void main(String[] args) {
Class<?> azz = Class.forName("com.demoA.A");
Object aObject = azz.getDeclaredConstructor().newInstance();
Method methodAReflected = null;
for (Method m : azz.getMethods) {
if (m.getName.equals("methodA")) {
methodAReflected = m;
}
}
Class bzz = Class.forName("com.demoB.B");
Object bObject = bzz.getDeclaredConstructor().newInstance();
methodAReflected.invoke(aObject, <how to pass varargs here>);
// Passing only bObject or new Object[] { bObject } result in an IllegalArgumentException : type mismatch
}
}
Also, is there is any better way (rather than iterating through the method names) to use Java reflection's getMethod() method to create the reflected method when the expected parameter is a vararg?
答案1
得分: 1
Use Array.newInstance
来创建一个新的数组,并使用 Array.set
来设置其元素。
Object methodAVarargs = Array.newInstance(bzz, 1);
Array.set(methodAVarargs, 0, bObject);
methodAReflected.invoke(aObject, methodAVarargs);
要找到一个较短的代码方法,您可以使用 get(Declared)Method
并传递 bzz
的 arrayType
:
Method methodAReflected = azz.getDeclaredMethod("methodA", bzz.arrayType());
英文:
Use Array.newInstance
to create a new array, and use Array.set
to set its elements.
Object methodAVarargs = Array.newInstance(bzz, 1);
Array.set(methodAVarargs, 0, bObject);
methodAReflected.invoke(aObject, methodAVarargs);
To find the method with a shorter code, you can use get(Declared)Method
and pass the arrayType
of bzz
:
Method methodAReflected = azz.getDeclaredMethod("methodA", bzz.arrayType());
答案2
得分: 0
你可以尝试以类似以下方式调用它:
B[] bObjectArray = <B对象数组>;
methodAReflected.invoke(aObject, (Object) bObjectArray);
另外,你可以查看官方的Oracle教程,在使用可变数量的参数调用方法部分,你可以找到一个类似你所需的示例。
英文:
You can try to call it with approach like this:
B[] bObjectArray = <array of Bs>;
methodAReflected.invoke(aObject, (Object) bObjectArray);
Also you can check official tutorial from Oracle, where in section Invoking Methods with a Variable Number of Arguments you can find example of using something similar that you need.
答案3
得分: 0
以下是翻译好的部分:
"At first, I added some debug code to see the real invocations:"(起初,我添加了一些调试代码来查看实际调用:)
// add identificator to the class
class B {
private final String id;
public B(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
// print args on invocation
class A {
public void methodA(B... b) {
var s = Arrays.stream(b).map(B::getId).reduce("", (acc, x) -> acc + x + ",");
System.out.println("params (" + b.length + "): " + s);
}
}
"And final code:"(最终代码:)
public static void main(String[] args) {
B bObject1 = (B) bzz.getDeclaredConstructor(String.class).newInstance("b0");
B bObject2 = (B) bzz.getDeclaredConstructor(String.class).newInstance("b1");
System.out.println("invoking with no args");
methodAReflected.invoke(aObject, (Object) new B[]{});
System.out.println("invoking with bObject1");
methodAReflected.invoke(aObject, (Object) new B[]{bObject1});
System.out.println("invoking with bObject1 and bObject2");
methodAReflected.invoke(aObject, (Object) new B[]{bObject1, bObject2});
}
"Output:"(输出:)
invoking with no args
params (0):
invoking with bObject1
params (1): b0,
invoking with bObject1 and bObject2
params (2): b0,b1,
"Why so?"(为什么这样?)
"Firstly, the method always takes one parameter:"(首先,该方法始终只接受一个参数:)
"methodAReflected.getParameterCount() -> 1"(methodAReflected.getParameterCount() -> 1)
"So let's see the parameter:"(那么让我们看看这个参数:)
"methodAReflected.getParameters() -> com.example.springsandbox.vararg.B... b"(methodAReflected.getParameters() -> com.example.springsandbox.vararg.B... b)
"methodAReflected.getParameters()[0].executable -> public void com.example.springsandbox.vararg.A.methodA(com.example.springsandbox.vararg.B[])"(methodAReflected.getParameters()[0].executable -> public void com.example.springsandbox.vararg.A.methodA(com.example.springsandbox.vararg.B[]))
英文:
At first, I added some debug code to see the real invocations:
// add identificator to the class
class B {
private final String id;
public B(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
// print args on invocation
class A {
public void methodA(B... b) {
var s = Arrays.stream(b).map(B::getId).reduce("", (acc, x) -> acc + x + ",");
System.out.println("params (" + b.length + "): " + s);
}
}
And final code:
public static void main(String[] args) {
B bObject1 = (B) bzz.getDeclaredConstructor(String.class).newInstance("b0");
B bObject2 = (B) bzz.getDeclaredConstructor(String.class).newInstance("b1");
System.out.println("invoking with no args");
methodAReflected.invoke(aObject, (Object) new B[]{});
System.out.println("invoking with bObject1");
methodAReflected.invoke(aObject, (Object) new B[]{bObject1});
System.out.println("invoking with bObject1 and bObject2");
methodAReflected.invoke(aObject, (Object) new B[]{bObject1, bObject2});
}
Output:
invoking with no args
params (0):
invoking with bObject1
params (1): b0,
invoking with bObject1 and bObject2
params (2): b0,b1,
Quite simple. All we need to remember is that we pass the args as raw Object
.
Why so?
Firstly, the method always takes one parameter:
methodAReflected.getParameterCount() -> 1
So let's see the parameter:
methodAReflected.getParameters() -> com.example.springsandbox.vararg.B... b
methodAReflected.getParameters()[0].executable -> public void com.example.springsandbox.vararg.A.methodA(com.example.springsandbox.vararg.B[])
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论