Graal: [native-image] [clojure] Can not call instance method (outside of main)

Created on 29 Oct 2018  路  2Comments  路  Source: oracle/graal

I created Jar with Clojure and Leiningen, and created Native Image from Jar.

Error: Instance that is defined outside of main does not have any methods.
OK: Instance that is defined inside of main have methods correctly.

Why?

GraalVM Version

> java -version
openjdk version "1.8.0_172"
OpenJDK Runtime Environment (build 1.8.0_172-20180626105433.graaluser.jdk8u-src-tar-g-b11)
GraalVM 1.0.0-rc8 (build 25.71-b01-internal-jvmci-0.48, mixed mode)

src/hello/core.clj

(ns hello.core
  (:gen-class))


;; Create Instance outside of main.
(def d (java.util.Date.))

(defn -main [& args]

  ;; Check Java Version
  (println "Check Java Version:" (System/getProperty "java.version")) ;; => 1.8.0_172

  ;; Call Inside Instance Method => OK
  ;; (println (.getTime (java.util.Date.))) ;; => 1540819744354

  ;; Call Outside Instance Method => error
  (println "Call Instance Method:" (.getTime d))) ;; => error

Run

> lein run
Compiling hello.core
Check Java Version: 1.8.0_172
Call Instance Method: 1540824144643

Create Jar

> lein uberjar
Compiling hello.core
Created ....../target/hello-1.0.0.jar
Created ....../target/hello-1.0.0-standalone.jar

Run Jar

> cd target/ 
> java -jar hello-1.0.0-standalone.jar
Check Java Version: 1.8.0_172
Call Instance Method: 1540824203620

Create Native Image

> native-image -jar hello-1.0.0-standalone.jar
Build on Server(pid: 14299, port: 53397)
[hello-1.0.0-standalone:14299]    classlist:   2,715.99 ms
[hello-1.0.0-standalone:14299]        (cap):   1,077.03 ms
[hello-1.0.0-standalone:14299]        setup:   1,583.26 ms
[hello-1.0.0-standalone:14299]   (typeflow):   4,502.79 ms
[hello-1.0.0-standalone:14299]    (objects):   2,659.10 ms
[hello-1.0.0-standalone:14299]   (features):      94.75 ms
[hello-1.0.0-standalone:14299]     analysis:   7,417.43 ms
[hello-1.0.0-standalone:14299]     universe:     271.41 ms
[hello-1.0.0-standalone:14299]      (parse):     841.99 ms
[hello-1.0.0-standalone:14299]     (inline):     900.53 ms
[hello-1.0.0-standalone:14299]    (compile):   4,986.20 ms
[hello-1.0.0-standalone:14299]      compile:   7,245.65 ms
[hello-1.0.0-standalone:14299]        image:   1,329.76 ms
[hello-1.0.0-standalone:14299]        write:     577.77 ms
[hello-1.0.0-standalone:14299]      [total]:  21,193.99 ms

Run Native Image

Check Java Version: 1.8.0_172
Exception in thread "main" java.lang.IllegalArgumentException: No matching field found: getTime for class java.util.Date
    at java.lang.Throwable.<init>(Throwable.java:265)
    at java.lang.Exception.<init>(Exception.java:66)
    at java.lang.RuntimeException.<init>(RuntimeException.java:62)
    at java.lang.IllegalArgumentException.<init>(IllegalArgumentException.java:52)
    at clojure.lang.Reflector.getInstanceField(Reflector.java:271)
    at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:315)
    at hello.core$_main.invokeStatic(core.clj:17)
    at hello.core$_main.doInvoke(core.clj:8)
    at clojure.lang.RestFn.invoke(RestFn.java:397)
    at clojure.lang.AFn.applyToHelper(AFn.java:152)
    at clojure.lang.RestFn.applyTo(RestFn.java:132)
    at hello.core.main(Unknown Source)
    at com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:164)

Most helpful comment

The problem is solved.
I understood Substrate VM limitations and the behavior of Clojure.

Clojure call method by Reflection, and Substrate VM has LIMITATIONS.

Understanding Class Initialization in GraalVM Native Image Generation

Substrate VM Java Limitations

at clojure.lang.Reflector.getInstanceField(Reflector.java:271)
at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:315)

add this code.

(set! *warn-on-reflection* true)

print warning.

> lein run
Compiling hello.core
Reflection warning, hello/core.clj:14:3 - reference to field getTime can't be resolved.
Check Java Version: 1.8.0_172
Call Instance method with TypeHint: 1540830117929

add TypeHint to avoid reflection.

(ns hello.core
  (:gen-class))

(set! *warn-on-reflection* true)


;; Create Instance outside of main.
(def d (java.util.Date.))


(defn -main [& args]

  ;; Check Java Version
  (println "Check Java Version:" (System/getProperty "java.version")) ;; => 1.8.0_172

  ;; Call Inside Instance Method => OK
  ;; (println (.getTime (java.util.Date.))) ;; => 1540819744354

  ;; Call Outside Instance Method => error
  ;; (println "Call Instance Method:" (.getTime d)) ;; => error

  ;; Call Outside Instance Method with TypeHint => OK
  (println "Call Instance Method with TypeHint:" (.getTime ^java.util.Date d))) ;; => 1540819744354

Run Native Image

> ./hello-1.0.0-standalone
Check Java Version: 1.8.0_172
Call Instance method with TypeHint: 1540830495423

All 2 comments

The problem is solved.
I understood Substrate VM limitations and the behavior of Clojure.

Clojure call method by Reflection, and Substrate VM has LIMITATIONS.

Understanding Class Initialization in GraalVM Native Image Generation

Substrate VM Java Limitations

at clojure.lang.Reflector.getInstanceField(Reflector.java:271)
at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:315)

add this code.

(set! *warn-on-reflection* true)

print warning.

> lein run
Compiling hello.core
Reflection warning, hello/core.clj:14:3 - reference to field getTime can't be resolved.
Check Java Version: 1.8.0_172
Call Instance method with TypeHint: 1540830117929

add TypeHint to avoid reflection.

(ns hello.core
  (:gen-class))

(set! *warn-on-reflection* true)


;; Create Instance outside of main.
(def d (java.util.Date.))


(defn -main [& args]

  ;; Check Java Version
  (println "Check Java Version:" (System/getProperty "java.version")) ;; => 1.8.0_172

  ;; Call Inside Instance Method => OK
  ;; (println (.getTime (java.util.Date.))) ;; => 1540819744354

  ;; Call Outside Instance Method => error
  ;; (println "Call Instance Method:" (.getTime d)) ;; => error

  ;; Call Outside Instance Method with TypeHint => OK
  (println "Call Instance Method with TypeHint:" (.getTime ^java.util.Date d))) ;; => 1540819744354

Run Native Image

> ./hello-1.0.0-standalone
Check Java Version: 1.8.0_172
Call Instance method with TypeHint: 1540830495423

The problem is solved.
I understood Substrate VM limitations and the behavior of Clojure.

Clojure call method by Reflection, and Substrate VM has LIMITATIONS.

Understanding Class Initialization in GraalVM Native Image Generation

Substrate VM Java Limitations

at clojure.lang.Reflector.getInstanceField(Reflector.java:271)
at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:315)

add this code.

(set! *warn-on-reflection* true)

print warning.

> lein run
Compiling hello.core
Reflection warning, hello/core.clj:14:3 - reference to field getTime can't be resolved.
Check Java Version: 1.8.0_172
Call Instance method with TypeHint: 1540830117929

add TypeHint to avoid reflection.

(ns hello.core
  (:gen-class))

(set! *warn-on-reflection* true)


;; Create Instance outside of main.
(def d (java.util.Date.))


(defn -main [& args]

  ;; Check Java Version
  (println "Check Java Version:" (System/getProperty "java.version")) ;; => 1.8.0_172

  ;; Call Inside Instance Method => OK
  ;; (println (.getTime (java.util.Date.))) ;; => 1540819744354

  ;; Call Outside Instance Method => error
  ;; (println "Call Instance Method:" (.getTime d)) ;; => error

  ;; Call Outside Instance Method with TypeHint => OK
  (println "Call Instance Method with TypeHint:" (.getTime ^java.util.Date d))) ;; => 1540819744354

Run Native Image

> ./hello-1.0.0-standalone
Check Java Version: 1.8.0_172
Call Instance method with TypeHint: 1540830495423

awesome!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

koduki picture koduki  路  3Comments

igor-ramazanov picture igor-ramazanov  路  3Comments

janostgren picture janostgren  路  3Comments

sxend picture sxend  路  3Comments

helloguo picture helloguo  路  3Comments