Call methods of a class generated in runtime

Offen
#166 12 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Anfängerfreundlichkeit
25/100
Issue-Typ
Bug
Klarheit
Größtenteils klar
Aktivitätsstatus
Veraltet
Tech-Stack
java, julia
Bereich
tooling

Rechercherichtung

Reproduziere den Fehler mit dem InMemoryJavaCompiler-Beispiel aus dem Issue und beginne dann in JavaCall's core.jl rund um jcall und die gemeldeten Zeilen 244 und 373. Vergleiche gewöhnliches Dispatch mit dem reflectionsbasierten jcall2-Pfad; abgeschlossen ist die Aufgabe, wenn Methoden auf dynamisch kompilierten Klassen über jcall aufgerufen werden können, während geerbte Methoden weiterhin funktionieren.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

jcall fails with NoSuchMethodError when calling methods of a dynamically compiled class.

I use InMemoryJavaCompiler to compile a new class and create its instance. (InMemoryJavaCompiler is based on javax.tools.*, so quite standard approach).

const JInMemoryJavaCompiler = @jimport org.mdkt.compiler.InMemoryJavaCompiler

function mkclass(name::String, src::String)
    jcompiler = jcall(JInMemoryJavaCompiler, "newInstance", JInMemoryJavaCompiler, ())
    return jcall(jcompiler, "compile", JClass, (JString, JString), name, src)
end

function instantiate(name::String, src::String)
    jclass = mkclass(name, src)
    return jcall(jclass, "newInstance", JObject, ())
end


init()
name = "julia.compiled.Hello"
src = """
        package julia.compiled;

        public class Hello {

            public String hello(String name) {
                return "Hello, " + name;
            }

            public void goodbye() {
                System.out.println("Goodbye!");
            }
        }
    """

obj = instantiate(name, src)

The resulting object looks like the ordinary one and I can see the methods I defined:

julia> listmethods(obj)
11-element Vector{JMethod}:
 java.lang.String hello(java.lang.String)
 void goodbye()
 void wait(long)
 void wait(long, int)
 void wait()
 boolean equals(java.lang.Object)
 java.lang.String toString()
 int hashCode()
 java.lang.Class getClass()
 void notify()
 void notifyAll()

However, calling them with jcall fails, even though calling the inherited methods works fine:

julia> jcall(obj, "hello", JString, (JString,), "Bob")
Exception in thread "main" java.lang.NoSuchMethodError: hello
ERROR: JavaCall.JavaCallError("Error calling Java: java.lang.NoSuchMethodError: hello")
Stacktrace:
 [1] geterror(allow::Bool)
   @ JavaCall ~/.julia/packages/JavaCall/MlduK/src/core.jl:418
 [2] jcall(obj::JObject, method::String, rettype::Type, argtypes::Tuple{DataType}, args::String)
   @ JavaCall ~/.julia/packages/JavaCall/MlduK/src/core.jl:244
 [3] top-level scope
   @ REPL[13]:1

julia> jcall(obj, "goodbye", Nothing, ())
Exception in thread "main" java.lang.NoSuchMethodError: goodbye
ERROR: JavaCall.JavaCallError("Error calling Java: java.lang.NoSuchMethodError: goodbye")
Stacktrace:
 [1] geterror(allow::Bool)
   @ JavaCall ~/.julia/packages/JavaCall/MlduK/src/core.jl:418
 [2] jcall(::JObject, ::String, ::Type, ::Tuple{})
   @ JavaCall ~/.julia/packages/JavaCall/MlduK/src/core.jl:244
 [3] top-level scope
   @ REPL[14]:1

julia> jcall(obj, "equals", jboolean, (JObject,), obj)
0x01

What's even more confusing, these new methods can actually be called using the reflection:

function jcall2(jobj::JavaObject, name::String, ret_type, arg_types, args...)
    jclass = getclass(jobj)
    jargs = [a for a in convert.(arg_types, args)]  # convert to Vector
    meth = jcall(jclass, "getMethod", JMethod, (JString, Vector{JClass}), name, getclass.(jargs))
    return meth(jobj, jargs...)
end

julia> jcall2(obj, "hello", JString, (JString,), "Bob")
"Hello, Bob"

julia> jcall2(obj, "goodbye", Nothing, ())
Goodbye!

Although it fails with NoSuchMethodException for the inherited method ¯_(ツ)_/¯:

julia> jcall2(obj, "equals", jboolean, (JObject,), obj)
Exception in thread "main" java.lang.NoSuchMethodException: julia.compiled.Hello.equals(julia.compiled.Hello)
        at java.base/java.lang.Class.getMethod(Class.java:2108)
ERROR: JavaCall.JavaCallError("Error calling Java: java.lang.NoSuchMethodException: julia.compiled.Hello.equals(julia.compiled.Hello)")
Stacktrace:
 [1] geterror(allow::Bool)
   @ JavaCall ~/.julia/packages/JavaCall/MlduK/src/core.jl:418
 [2] geterror
   @ ~/.julia/packages/JavaCall/MlduK/src/core.jl:403 [inlined]
 [3] _jcall(::JClass, ::Ptr{Nothing}, ::Ptr{Nothing}, ::Type, ::Tuple{DataType, DataType}, ::String, ::Vararg{Any})
   @ JavaCall ~/.julia/packages/JavaCall/MlduK/src/core.jl:373
 [4] jcall(::JClass, ::String, ::Type, ::Tuple{DataType, DataType}, ::String, ::Vararg{Any})
   @ JavaCall ~/.julia/packages/JavaCall/MlduK/src/core.jl:245
 [5] jcall2(jobj::JObject, name::String, ret_type::Type, arg_types::Tuple{DataType}, args::JObject)
   @ Main ./REPL[17]:4
 [6] top-level scope
   @ REPL[18]:1

The code above is executable from the Spark#new-api branch, but honestly I hope that I'm just doing some stupid mistake that a keen eye can catch just from the description.

Vorherrschende Sprache
Julia
Sterne
125
Forks
53
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus JuliaInterop/JavaCall.jl

Alle Issues in JuliaInterop/JavaCall.jl

Ähnliche Issues

Weitere Issues zu Julia

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.