Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to call a method from java whose name is send? #3576

Closed
AlexeyMatskevich opened this issue May 31, 2024 · 2 comments
Closed

How to call a method from java whose name is send? #3576

AlexeyMatskevich opened this issue May 31, 2024 · 2 comments
Labels

Comments

@AlexeyMatskevich
Copy link

I installed pulsar client on java in my truffleruby-jvm 24.0.1 installation, compiled with Gradle 8.7 and tried to use it (I have absolutely no knowledge of Java and don't know how right I am doing everything).
Here's an example of how I work with a client:

Java.add_to_classpath("/app/pulsar-java-client/lib/build/libs/lib-all.jar")
pulsar = Java.type('org.apache.pulsar.client.api.PulsarClient')
client = pulsar.builder.serviceUrl(ENV["PULSAR_URL"]).build

producer = client.newProducer.topic("my-topic").create

next step, I try to send a message using the pulsar client documentation as a primary source:

Producer<String> stringProducer = client.newProducer(Schema.STRING)
        .topic("my-topic")
        .create();
stringProducer.send("My message");

Unfortunately, I don't understand how I can call the send (java version) method, given the fact that the ruby Object class already defines this method.
Is there any way around this in any way?

@AlexeyMatskevich
Copy link
Author

AlexeyMatskevich commented May 31, 2024

This seems to be done as follows

producer['send'].call(-> {"My message"})

but I seem to be having trouble typing.

producer['send'].call(-> {"My message"})
#<Polyglot::ForeignException[Java] java.lang.ClassCastException:0x71cdc44c: class com.oracle.truffle.polyglot.PolyglotMapAndFunction cannot be cast to class java.lang.String (com.oracle.truffle.polyglot.PolyglotMapAndFunction is in module org.graalvm.truffle of loader 'app'; java.lang.String is in module java.base of loader 'bootstrap')>
backtraces are hidden because TruffleRuby doesn't have a case for the org.truffleruby.language.objects.IsCopyableObjectNodeGen node with values of type com.oracle.truffle.host.HostException
        from org.truffleruby.language.objects.IsCopyableObjectNodeGen.executeAndSpecialize(IsCopyableObjectNodeGen.java:168)
        from org.truffleruby.language.objects.IsCopyableObjectNodeGen.execute(IsCopyableObjectNodeGen.java:113)
        from org.truffleruby.core.kernel.KernelNodesFactory$CloneNodeFactory$CloneNodeGen.executeAndSpecialize(KernelNodesFactory.java:2953)
        from org.truffleruby.core.kernel.KernelNodesFactory$CloneNodeFactory$CloneNodeGen.execute(KernelNodesFactory.java:2935)
        from org.truffleruby.language.control.SequenceNode.execute(SequenceNode.java:38)
        from org.truffleruby.language.RubyMethodRootNode.execute(RubyMethodRootNode.java:65) was raised when processing them

Even if one tries to use Java types (if I'm doing it right)

irb(main):007> ST = Java.type('java.lang.String')
=> #<Polyglot::ForeignClass[Java] type java.lang.String>
irb(main):009> s = ST.new("Hello, world")
=> "Hello, world"
irb(main):012> producer['send'].call(-> {s})
#<Polyglot::ForeignException[Java] java.lang.ClassCastException:0x68d272c7: class com.oracle.truffle.polyglot.PolyglotMapAndFunction cannot be cast to class java.lang.String (com.oracle.truffle.polyglot.PolyglotMapAndFunction is in module org.graalvm.truffle of loader 'app'; java.lang.String is in module java.base of loader 'bootstrap')>
backtraces are hidden because TruffleRuby doesn't have a case for the org.truffleruby.language.objects.IsCopyableObjectNodeGen node with values of type com.oracle.truffle.host.HostException
        from org.truffleruby.language.objects.IsCopyableObjectNodeGen.executeAndSpecialize(IsCopyableObjectNodeGen.java:168)
        from org.truffleruby.language.objects.IsCopyableObjectNodeGen.execute(IsCopyableObjectNodeGen.java:113)
        from org.truffleruby.core.kernel.KernelNodesFactory$CloneNodeFactory$CloneNodeGen.executeAndSpecialize(KernelNodesFactory.java:2953)
        from org.truffleruby.core.kernel.KernelNodesFactory$CloneNodeFactory$CloneNodeGen.execute(KernelNodesFactory.java:2935)
        from org.truffleruby.language.control.SequenceNode.execute(SequenceNode.java:38)
        from org.truffleruby.language.RubyMethodRootNode.execute(RubyMethodRootNode.java:65) was raised when processing them

@eregon
Copy link
Member

eregon commented Jun 3, 2024

This works fine:

Dir.glob("pulsar-client/*.jar").each { |f| Java.add_to_classpath File.expand_path f }
pulsar = Java.type('org.apache.pulsar.client.api.PulsarClient')
p pulsar
client = pulsar.builder.serviceUrl("pulsar://localhost:6650/").build
p client

Schema = Java.type('org.apache.pulsar.client.api.Schema')
producer = client.newProducer(Schema.STRING).topic("my-topic").create
p producer

producer[:send].call("My message")
# Or:
Truffle::Interop.invoke_member(producer, :send, "My message")

I followed https://pulsar.apache.org/docs/next/getting-started-standalone/ (including running bin/pulsar standalone)
and https://pulsar.apache.org/docs/next/client-libraries-java-setup/
and downloaded all Maven jars to a folder with https://stackoverflow.com/a/75183691/388803

So it's producer[:send].call("My message") not producer['send'].call(-> {"My message"}) which would pass a Proc and not a String.
The Schema.STRING is also needed otherwise the API seems to expect [B, i.e. byte[].
There is also Truffle::Interop.invoke_member(producer, :send, "My message") which uses interop explicitly.

@eregon eregon closed this as completed Jun 3, 2024
@eregon eregon added the polyglot label Jun 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants