Clojure中gen-class生成类引发ClassNotFoundException的解决方法
解决Clojure gen-class生成类的ClassNotFoundException问题
问题场景
使用gen-class在myorg.helpers.fs-input-stream命名空间生成myorg.helpers.FsInputStream类,在myorg.plugin.orc-output中导入该类,运行测试时抛出:
Syntax error (ClassNotFoundException) compiling at (myorg/plugin/orc_output.clj:1:1).
myorg.helpers.fs-input-stream.FsInputStream
相关代码如下:
生成类的命名空间代码:
(ns myorg.helpers.fs-input-stream) (gen-class :name "myorg.helpers.FsInputStream" :extends java.io.ByteArrayInputStream :implements [org.apache.hadoop.fs.Seekable org.apache.hadoop.fs.PositionedReadable] :main false :exposes {buf {:get getBuf} pos {:get getPos} mark {:get getMark}} :init-impl-ns false)
使用类的命名空间代码:
(ns myorg.plugin.orc-output (:import (myorg.helpers FsInputStream) (org.apache.hadoop.fs FileSystem FSDataInputStream))) (set! *warn-on-reflection* true) (defn input-stream-filesystem [buffered-bytes] (proxy [FileSystem] [] (open [_] (FSDataInputStream. (FsInputStream. buffered-bytes)))))
测试代码:
(ns myorg.plugin.orc-output-test (:require [clojure.test :refer :all]) (:require [myorg.plugin.orc-output :refer :all])) (deftest orc-create (is (= 1 1)))
核心原因
gen-class生成的Java类需要**提前编译(AOT)**才能被其他命名空间导入使用。测试运行时,生成类的命名空间未被提前加载编译,导致JVM找不到对应的类文件。
解决步骤
1. 配置AOT编译
在项目构建配置中,将生成类的命名空间标记为需要AOT编译:
- 若使用Leiningen(project.clj):
添加:aot配置项:(defproject gen-class-error-demo "0.1.0-SNAPSHOT" :dependencies [[org.clojure/clojure "1.11.1"] [org.apache.hadoop/hadoop-common "3.3.4"]] :aot [myorg.helpers.fs-input-stream]) ; 指定要AOT编译的命名空间 - 若使用tools.deps(deps.edn):
添加:aot配置并定义编译任务:
运行命令手动编译:{:deps {org.clojure/clojure {:mvn/version "1.11.1"} org.apache.hadoop/hadoop-common {:mvn/version "3.3.4"}} :aliases {:compile {:exec-fn clojure.core/compile :exec-args {:namespace myorg.helpers.fs-input-stream}}}}clj -X:compile
2. 调整测试的依赖加载顺序
在测试命名空间中,先require生成类的命名空间,确保它被加载并触发类生成:
修改测试代码:
(ns myorg.plugin.orc-output-test (:require [clojure.test :refer :all] [myorg.helpers.fs-input-stream] ; 优先加载生成类的命名空间 [myorg.plugin.orc-output :refer :all])) (deftest orc-create (is (= 1 1)))
3. IDE运行配置调整
在IntelliJ IDEA中:
- 打开测试的运行配置,勾选**"Compile before launch"**选项,确保测试前完成所有必要编译。
- 或者,将
myorg.helpers.fs-input-stream命名空间添加到编译前置列表中。
验证
完成上述配置后,重新运行测试,ClassNotFoundException即可解决。
内容的提问来源于stack exchange,提问作者user51
相关产品推荐
相关产品推荐

