sclass RecursiWatcherService extends AutoCloseable { File rootFolder; WatchService watcher; ExecutorService executor; public void init() throws IOException { watcher = FileSystems.getDefault().newWatchService(); executor = Executors.newSingleThreadExecutor(); startRecursiveWatcher(); } void cleanMeUp() { close(); } public void close() { pcall { watcher.close(); } executor.shutdown(); } private void startRecursiveWatcher() throws IOException { LOG.info("Starting Recursive Watcher"); final Map keys = new HashMap<>(); Consumer register = p -> { if (!p.toFile().exists() || !p.toFile().isDirectory()) { throw new RuntimeException("folder " + p + " does not exist or is not a directory"); } try { Files.walkFileTree(p, new SimpleFileVisitor() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { LOG.info("registering " + dir + " in watcher service"); WatchKey watchKey = dir.register(watcher, new WatchEvent.Kind[]{ENTRY_CREATE}, SensitivityWatchEventModifier.HIGH); keys.put(watchKey, dir); return FileVisitResult.CONTINUE; } }); } catch (IOException e) { throw new RuntimeException("Error registering path " + p); } }; register.accept(rootFolder.toPath()); executor.submit(() -> { while (true) { final WatchKey key; try { key = watcher.take(); // wait for a key to be available } catch (InterruptedException ex) { return; } final Path dir = keys.get(key); if (dir == null) { System.err.println("WatchKey " + key + " not recognized!"); continue; } key.pollEvents().stream() .filter(e -> (e.kind() != OVERFLOW)) .map(e -> ((WatchEvent) e).context()) .forEach(p -> { final Path absPath = dir.resolve(p); if (absPath.toFile().isDirectory()) { register.accept(absPath); } else { final File f = absPath.toFile(); LOG.info("Detected new file " + f.getAbsolutePath()); } }); boolean valid = key.reset(); // IMPORTANT: The key must be reset after processed if (!valid) { break; } } }); } }