我正在尝试将 clojure 库集成与基座一起使用,但我在编译时遇到了一个奇怪的错误
java.lang.Thread.run Thread.java: 748
java.util.concurrent.ThreadPoolExecutor$Worker.run ThreadPoolExecutor.java: 624
java.util.concurrent.ThreadPoolExecutor.runWorker ThreadPoolExecutor.java: 1149
java.util.concurrent.FutureTask.run FutureTask.java: 266
...
clojure.core/binding-conveyor-fn/fn core.clj: 2030
boot.core/boot/fn core.clj: 1031
boot.core/run-tasks core.clj: 1022
boot.task.built-in/eval2946/fn/fn/fn built_in.clj: 804
boot.pod/eval-in* pod.clj: 471
...
org.projectodd.shimdandy.impl.ClojureRuntimeShimImpl.invoke ClojureRuntimeShimImpl.java: 97
org.projectodd.shimdandy.impl.ClojureRuntimeShimImpl.invoke ClojureRuntimeShimImpl.java: 104
...
boot.pod/eval-in* pod.clj: 468
clojure.core/eval core.clj: 3214
...
pod$eval158.invoke NO_SOURCE_FILE
pod$eval158.invokeStatic NO_SOURCE_FILE
clojure.core/compile core.clj: 6136
clojure.core/compile/fn core.clj: 6136
clojure.core/load-one core.clj: 5908
...
clojure.core/load core.clj: 6109
clojure.core/load core.clj: 6125
clojure.core/load/fn core.clj: 6126
...
integrant.core/init core.cljc: 415
integrant.core/init core.cljc: 418
integrant.core/build core.cljc: 321
clojure.core/reduce core.clj: 6828
clojure.core.protocols/fn/G protocols.clj: 13
clojure.core.protocols/fn protocols.clj: 75
clojure.core.protocols/seq-reduce protocols.clj: 31
clojure.core.protocols/fn/G protocols.clj: 19
clojure.core.protocols/fn protocols.clj: 168
clojure.core/partial/fn core.clj: 2632
integrant.core/build-key core.cljc: 300
integrant.core/try-build-action core.cljc: 292
...
redblackrose.core/fn core.clj: 145
redblackrose.core/start core.clj: 136
io.pedestal.http/create-server http.clj: 374
io.pedestal.http/create-server http.clj: 377
io.pedestal.http/server http.clj: 348
...
io.pedestal.http.jetty/server jetty.clj: 223
io.pedestal.http.jetty/create-server jetty.clj: 185
java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to java.lang.Number
clojure.lang.ExceptionInfo: Error on key :adapter/jetty when building system
data: {#object[clojure.lang.Keyword 0x2f85ee14 ":reason"] #object[clojure.lang.Keyword 0x78b8af86 ":integrant.core/build-threw-exception"], #object[clojure.lang.Keyword 0x348f1abf ":system"] {}, #object[clojure.lang.Keyword 0x748df981 ":function"] #object[clojure.lang.MultiFn 0x75c8d8e7 "clojure.lang.MultiFn@75c8d8e7"], #object[clojure.lang.Keyword 0x3681c4b9 ":key"] #object[clojure.lang.Keyword 0xa9c9cbe ":adapter/jetty"], #object[clojure.lang.Keyword 0x64607768 ":value"] {#object[clojure.lang.Keyword 0x1c29dad6 ":port"] 3000}}
clojure.lang.Compiler$CompilerException: Syntax error macroexpanding at (core.clj:148:3).
data: {#object[clojure.lang.Keyword 0x7112fa5 ":clojure.error/phase"] #object[clojure.lang.Keyword 0x342dc040 ":execution"], #object[clojure.lang.Keyword 0x3a8ead9 ":clojure.error/line"] 148, #object[clojure.lang.Keyword 0x281ca256 ":clojure.error/column"] 3, #object[clojure.lang.Keyword 0x26feccf7 ":clojure.error/source"] "core.clj"}
clojure.lang.ExceptionInfo: Syntax error macroexpanding at (core.clj:148:3).
line: 80
redblackrose.core 文件是
(ns redblackrose.core
(:gen-class)
(:require [io.pedestal.http :as server]
[clojure.core.async :as a]
[clojure.java.io :as io]
[integrant.core :as ig]
[io.pedestal.http :as server]
[reitit.coercion.spec]
[reitit.dev.pretty :as pretty]
[reitit.http :as http]
[reitit.http.coercion :as coercion]
[reitit.http.interceptors.dev :as dev]
[reitit.http.interceptors.exception :as exception]
[reitit.http.interceptors.multipart :as multipart]
[reitit.http.interceptors.muuntaja :as muuntaja]
[reitit.http.interceptors.parameters :as parameters]
[reitit.http.spec :as spec]
[reitit.pedestal :as pedestal]
[reitit.ring :as ring]
[reitit.swagger :as swagger]
[reitit.swagger-ui :as swagger-ui]
[spec-tools.spell :as spell]
[muuntaja.core :as m]))
(defn interceptor [number]
{:enter (fn [ctx] (a/go (update-in ctx [:request :number] (fnil + 0) number)))})
(def router
(pedestal/routing-interceptor
(http/router
[["/swagger.json"
{:get {:no-doc true
:swagger {:info {:title "my-api"
:description "with pedestal & reitit-http"}}
:handler (swagger/create-swagger-handler)}}]
["/interceptors"
{:swagger {:tags ["interceptors"]}
:interceptors [(interceptor 1)]}
["/number"
{:interceptors [(interceptor 10)]
:get {:interceptors [(interceptor 100)]
:handler (fn [req]
{:status 200
:body (select-keys req [:number])})}}]]
["/files"
{:swagger {:tags ["files"]}}
["/upload"
{:post {:summary "upload a file"
:parameters {:multipart {:file multipart/temp-file-part}}
:responses {200 {:body {:name string?, :size int?}}}
:handler (fn [{{{:keys [file]} :multipart} :parameters}]
{:status 200
:body {:name (:filename file)
:size (:size file)}})}}]
["/download"
{:get {:summary "downloads a file"
:swagger {:produces ["image/png"]}
:handler (fn [_]
{:status 200
:headers {"Content-Type" "image/png"}
:body (io/input-stream
(io/resource "reitit.png"))})}}]]
["/math"
{:swagger {:tags ["math"]}}
["/plus"
{:get {:summary "plus with spec query parameters"
:parameters {:query {:x int?, :y int?}}
:responses {200 {:body {:total int?}}}
:handler (fn [{{{:keys [x y]} :query} :parameters}]
{:status 200
:body {:total (+ x y)}})}
:post {:summary "plus with spec body parameters"
:parameters {:body {:x int?, :y int?}}
:responses {200 {:body {:total int?}}}
:handler (fn [{{{:keys [x y]} :body} :parameters}]
{:status 200
:body {:total (+ x y)}})}}]]]
{:reitit.interceptor/transform dev/print-context-diffs ;; pretty context diffs
:validate spec/validate ;; enable spec validation for route data
:reitit.spec/wrap spell/closed ;; strict top-level validation
:exception pretty/exception
:data {:coercion reitit.coercion.spec/coercion
:muuntaja m/instance
:interceptors [;; swagger feature
swagger/swagger-feature
;; query-params & form-params
(parameters/parameters-interceptor)
;; content-negotiation
(muuntaja/format-negotiate-interceptor)
;; encoding response body
(muuntaja/format-response-interceptor)
;; exception handling
(exception/exception-interceptor)
;; decoding request body
(muuntaja/format-request-interceptor)
;; coercing response bodys
(coercion/coerce-response-interceptor)
;; coercing request parameters
(coercion/coerce-request-interceptor)
;; multipart
(multipart/multipart-interceptor)]}})
;; optional default ring handler (if no routes have matched)
(ring/routes
(swagger-ui/create-swagger-ui-handler
{:path "/"
:config {:validatorUrl nil
:operationsSorter "alpha"}})
(ring/create-resource-handler)
(ring/create-default-handler))))
(defn start [port]
(-> {:env :dev
::server/type :jetty
::server/port port
::server/join? false
;; no pedestal routes
::server/routes []
;; allow serving the swagger-ui styles & scripts from self
::server/secure-headers {:content-security-policy-settings
{:default-src "'self'"
:style-src "'self' 'unsafe-inline'"
:script-src "'self' 'unsafe-inline'"}}}
(server/default-interceptors)
;; use the reitit router
(pedestal/replace-last-interceptor router)
(server/dev-interceptors)
(server/create-server)
(server/start))
(println "server running in port 3000"))
(def config
{:adapter/jetty {:port 3000}})
(defmethod ig/init-key :adapter/jetty [_ {:keys [handler] :as opts}]
(start [opts]))
(def system
(ig/init config))
(defn -main [& args]
(system))
我知道这个例子看起来几乎没用(只有一个集成的“组件”),但我只是为一个更复杂的项目(也需要数据库访问)设置框架。