Passing varargs to Java from Python using Py4j
Asked Answered
L

1

6

I am trying to pass varargs to Java code from python.

Java code : LogDebugCmd.java

public class LogDebugCmd implements Command {
  private Class clazz;
  private String format;
  private Object[] args;

  public LogDebugCmd() {}
  public void setLog(String format, Object... args) {
    this.format = format;
    this.args = args.clone();
    clazz = getClass();
  }

  @Override
  public void execute() {
    VLog.getLog(clazz).debug(format, args);
  }

CommandEntryPoint.java

public class CommandEntryPoint {
  private LogDebugCmd logDebugCmd;

  public CommandEntryPoint() {
    logDebugCmd = new LogDebugCmd();

  public LogDebugCmd getLogDebugCmd(String str, Object... args) {
    setLog(str, args);
    return logDebugCmd;
  }
  public static void main(String args[]) {
    GatewayServer gatewayServer = new GatewayServer(new CommandEntryPoint());
    gatewayServer.start();
    System.out.println("Gateway Server Started");
  }

Python code test.py:

from py4j.java_gateway import JavaGateway
gateway = JavaGateway()
logDebugCmd = gateway.entry_point.getLogDebugCmd("Step 01 - Test initiated.")
logDebugCmd..execute()

Error :

Traceback (most recent call last):
  File "C:/Python27/Lib/site-packages/py4j-0.10.3-py2.7.egg/py4j/sampleTLStest.py", line 4, in <module>
    logDebugCmd = gateway.entry_point.getLogDebugCmd("Step 01 - Test initiated.")
  File "C:\Python27\lib\site-packages\py4j-0.10.3-py2.7.egg\py4j\java_gateway.py", line 1133, in __call__
    answer, self.gateway_client, self.target_id, self.name)
  File "C:\Python27\lib\site-packages\py4j-0.10.3-py2.7.egg\py4j\protocol.py", line 323, in get_return_value
    format(target_id, ".", name, value))
***Py4JError: An error occurred while calling t.getLogDebugCmd. 
Trace:
py4j.Py4JException: Method getLogDebugCmd([class java.lang.String]) does not exist at py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.java:318)
at py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.java:326)
at py4j.Gateway.invoke(Gateway.java:272)
at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
at py4j.commands.CallCommand.execute(CallCommand.java:79)
at py4j.GatewayConnection.run(GatewayConnection.java:214)
at java.lang.Thread.run(Thread.java:745)***

Is there a way to pass varargs to Java ? I am trying to pass String as the second argument to getLogDebugCmd() which also errors out.

Lauryn answered 3/11, 2016 at 22:45 Comment(0)
S
6

Varargs are actually represented as an array so you can do this:

# Pass a None if you have no varargs
logDebugCmd = gateway.entry_point.getLogDebugCmd("Step 01 - Test initiated.", None)

# Create an array of objects
object_class = gateway.jvm.Object
object_array = gateway.new_array(object_class, 2)
object_array[0] = "foo"
object_array[1] = "bar"
logDebugCmd = gateway.entry_point.getLogDebugCmd("Step 01 - Test initiated.", object_array)

There is a pull request to improve varargs support in Py4J, but it has some compilation issues so it has not been merged yet.

Stirpiculture answered 4/11, 2016 at 9:43 Comment(3)
Thank you for the quick reply, @Stirpiculture ! This helped.Lauryn
Just one correction with passing 'None' -> Cast None to 'Object' type before passing it in place of Object... args. As a way to make it clear for Java that we are passing Null Object and not null in place of Object array. The later will lead to a NullPointerException. Ref: link. For example : object_array[0] = None logDebugCmd = gateway.entry_point.getLogDebugCmd("Step 01 - Test initiated.", object_array)Lauryn
Actually, it depends on the called code: if it checks whether args is null, you won't get a NullPointerException. Now thinking of it, you would be better of creating an empty array: object_array = gateway.new_array(object_class, 0).Stirpiculture

© 2022 - 2024 — McMap. All rights reserved.