Error: NullPointerException in the Event Handler
Closed this issue · 1 comments
Hello,
first of all: A big thanks for driving this project forward.
I am posting this here because issues seem to be disabled on your Bukkit4Clojure fork
When I generate a new lein project according to your instructions and then trying to put the example event handler code in it,
I cannot produce the uberjar of my project. While compiling, the error log is as following:
{:clojure.main/message
"Execution error (NullPointerException) at bukkitclj.event/register-event (event.clj:48).\nnull\n",
:clojure.main/triage
{:clojure.error/class java.lang.NullPointerException,
:clojure.error/line 48,
:clojure.error/symbol bukkitclj.event/register-event,
:clojure.error/source "event.clj",
:clojure.error/phase :execution},
:clojure.main/trace
{:via
[{:type clojure.lang.Compiler$CompilerException,
:message "Syntax error macroexpanding at (plugin.clj:19:1).",
:data
{:clojure.error/phase :execution,
:clojure.error/line 19,
:clojure.error/column 1,
:clojure.error/source "plugin.clj"},
:at [clojure.lang.Compiler$InvokeExpr eval "Compiler.java" 3707]}
{:type java.lang.NullPointerException,
:at [bukkitclj.event$register_event invokeStatic "event.clj" 48]}],
:trace
[[bukkitclj.event$register_event invokeStatic "event.clj" 48]
[bukkitclj.event$register_event invoke "event.clj" 36]
[bukkitclj.event$register_event invokeStatic "event.clj" 40]
[bukkitclj.event$register_event invoke "event.clj" 36]
[lobbymania.plugin$fn__472 invokeStatic "plugin.clj" 20]
[lobbymania.plugin$fn__472 invoke "plugin.clj" 19]
[clojure.lang.AFn applyToHelper "AFn.java" 152]
[clojure.lang.AFn applyTo "AFn.java" 144]
[clojure.lang.Compiler$InvokeExpr eval "Compiler.java" 3702]
[clojure.lang.Compiler compile1 "Compiler.java" 7731]
[clojure.lang.Compiler compile "Compiler.java" 7798]
[clojure.lang.RT compile "RT.java" 411]
[clojure.lang.RT load "RT.java" 457]
[clojure.lang.RT load "RT.java" 424]
[clojure.core$load$fn__6839 invoke "core.clj" 6126]
[clojure.core$load invokeStatic "core.clj" 6125]
[clojure.core$load doInvoke "core.clj" 6109]
[clojure.lang.RestFn invoke "RestFn.java" 408]
[clojure.core$load_one invokeStatic "core.clj" 5908]
[clojure.core$compile$fn__6844 invoke "core.clj" 6136]
[clojure.core$compile invokeStatic "core.clj" 6136]
[clojure.core$compile invoke "core.clj" 6128]
[user$eval155$fn__164 invoke "form-init1447454908815526697.clj" 1]
[user$eval155 invokeStatic "form-init1447454908815526697.clj" 1]
[user$eval155 invoke "form-init1447454908815526697.clj" 1]
[clojure.lang.Compiler eval "Compiler.java" 7177]
[clojure.lang.Compiler eval "Compiler.java" 7167]
[clojure.lang.Compiler eval "Compiler.java" 7167]
[clojure.lang.Compiler load "Compiler.java" 7636]
[clojure.lang.Compiler loadFile "Compiler.java" 7574]
[clojure.main$load_script invokeStatic "main.clj" 475]
[clojure.main$init_opt invokeStatic "main.clj" 477]
[clojure.main$init_opt invoke "main.clj" 477]
[clojure.main$initialize invokeStatic "main.clj" 508]
[clojure.main$null_opt invokeStatic "main.clj" 542]
[clojure.main$null_opt invoke "main.clj" 539]
[clojure.main$main invokeStatic "main.clj" 664]
[clojure.main$main doInvoke "main.clj" 616]
[clojure.lang.RestFn applyTo "RestFn.java" 137]
[clojure.lang.Var applyTo "Var.java" 705]
[clojure.main main "main.java" 40]],
:phase :execution}}
From plugin.clj:
(ns lobbymania.plugin
(:gen-class
:name lobbymania.Lobbymania
:extends bukkitclj.ClojurePlugin)
(:import [org.bukkit.plugin.java JavaPlugin]))
(set! *warn-on-reflection* true)
(defn -onEnable [^JavaPlugin this]
(.. this (getLogger) (info "Clojure plugin Lobbymania enabled")))
(defn -onDisable [^JavaPlugin this])
(require '[bukkitclj.event :as ev])
(require '[bukkitclj.repl])
(ev/find-event "player-toggle")
(ev/describe-event :player/player-toggle-sneak)
;; use a reference to your own plugin instance here...
(let [plugin (deref bukkitclj.repl/plugin-ref)]
(ev/register-event plugin
:player/player-toggle-sneak
(fn [e] (println "event triggered!"))
:priority/normal))
I looked at the event.clj file line 48, where it says:
(bk/plugin-manager)
But this refers to bukkit.clj which contains the macro
I do not know why the compiler even tries to runtime-check the value of plugin-manager against null, as this variable will be set on runtime and can never be initialized in an isolated environment.
Maybe I am getting something wrong here though, correct me if i do 😄
Thanks for looking into this,
m0rtis0
This is simply a matter of understanding the difference between compile-time and run-time. The plugins must be AoT (ahead-of-time) compiled. When this happens, all top-level forms are evaluated. Most of the lines after the -onDisable
function assume that the plugin is running in the Minecraft server. Obviously, this is not the case at compile time. The fix is easy, put everything after -onDisable
in a (comment ...)
expression or wrap them all in a function. Then connect to the repl and invoke the expressions/function.
To go a little deeper here, the deref
call is always going to return nil at compile-time, because that ref gets initialized in Bukkit4Clojure's on-enable function, which only gets called when the Minecraft server loads the plugin:
https://github.com/cpmcdaniel/Bukkit4Clojure/blob/master/src/clojure/bukkitclj/repl.clj#L93
Hope this helps! Closing the issue. Let me know if this does not solve your problem.