Welcome! Please see the About page for a little more info on how this works.

0 votes
in Compiler by
edited by

We are rendering svg strings to images uses org.apache.batik. In order to set the image quality we get, we proxy org.apache.batik.transcoder.image.PNGTranscoder so that the call to createRenderer can have some image rendering settings applied to the render that returns. The method createRenderer is a protected method on the abstract class org.apache.batik.transcoder.image.ImageTranscoder which the PNGTranscoder extends.

The full code is below

(set! *warn-on-reflection* true)
(defn- high-quality-png-transcoder ^PNGTranscoder []
  (proxy [PNGTranscoder] []
    (createRenderer []
      (let [add-hint                (fn [^RenderingHints hints k v] (.add hints (RenderingHints. k v)))
            ^ImageRenderer renderer (proxy-super createRenderer) ;; line 104
            hints                   (RenderingHints.
        (doto hints
          (add-hint RenderingHints/KEY_INTERPOLATION       RenderingHints/VALUE_INTERPOLATION_BICUBIC)
          (add-hint RenderingHints/KEY_ANTIALIASING        RenderingHints/VALUE_ANTIALIAS_ON)
          (add-hint RenderingHints/KEY_COLOR_RENDERING     RenderingHints/VALUE_COLOR_RENDER_QUALITY)
          (add-hint RenderingHints/KEY_DITHERING           RenderingHints/VALUE_DITHER_DISABLE)
          (add-hint RenderingHints/KEY_RENDERING           RenderingHints/VALUE_RENDER_QUALITY)
          (add-hint RenderingHints/KEY_STROKE_CONTROL      RenderingHints/VALUE_STROKE_PURE)
          (add-hint RenderingHints/KEY_FRACTIONALMETRICS   RenderingHints/VALUE_FRACTIONALMETRICS_ON)
          (add-hint RenderingHints/KEY_TEXT_ANTIALIASING   RenderingHints/VALUE_TEXT_ANTIALIAS_OFF))
        (.setRenderingHints renderer hints)

This generates the warning

Reflection warning, metabase/pulse/render/poc.clj:104:37 - reference to field createRenderer can't be resolved.

Clojure docs give the "typehint this" workaround. Adding a ^PNGTranscoder this this right above the proxy-super doesn't fix anything but just indicates that the code has more information:

Reflection warning, metabase/pulse/render/poc.clj:105:37 - reference to field createRenderer on org.apache.batik.transcoder.image.PNGTranscoder can't be resolved.

(line 104 becomes line 105 with the new type-hinted this binding)

1 Answer

+1 vote

The createRenderer method is protected on PNGTranscoder, but public on the generated proxy class, so it is impossible to call non-reflectively, unless this is type hinted with the concrete type of the proxy(which is a huge hack, but maybe technically possible), but calling it reflectively, which uses the runtime type of the proxy and so has access to the method, works fine.