给定一个引用类的Clojure函数,如果该类有一个在运行时失败的静态字段初始化器,函数将无法编译,因为编译器(无谓地)运行了初始化器,即使相应的字段没有被访问。值得注意的是,当将类存储在var中并通过它进行引用时(请参阅下面的解决方案)不会发生这种情况。编译器能否在这里支持直接引用?
复现问题
(以下代码也可见于https://github.com/bevuta/clojure-fn-compilation-issue-repro)
deps.edn
:
{:deps {io.netty/netty-codec {:mvn/version "4.1.108.Final"}}}
src/repro/fail.clj
:
(ns repro.fail
(:import io.netty.handler.codec.compression.BrotliOptions))
(defn bar []
BrotliOptions)
(defn -main [& args]
(prn (bar)))
在这里,bar
函数引用了io.netty.handler.codec.compression.BrotliOptions
类。该类有一个包私有的静态字段DEFAULT
,其初始化器依赖于由可选第三方库提供的类。然而,即使bar
从未引用该字段,初始化器也会运行并因为该库不存在而失败。
运行方式如下:
$ clojure -M -m repro.fail
Execution error (ClassNotFoundException) at jdk.internal.loader.BuiltinClassLoader/loadClass (BuiltinClassLoader.java:641).
com.aayushatharva.brotli4j.encoder.Encoder$Parameters
解决方案
可以通过将类值放入独立的def
并将该值用于函数来解决这个问题
src/repro/ok.clj
:
(ns repro.ok
(:import io.netty.handler.codec.compression.BrotliOptions))
(def foo BrotliOptions)
(defn bar []
foo)
(defn -main [& args]
(prn (bar)))
运行方式如下:
$ clojure -M -m repro.ok
io.netty.handler.codec.compression.BrotliOptions
相关性
在https://github.com/clj-commons/aleph/issues/703)的上下文中遇到了该问题。