如何在Java反射的情况下将参数传递给调用方法的可变参数(reflected class)?

huangapple go评论75阅读模式
英文:

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 并传递 bzzarrayType

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 = &lt;array of Bs&gt;;
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(&quot;&quot;, (acc, x) -&gt; acc + x + &quot;,&quot;);
        System.out.println(&quot;params (&quot; + b.length + &quot;): &quot; + s);
    }
}

And final code:

public static void main(String[] args) {
        B bObject1 = (B) bzz.getDeclaredConstructor(String.class).newInstance(&quot;b0&quot;);
        B bObject2 = (B) bzz.getDeclaredConstructor(String.class).newInstance(&quot;b1&quot;);

        System.out.println(&quot;invoking with no args&quot;);
        methodAReflected.invoke(aObject, (Object) new B[]{});

        System.out.println(&quot;invoking with bObject1&quot;);
        methodAReflected.invoke(aObject, (Object) new B[]{bObject1});

        System.out.println(&quot;invoking with bObject1 and bObject2&quot;);
        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() -&gt; 1

So let's see the parameter:

methodAReflected.getParameters() -&gt; com.example.springsandbox.vararg.B... b
methodAReflected.getParameters()[0].executable -&gt; public void com.example.springsandbox.vararg.A.methodA(com.example.springsandbox.vararg.B[])

huangapple
  • 本文由 发表于 2023年5月10日 14:44:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76215566.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定