cpmcdaniel/bukkit-for-clojure-template

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.