Question

I'm struggling to get the correct type hints to avoid a warn on reflection while writing text-file-output from a database query.

I've tried to put ^String type hints before each function being called, as ultimately the output is going to hit a text file on disk.

The reflection warning occurs on the :row-fn line towards the end of the function. I have the comment Reflection warning, dbdump/dbdump.clj:157:44 - call to write can't be resolved. on the same line.

How can i get rid of this warning? I'm thinking there is a performance cost when working with large datasets.

(defn run-job [job-time-string db-spec config]
  (let [; {{{
        source-sql          (str "select * from " (:source-base-name config)(:table-name config))
        max-rows            (:max-rows            config)
        fetch-size          (:fetch-size          config)
        working-dir         (:working-dir         config)
        output-name           (str working-dir "/" job-time-string ".pipe" )
        field-delim         (:field-delim         config)
        row-delim           (:row-delim           config)
        log-report-interval (:log-report-interval config)
        row-count           (atom 0)  ; For state on rows
        db-connection       (doto (j/get-connection db-spec))
        statement           (j/prepare-statement db-connection source-sql :fetch-size fetch-size :concurrency :read-only :max-rows max-rows)
        start-in-millis     (System/currentTimeMillis)
        replace-newline (^String fn [s]
                          (if
                              (string? s)
                            (clojure.string/replace  s #"\n" " ")
                            s)) ; I'd prefer not to do this; Right now we can't load \n fields.
        row-fn          (^String fn [v]
                          (swap! row-count inc)
                          (when
                              (zero?
                               (mod @row-count log-report-interval))
                            (write-logs @row-count start-in-millis 3 (:table-name config) ))
                          (str (join field-delim (doall (map #(replace-newline %) v))) row-delim ))
        ]; }}}
    (with-open [^java.io.Writer wrtr (io/writer output-name )]
        (info "Fetching jdbc query..." )
        (info source-sql)
        (try
          (j/query db-connection [statement]
                   :as-arrays?    true
                   :result-set-fn vec
; Reflection warning, dbdump/dbdump.clj:157:44 - call to write can not be resolved.
                   :row-fn        ^String #(.write wrtr (row-fn %)))
          (catch Exception e
            (error (str "Error while fetching JDBC data." (.getMessage e)))
            (System/exit 9))))
    (write-logs @row-count start-in-millis 0 (str (:source-base-name config)  (:table-name config) " Completed - "))))
Was it helpful?

Solution

The reflection warning tells you that you need to clarify which write method is to be called in #(.write wrtr (row-fn %)). So you'll need to type-hint wrtr and (row-fn %):

#(.write ^java.io.Writer wrtr ^String (row-fn %))

Incidentally, adding type hints to fn forms or function literals has no effect. (Well, adding primitive hints does make the resulting function implement the relevant clojure.lang.IFn$[OLD]+ interface, but those hints would need to be attached to the parameter vector and/or the individual symbols naming the parameters.)

(In contrast, adding type hints to function names in defn forms does have the effect of placing :tag metadata on the resulting Vars; this will be used by the compiler to disambiguate Java method calls.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top