codeconsole commented on code in PR #16089:
URL: https://github.com/apache/grails-core/pull/16089#discussion_r3714814663
##########
grails-bootstrap/src/main/groovy/org/grails/io/watch/DirectoryWatcher.java:
##########
@@ -45,32 +45,57 @@ public class DirectoryWatcher extends Thread {
*/
public DirectoryWatcher() {
setDaemon(true);
- AbstractDirectoryWatcher directoryWatcherDelegate;
+ this.directoryWatcherDelegate = createDelegate();
+ }
+
+ /**
+ * Selects the best available watcher implementation.
+ *
+ * <p>On macOS the native FSEvents based watcher is preferred, but it
requires the optional
+ * {@code io.methvin:directory-watcher} dependency. When that isn't
available the JDK
+ * {@link java.nio.file.WatchService} is used instead. Polling is only a
last resort.</p>
+ *
+ * @return the watcher to delegate to
+ */
+ private static AbstractDirectoryWatcher createDelegate() {
+ if (System.getProperty("os.name").equals("Mac OS X")) {
+ AbstractDirectoryWatcher macOsWatcher = createMacOsWatcher();
+ if (macOsWatcher != null) {
+ return macOsWatcher;
+ }
+ }
try {
- if (System.getProperty("os.name").equals("Mac OS X")) {
- Boolean jnaAvailable = false;
- try {
- Class.forName("com.sun.jna.Pointer");
- jnaAvailable = true;
- } catch (ClassNotFoundException e) {
- if (LOG.isWarnEnabled()) {
- LOG.warn("Error Initializing Native OS X File Event
Watcher. Add JNA to classpath for Faster File Watching performance.");
- }
-
- }
- if (jnaAvailable) {
- directoryWatcherDelegate = (AbstractDirectoryWatcher)
Class.forName("org.grails.io.watch.MacOsWatchServiceDirectoryWatcher").getDeclaredConstructor().newInstance();
- } else {
- directoryWatcherDelegate = (AbstractDirectoryWatcher)
Class.forName("org.grails.io.watch.WatchServiceDirectoryWatcher").getDeclaredConstructor().newInstance();
- }
- } else {
- directoryWatcherDelegate = (AbstractDirectoryWatcher)
Class.forName("org.grails.io.watch.WatchServiceDirectoryWatcher").getDeclaredConstructor().newInstance();
+ return new WatchServiceDirectoryWatcher();
+ } catch (Throwable e) {
+ LOG.warn("Could not create a WatchService based directory watcher.
Falling back to PollingDirectoryWatcher.", e);
+ return new PollingDirectoryWatcher();
+ }
+ }
+
+ /**
+ * @return the native macOS watcher, or {@code null} if it is unavailable
+ */
+ private static AbstractDirectoryWatcher createMacOsWatcher() {
+ try {
+ // MacOsWatchServiceDirectoryWatcher delegates to io.methvin's
MacOSXListeningWatchService,
+ // an optional dependency of this module. Probe for that class
rather than for JNA: JNA is
+ // frequently present transitively (Testcontainers, docker-java,
...) without the watcher
+ // library, and using it as the signal sends those applications
down a load that can't succeed.
+ // A LinkageError means the class is present but its own
dependencies (JNA) are not, which is
+ // equally unusable, so treat both as simply unavailable.
+
Class.forName("io.methvin.watchservice.MacOSXListeningWatchService");
+ } catch (ClassNotFoundException | LinkageError e) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Native macOS file event watching is unavailable.
Add 'io.methvin:directory-watcher' to the classpath for faster file watching.",
e);
Review Comment:
Agreed — changed to warn in ab2b2afb3e.
Worth surfacing: the JDK supplies no native `WatchService` on macOS.
`FileSystems.getDefault().newWatchService()` returns
`sun.nio.fs.PollingWatchService`, and `WatchServiceDirectoryWatcher` registers
without a sensitivity modifier, so the fallback polls at the default 10s. That
is a real reload latency cost with a one dependency fix, so the message now
states the consequence as well as naming the dependency — and yes, adding the
library silences it.
The `ClassNotFoundException` stays at `LOG.debug` so the warn line remains a
single actionable sentence rather than a stack trace, which is what made the
message on `8.0.x` noisy.
`DirectoryWatcherSpec` now also covers that the advice is emitted on macOS
without the library, and that it stays off platforms it cannot help.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]