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

NullPointerException when run from lein with :eval-in :leiningen #17

Open
lread opened this issue Sep 16, 2022 · 9 comments
Open

NullPointerException when run from lein with :eval-in :leiningen #17

lread opened this issue Sep 16, 2022 · 9 comments
Assignees

Comments

@lread
Copy link

lread commented Sep 16, 2022

Symptom

I was upgrading some pretty dated koacha deps in MrAnderson.
It was using version 0.0-32 of the kaocha-cloverage plugin.

After upgrading to the current kaocha versions, I encoutered NullPointerExceptions:

$ lein kaocha-coverage      
Error encountered performing task 'run' with profile(s): 'base,system,user,provided,dev,kaocha'
java.lang.NullPointerException
	at kaocha.plugin.cloverage$run_cloverage.invokeStatic(cloverage.clj:134)
	at kaocha.plugin.cloverage$run_cloverage.invoke(cloverage.clj:128)
	at kaocha.plugin.cloverage$cloverage_main_hook.invokeStatic(cloverage.clj:174)
	at kaocha.plugin.cloverage$cloverage_main_hook.invoke(cloverage.clj:143)
	at clojure.lang.AFn.applyToHelper(AFn.java:154)
	at clojure.lang.AFn.applyTo(AFn.java:144)
	at clojure.core$apply.invokeStatic(core.clj:669)
	at clojure.core$apply.invoke(core.clj:662)
	at kaocha.plugin$run_hook_STAR_$fn__2714.invoke(plugin.clj:91)
	at clojure.lang.PersistentVector.reduce(PersistentVector.java:343)
	at clojure.core$reduce.invokeStatic(core.clj:6885)
	at clojure.core$reduce.invoke(core.clj:6868)
	at kaocha.plugin$run_hook_STAR_.invokeStatic(plugin.clj:89)
	at kaocha.plugin$run_hook_STAR_.doInvoke(plugin.clj:88)
	at clojure.lang.RestFn.invoke(RestFn.java:445)
	at clojure.lang.AFn.applyToHelper(AFn.java:160)
	at clojure.lang.RestFn.applyTo(RestFn.java:132)
	at clojure.core$apply.invokeStatic(core.clj:673)
	at clojure.core$apply.invoke(core.clj:662)
	at kaocha.plugin$run_hook.invokeStatic(plugin.clj:100)
	at kaocha.plugin$run_hook.doInvoke(plugin.clj:99)
	at clojure.lang.RestFn.invoke(RestFn.java:425)
	at kaocha.runner$run$fn__3711.invoke(runner.clj:131)
	at clojure.lang.AFn.applyToHelper(AFn.java:152)
	at clojure.lang.AFn.applyTo(AFn.java:144)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at clojure.core$with_bindings_STAR_.invokeStatic(core.clj:1990)
	at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1990)
	at clojure.lang.RestFn.invoke(RestFn.java:425)
	at kaocha.runner$run.invokeStatic(runner.clj:130)
	at kaocha.runner$run.invoke(runner.clj:73)
	at kaocha.runner$_main_STAR_.invokeStatic(runner.clj:176)
	at kaocha.runner$_main_STAR_.doInvoke(runner.clj:144)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at clojure.core$apply.invoke(core.clj:662)
	at kaocha.runner$_main.invokeStatic(runner.clj:187)
	at kaocha.runner$_main.doInvoke(runner.clj:185)
	at clojure.lang.RestFn.invoke(RestFn.java:421)
	at clojure.lang.Var.invoke(Var.java:388)
	at user$eval663.invokeStatic(NO_SOURCE_FILE:0)
	at user$eval663.invoke(NO_SOURCE_FILE)
	at clojure.lang.Compiler.eval(Compiler.java:7194)
	at clojure.lang.Compiler.eval(Compiler.java:7184)
	at clojure.lang.Compiler.eval(Compiler.java:7149)
	at clojure.core$eval.invokeStatic(core.clj:3215)
	at clojure.core$eval.invoke(core.clj:3211)
	at leiningen.core.eval$fn__7195.invokeStatic(eval.clj:344)
	at leiningen.core.eval$fn__7195.invoke(eval.clj:336)
	at clojure.lang.MultiFn.invoke(MultiFn.java:234)
	at leiningen.core.eval$eval_in_project.invokeStatic(eval.clj:368)
	at leiningen.core.eval$eval_in_project.invoke(eval.clj:358)
	at leiningen.core.eval$eval_in_project.invokeStatic(eval.clj:362)
	at leiningen.core.eval$eval_in_project.invoke(eval.clj:358)
	at leiningen.run$run_main.invokeStatic(run.clj:130)
	at leiningen.run$run_main.invoke(run.clj:123)
	at leiningen.run$run.invokeStatic(run.clj:157)
	at leiningen.run$run.doInvoke(run.clj:134)
	at clojure.lang.RestFn.applyTo(RestFn.java:139)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.core$apply.invokeStatic(core.clj:669)
	at clojure.core$apply.invoke(core.clj:662)
	at leiningen.core.main$partial_task$fn__7376.doInvoke(main.clj:284)
	at clojure.lang.RestFn.applyTo(RestFn.java:139)
	at clojure.lang.AFunction$1.doInvoke(AFunction.java:31)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:669)
	at clojure.core$apply.invoke(core.clj:662)
	at leiningen.core.main$apply_task.invokeStatic(main.clj:334)
	at leiningen.core.main$apply_task.invoke(main.clj:320)
	at leiningen.with_profile$with_profiles_STAR_.invokeStatic(with_profile.clj:14)
	at leiningen.with_profile$with_profiles_STAR_.invoke(with_profile.clj:8)
	at leiningen.with_profile$apply_task_with_profiles.invokeStatic(with_profile.clj:53)
	at leiningen.with_profile$apply_task_with_profiles.invoke(with_profile.clj:45)
	at leiningen.with_profile$with_profile$fn__12011.invoke(with_profile.clj:85)
	at clojure.core$mapv$fn__8535.invoke(core.clj:6979)
	at clojure.core.protocols$fn__8249.invokeStatic(protocols.clj:168)
	at clojure.core.protocols$fn__8249.invoke(protocols.clj:124)
	at clojure.core.protocols$fn__8204$G__8199__8213.invoke(protocols.clj:19)
	at clojure.core.protocols$seq_reduce.invokeStatic(protocols.clj:31)
	at clojure.core.protocols$fn__8236.invokeStatic(protocols.clj:75)
	at clojure.core.protocols$fn__8236.invoke(protocols.clj:75)
	at clojure.core.protocols$fn__8178$G__8173__8191.invoke(protocols.clj:13)
	at clojure.core$reduce.invokeStatic(core.clj:6886)
	at clojure.core$mapv.invokeStatic(core.clj:6970)
	at clojure.core$mapv.invoke(core.clj:6970)
	at leiningen.with_profile$with_profile.invokeStatic(with_profile.clj:85)
	at leiningen.with_profile$with_profile.doInvoke(with_profile.clj:63)
	at clojure.lang.RestFn.applyTo(RestFn.java:146)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.core$apply.invokeStatic(core.clj:669)
	at clojure.core$apply.invoke(core.clj:662)
	at leiningen.core.main$partial_task$fn__7376.doInvoke(main.clj:284)
	at clojure.lang.RestFn.invoke(RestFn.java:410)
	at clojure.lang.AFn.applyToHelper(AFn.java:154)
	at clojure.lang.RestFn.applyTo(RestFn.java:132)
	at clojure.lang.AFunction$1.doInvoke(AFunction.java:31)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:669)
	at clojure.core$apply.invoke(core.clj:662)
	at leiningen.core.main$apply_task.invokeStatic(main.clj:334)
	at leiningen.core.main$apply_task.invoke(main.clj:320)
	at leiningen.core.main$resolve_and_apply.invokeStatic(main.clj:343)
	at leiningen.core.main$resolve_and_apply.invoke(main.clj:336)
	at leiningen.core.main$_main$fn__7465.invoke(main.clj:453)
	at leiningen.core.main$_main.invokeStatic(main.clj:442)
	at leiningen.core.main$_main.doInvoke(main.clj:439)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at clojure.main$main_opt.invokeStatic(main.clj:514)
	at clojure.main$main_opt.invoke(main.clj:510)
	at clojure.main$main.invokeStatic(main.clj:664)
	at clojure.main$main.doInvoke(main.clj:616)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.main.main(main.java:40)

Exploration

I had a peek a the plugin code that throws and saw:

decls (-> []
(.getClass)
(.getClassLoader)
(.getResources "data_readers.clj")
enumeration-seq)

If I try this in code in a lein repl I can reproduce the nil:

$ lein repl
nREPL server started on port 54918 on host 127.0.0.1 - nrepl://127.0.0.1:54918
REPL-y 0.5.1, nREPL 0.9.0
Clojure 1.11.1
OpenJDK 64-Bit Server VM 11.0.16.1+1
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> (-> [] (.getClass) (.getClassLoader))
nil

If I do this from a clojure REPL all is good:

$ clj
Clojure 1.11.1
user=> (-> [] (.getClass) (.getClassLoader))
#object[jdk.internal.loader.ClassLoaders$AppClassLoader 0x277050dc "jdk.internal.loader.ClassLoaders$AppClassLoader@277050dc"]

I noticed that this change came from lein-cloverage and found a similar issue raised over there.

I then noticed MrAnderson is using :eval-in :leiningen in its project.clj.

Workaround

In MrAnderson's project.clj :kaocha profile, I set :eval-in :sub-process.

Next Steps

Please feel free to close this issue if it is expected behaviour.

If it does represent an issue, I am happy to help in any way I can.

@plexus
Copy link
Member

plexus commented Sep 19, 2022

Hey, thanks for reporting this. I'm not sure what the intention is of (-> [] .getClass .getClassLoader), maybe @skuro remembers.

If we simply want to scan for data_reader files then I see no reasing why we can't use the currentContextClassloader. If for some reason we really want the system app classloader, then there's (ClassLoader/getSystemClassLoader) for that.

So yes a PR would be very appreciated. Try replacing (-> [] (.getClass) (.getClassLoader)) with (.getCurrenctContextClassloader (Thread/currentThread)). I see no reason why that wouldn't work. The only potential downside is that depending on which specific combo of tools you are using you could get quite a few different resutls from that call, but pretty much any compliant classloader should be good enough here. A similar change could also be made in lein-cloverage.

@lread
Copy link
Author

lread commented Sep 22, 2022

Thanks for the reply @plexus!

I can't say I understand the change nor why it doesn't work when :eval-in leiningen is active.

But... maybe that does not matter too much.
This change was trying to make sure data readers were found and enabled.
I could check that this is the case with (.getCurrenctContextClassloader (Thread/currentThread)) regardless of lein :eval-in values.

@humorless
Copy link
Member

humorless commented Apr 21, 2023

Hello @lread ,

My lein is of version Leiningen 2.9.8, and I have tried several different java, including Java.net, Microsoft, Temurin, Zulu.

  • I can not reproduce the nil returned by (-> [] (.getClass) (.getClassLoader))
  • I can not reproduce the error here.

It seems that the issues resolved in newer leiningen version.

@humorless humorless self-assigned this Apr 21, 2023
@humorless
Copy link
Member

It seems that the code

(-> [] (.getClass) (.getClassLoader))

is the same like here.

@humorless humorless moved this from Candidate to 👀 In review in Lambda Island Open Source May 4, 2023
@humorless humorless moved this from 👀 In review to ✅ Done in Lambda Island Open Source May 4, 2023
@lread
Copy link
Author

lread commented May 4, 2023

Hi @humorless, thanks for taking a look! ❤️

It seems that the code

(-> [] (.getClass) (.getClassLoader))

is the same like here.

Yes, this is what I noticed too and reported in the original issue.
But both @plexus and I did not exactly understand why.

I'm curious,
Is this issue closed because it is fixed?
Or because it is not considered an issue?
Or because it is stale and there wasn't much interest in fixing?

@humorless humorless reopened this May 4, 2023
@github-project-automation github-project-automation bot moved this from ✅ Done to 📋 Information Needed in Lambda Island Open Source May 4, 2023
@humorless
Copy link
Member

Hi @humorless, thanks for taking a look! ❤️

It seems that the code

(-> [] (.getClass) (.getClassLoader))

is the same like here.

Yes, this is what I noticed too and reported in the original issue. But both @plexus and I did not exactly understand why.

I'm curious, Is this issue closed because it is fixed? Or because it is not considered an issue? Or because it is stale and there wasn't much interest in fixing?

Hello @lread,

I have replied this issue, and I previously thought we get to good enough answer. (It seems that I was wrong.) I reopen it now.

I made my judgement by two facts which I believe. (But, you know, sometimes, I make mistakes.)

  1. (-> [] (.getClass) (.getClassLoader)) is a correct way to get ClassLoader. I have done certain search in the Internet.
  2. I can not reproduce (-> [] (.getClass) (.getClassLoader)) => nil in Leiningen repl.

Therefore, I guessed probably the issue disappears in the newer version of Leiningen.

@humorless humorless moved this from 📋 Information Needed to Candidate in Lambda Island Open Source May 4, 2023
@lread
Copy link
Author

lread commented May 4, 2023

Cool, thanks for following up!

@alysbrooks
Copy link
Member

We may actually want to close this issue if we can't reproduce it in the latest version of Leningen. @lread, have you run into this issue recently? Do you happen to know which version of Leiningen you were using?

I suppose another reason to keep this open is the (-> [] (.getClass) (.getClassLoader)) code. Although, based on Laurence's investigation, it's not clear why this wouldn't work. I almost wonder if it's an issue in Leiningen (perhaps fixed)?

JavaDocs for Class.getClassLoader say:

Every Class object contains a reference to the ClassLoader that defined it.

@alysbrooks
Copy link
Member

Okay, I did the obvious thing and tried lein repl on my machine. It failed on Leiningen 2.9.1 on Ubuntu on Java 13 with Clojure 1.10.1. However, it succeeded on a project running Clojure 1.10.3 and when I changed it to run Clojure 1.10.2. I thought it was the Clojrue version but then I tried it in the same project with Clojure 1.10.1 and it worked there.

I did find this on Clojuredocs:

`clojure

;; WARNING: If the examples above don't seem to return the expected results,
;; be aware that tools like Leiningen[https://leiningen.org/] or
;; nRepl[https://github.com/nrepl/nrepl] alter the context class loader.
;; Please use a vanilla REPL like
;; clojure.deps[https://clojure.org/guides/getting_started] instead.
`

I wonder if nREPL is really to blame. They did fix an issue with the context class loader in 0.6.0. I can't test earlier versions of nREPL since manually setting an older version of nREPL in the project.clj file crashes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Candidate
Development

No branches or pull requests

4 participants