   (take! [this])
   (stop! [this]))
 
-(defn- take-events [watcher normalize]
-  (when-let [watch-key (try
-                         (.take watcher)
-                         (catch InterruptedException _ _ nil))]
-    (let [events (for [event (.pollEvents watch-key)
+(defn- take-events [^WatchService watcher normalize]
+  (when-let [^WatchKey watch-key (try
+                                   (.take watcher)
+                                   (catch InterruptedException _ _ nil))]
+    (let [events (for [^WatchEvent event (.pollEvents watch-key)
                        :let [kind (.kind event)
                              context (.context event)]]
                    (normalize watch-key kind context))]
       (.reset watch-key)
       events)))
 
-(defn- recursive-register! [this path events f]
+(defn- recursive-register! [this ^Path path events f]
   (let [events (into-array (map standard-watch-event-kinds events))]
-    (.reset (f events)))
-  (doseq [dir (-> path .toFile .listFiles)]
+    (.reset ^WatchKey (f events)))
+  (doseq [^File dir (-> path .toFile .listFiles)]
     (when (.isDirectory dir)
       (register! this (.toPath dir) events))))
 
 (def java-watcher-impl
-  {:register! (fn [this path events]
+  {:register! (fn [this ^Path path events]
                 (recursive-register! this path events
                   #(.register path this %)))
    :take! (fn [this]
             (try (take-events
                    this
-                   (fn [watch-key kind context]
-                     {:file (-> (.watchable watch-key)
-                              (.resolve context) .toFile .getCanonicalFile)
+                   (fn [^WatchKey watch-key kind ^Path context]
+                     {:file (.. ^Path (.watchable watch-key)                                
+                                (resolve context)
+                                toFile
+                                getCanonicalFile)
                       :kind ((map-invert standard-watch-event-kinds) kind)}))
                  (catch java.nio.file.ClosedWatchServiceException _ _ nil)))
-   :stop! (fn [this]
-            (doto this .close))})
+   :stop! (fn [^WatchService this]
+            (.close this))})
 
 (def polling-watcher-impl
   (assoc java-watcher-impl
-    :register! (fn [this path events]
+    :register! (fn [^hawk.PollingWatchService this path events]
                  (recursive-register! this path events
                    #(.register this path % (into-array WatchEvent$Modifier []))))))
 
 (def barbary-watcher-impl
-  {:register! (fn [this path events]
+  {:register! (fn [this ^Path path events]
                 (let [file (-> path .toFile WatchableFile.)
                       events (into-array (map barbary-watch-event-kinds events))]
                   (.register file this events)))

                     {:file (-> context str io/file .getCanonicalFile)
                      :kind ((map-invert barbary-watch-event-kinds) kind)}))
                 (catch com.barbarysoftware.watchservice.ClosedWatchServiceException _ _ nil)))
   :stop! (fn [this]
            (doto this .close))})

(extend java.nio.file.WatchService Watcher java-watcher-impl)
(extend hawk.PollingWatchService Watcher polling-watcher-impl)

  (:require [clojure.java.io :as io]
            [clojure.set :refer [map-invert]])
  (:import (hawk SensitivityWatchEventModifier)
           java.io.File
           (java.nio.file FileSystems Path Paths StandardWatchEventKinds WatchEvent WatchEvent$Modifier WatchKey WatchService)
           (com.barbarysoftware.watchservice StandardWatchEventKind WatchableFile)))

(def barbary-watch-event-kinds
