jooby-project / jooby

The modular web framework for Java and Kotlin
https://jooby.io
Apache License 2.0
1.7k stars 199 forks source link

jooby-run: Hot reloading not working when .class file is changed by external process #3505

Closed blazmrak closed 3 weeks ago

blazmrak commented 3 weeks ago

I'm using neovim + LazyVim and jooby maven plugin restarts the server, but does not pick up the code changes. The docs say that the plugin is looking for .classpath file and leaves the compilation to eclipse. I'm using jdtls, which should compile the changes I think, but changes are not visible (even after running jdtls.compile manually and getting "compilation completed" message). Do I have incorrect configuration or am missing something obvious?

jknack commented 3 weeks ago

try without .classpath file and see if works.

blazmrak commented 3 weeks ago

When I delete the .classpath it works. But when running jdtls (Eclipse language server) it doesn't, as it autocreates .classpath. Would it be possible to add an option to override this behavior?

jknack commented 3 weeks ago

where jdtls ouput class files? Can you share an example project?

blazmrak commented 3 weeks ago

At the root, I'm guessing the same as Eclipse, since it's the same language server that Eclipse uses. Sure, I'll have minimal repro up in a sec.

Edit: disregard what I said, I misread where does it put .classpath file... It generates target folder with classes, generated-sources, generated-test-sources and some other folder, but from what I understand, classes folder is key here, correct?

blazmrak commented 3 weeks ago

Here it is https://github.com/blazmrak/joobytest

blazmrak commented 3 weeks ago

I added jdtls-build branch, where I rmrf'd target and bin and just opened the editor, no leftover maven build.

jknack commented 3 weeks ago

So, is eclipse/jdtls compiling source code? It should works as long as compiled code is save on target/classes. Try to run jooby run in debug mode and check if you see something on logs: mvn jooby:run -X

blazmrak commented 3 weeks ago

Yes, it should compile, it says it compiles (I even ran it manually), I ran jooby in debug, it just prints what has changed, but the change is not visible. Here is the log

[DEBUG] Jooby is now state: RUNNING
[DEBUG] ENTRY_MODIFY [...joobytest/target/classes/app/App.class]
[DEBUG] -> MODIFY [...joobytest/target/classes/app/App.class] (isDirectory: false)
[DEBUG] Restarting application on file change: ...joobytest/target/classes/app/App.class
[DEBUG] ENTRY_MODIFY [...joobytest/target/classes/application.conf]
[DEBUG] ENTRY_MODIFY [...joobytest/target/classes/logback.xml]
[DEBUG] Closing server. state: RESTART
[2024-08-19 22:29:14,403]-[pool-2-thread-1] INFO  app.App - Stopped App
[2024-08-19 22:29:14,417]-[pool-2-thread-1] INFO  app.App - App (dev) started
[2024-08-19 22:29:14,417]-[pool-2-thread-1] INFO  app.App - routes: 

  GET /

listening on:
  http://localhost:8080/

It seems that the change happens, jooby even picks it up, but when the server is restarted, the change is not visible...

Edit: Oh, and also, I just tried now, running mvn exec:java picks up the changes, so jdtls does recompile the changes.

Edit 2: I get an exception at start up:

[DEBUG] Assuming ExtendedWatchEventModifier.FILE_TREE is not supported
java.lang.UnsupportedOperationException: Modifier not supported
    at sun.nio.fs.LinuxWatchService$Poller.implRegister (LinuxWatchService.java:235)
    at sun.nio.fs.AbstractPoller.processRequests (AbstractPoller.java:266)
    at sun.nio.fs.LinuxWatchService$Poller.run (LinuxWatchService.java:357)
    at java.lang.Thread.run (Thread.java:1583)

Would this be related?

blazmrak commented 3 weeks ago

I'm losing it, it's way too late for me, but I think you are never unloading the module for Eclipse projects. I might be wrong on this, as I didn't try it out, but just looked at the code on github. I can fork it and try to change it to confirm, and maybe make a PR if I find anything...

https://github.com/jooby-project/jooby/blob/d2f41ddf5a0ee07d777969b3c33550202617dfd0/modules/jooby-run/src/main/java/io/jooby/run/JoobyRun.java#L438

If this is the case, I think the way plugin is initialized has to be changed, to first scan for .classpath and then use that in onFileChanged lambda or just make it an option, that defaults to false when .classpath is detected. So instead of having empty compileExtensions list, you would still have the list, but would also have the information if the plugin needs to do compilation as well. I hope this made some sense :sweat_smile:

Basically remove this https://github.com/jooby-project/jooby/blob/d2f41ddf5a0ee07d777969b3c33550202617dfd0/modules/jooby-maven-plugin/src/main/java/io/jooby/maven/RunMojo.java#L221 and update this https://github.com/jooby-project/jooby/blob/d2f41ddf5a0ee07d777969b3c33550202617dfd0/modules/jooby-maven-plugin/src/main/java/io/jooby/maven/RunMojo.java#L91

jknack commented 3 weeks ago

Yes! You're right. We never fired the restart wonder when started to failed 🤔