   [^clojure.lang.IPersistentSet s bound]
   (if (seq s)
     (condp = bound        
-      :service (HashPrintServiceAttributeSet. (into-array PrintServiceAttribute s))
-      :job (HashPrintJobAttributeSet. (into-array PrintJobAttribute s))
-      :doc (HashDocAttributeSet. (into-array DocAttribute s))
-      :request (HashPrintRequestAttributeSet. (into-array PrintRequestAttribute s))
+      :service (HashPrintServiceAttributeSet.
+                #^"[Ljavax.print.attribute.PrintServiceAttribute;"
+                (into-array PrintServiceAttribute s))
+      :job (HashPrintJobAttributeSet.
+            #^"[Ljavax.print.attribute.PrintJobAttribute;"
+            (into-array PrintJobAttribute s))
+      :doc (HashDocAttributeSet.
+            #^"[Ljavax.print.attribute.DocAttribute;"
+            (into-array DocAttribute s))
+      :request (HashPrintRequestAttributeSet.
+                #^"[Ljavax.print.attribute.PrintRequestAttribute;"
+                (into-array PrintRequestAttribute s))
       nil)))
 
 (defn- valid-attrs?


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Job ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;  A JobSpec might look something like this:
(comment {:doc {:source "/path/to/doc.pdf"
                :flavor (:autosense flavors/input-streams)
                :attrs #{Chromaticity/MONOCHROME
                         PrintQuality/HIGH
                         OrientationRequested/PORTRAIT}}
          :printer (printer "HP_Color_LaserJet_CP3505")
          :attrs #{(Copies. 5) MediaTray/MAIN}
          :listener (listeners/basic-listener)})

;; Or

(comment {:docs [{:source "/path/to/doc1.pdf"
                  :flavor (:autosense flavors/input-streams)
                  :attrs #{Chromaticity/MONOCHROME}}
                 {:source "http://somesite.com/doc2.pdf"
                  :flavor (:autosense flavors/urls)
                  :attrs #{Chromaticity/COLOR}}]
          :printer (printer :default)
          :attrs #{MediaTray/MAIN}
          :listener (listeners/basic-listener)})

(defprotocol IJobSpec
  (submit [this]) 
  (add-listener [this listener-fn]))

;; TODO: Handle exception scenarios
(defrecord JobSpec [doc printer job attrs]
  IJobSpec
  (submit [this]
    (if-let [{listener-fn :listener-fn} this]
      (add-listener this listener-fn))
    (let [{{doc-obj :obj} :doc} this
          {:keys [^DocPrintJob job attrs]} this
          attr-set (make-set attrs :request)]
      (.. job (print doc-obj attr-set))))
  (add-listener [this listener-fn]
    (let [{:keys [^DocPrintJob job listener-fn]} this
          listener (listener-fn)]
      (doto job (.addPrintJobListener listener)))))

(defrecord MultiJobSpec [docs printer jobs attrs]
  IJobSpec
  (submit [this]
    (if-let [{listener-fn :listener-fn} this]
      (add-listener this listener-fn))
    (let [{:keys [docs jobs]} this
          doc-objs (map :obj docs)]
      (doall
       (map (fn [^DocPrintJob j d]
              (.. j (print @d (make-set attrs :request)))) jobs doc-objs))))
  (add-listener [this listener-fn]
    (let [{:keys [jobs listener-fn]} this]
      (doseq [^DocPrintJob j jobs]
        (.. j (addPrintJobListener (listener-fn)))))))

;; TODO: SEE http://oobaloo.co.uk/clojure-from-callbacks-to-sequences!!!
(defmulti make-job
  "Dispatch on which key is present in the spec map."
  (fn [spec] (apply (some-fn #{:doc} #{:docs}) (keys spec))))

(defmethod make-job :doc [spec]

        (-> spec add-doc add-job map->JobSpec)))))

(defmethod make-job :docs [spec]
  (let [{docs :docs} spec]
    (for [doc docs]
      (-> spec (dissoc :docs) (assoc :doc doc) make-job))))

;; Old method of encapsulating a 'MultiJobSpec', most
;; values in a JobSpec will be Singleton/Enum instances
;; anyways, so structural sharing may not be necessary,
;; though I'll throw this in here anyways:
;;
;; TODO: Analyze memory consumption in JVisualVM for:
;; 1. maps vs records being used for job specs in general
;; 2. Using MultiJobSpec vs just using 
;;
;; (defmethod make-job :docs [spec]
;;   (let [{:keys [^PrintService printer
;;                 ^PrintJobListener listener
;;                 docs attrs]} spec]
;;     (if (and (every? (fn [d] (valid-attrs? d :doc)) (map :attrs docs))
;;              (valid-attrs? attrs :job))
;;       (letfn [(add-doc [doc-map]
;;                 (assoc-in doc-map [:obj] (delay (make-doc doc-map))))
;;               (add-docs [spec]
;;                 (update-in spec [:docs] (fn [doc-list] (map add-doc  doc-list))))
;;               (add-jobs [spec]
;;                 (assoc-in spec [:jobs] (for [doc docs] (.. printer createPrintJob))))]
;;         (-> spec add-docs add-jobs map->MultiJobSpec)))))

(defn -main
  "Main method, expects each value in args to be the string
   representation of a clojure map to be read by the reader."
  {:since "0.0.1"}
  [& args]
  (if (seq args)
    (doseq [v args]
      (let [spec (read-string v)]
        (-> (make-job spec) submit!)))))
