private static void traverseRecursively(final File fromFile, @NotNull FileFilter dirFilter, @NotNull FileFilter fileFilter, @NotNull FSOperations.FileConsumer processor) throws IOException {
    Files.walkFileTree(fromFile.toPath(), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, new SimpleFileVisitor<>() {
      @Override
      public FileVisitResult visitFileFailed(Path file, IOException e) throws IOException {
        if (e instanceof NoSuchFileException) {
          return FileVisitResult.TERMINATE;
        }
        if (e instanceof FileSystemLoopException) {
          LOG.info(e);
          // in some cases (e.g. Google Drive File Stream) loop detection for directories works incorrectly
          // fallback: try to traverse in the old IO-way
          traverseRecursivelyIO(file.toFile(), dirFilter, fileFilter, processor);
          return FileVisitResult.SKIP_SUBTREE;
        }
        return super.visitFileFailed(file, e);
      }

      @Override
      public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
        return dirFilter.accept(dir.toFile())? FileVisitResult.CONTINUE : FileVisitResult.SKIP_SUBTREE;
      }

      @Override
      public FileVisitResult visitFile(Path f, BasicFileAttributes attrs) throws IOException {
        final File _file = f.toFile();
        if (fileFilter.accept(_file)) {
          processor.consume(_file, attrs);
        }
        return FileVisitResult.CONTINUE;
      }
    });
  }
private static void traverseRecursively(final File fromFile, @NotNull FileFilter dirFilter, @NotNull FileFilter fileFilter, @NotNull FSOperations.FileConsumer processor)