Clojure注释和整数

4

我正在为JaxRs注释的服务添加Swagger注释。

我的代码如下:

(^{
 GET true
 Path "/{who}"
 ApiOperation {:value "Get a hello" :notes "simple clojure GET"}
 Produces ["text/plain; charset=UTF-8"]
 ApiResponses {:value [(ApiResponse {:code 200 :message "yay!"})]}

}

如果我反编译生成的类,注释看起来像这样:

@ApiResponses({@com.wordnik.swagger.annotations.ApiResponse(code=200L, message="yay!")})
@Produces({"text/plain; charset=UTF-8"})
@ApiOperation(value="Get a hello", notes="simple clojure GET")
@Path("/{who}")
@GET(true)

注意第一个注释中的代码=200L

在运行时,这个值必须是int类型,但我不知道如何实现

如果我尝试

ApiResponses {:value [(ApiResponse {:code (int 200) :message "yay!"})]}

我遇到一个编译错误(使用Maven Swagger插件)。
Exception in thread "main" java.lang.ClassCastException: clojure.lang.Var cannot be cast to java.lang.Class, compiling:(pocclj/resourceclj.clj:14)

我已经尝试过

(def success (int 200))
 ...
ApiResponses {:value [(ApiResponse {:code success :message "yay!"})]}

这会导致编译错误:

Exception in thread "main" java.lang.IllegalArgumentException: Unsupported annotation value: success of class class java.lang.Integer, compiling:(pocclj/resourceclj.clj:14)

我尝试了一些其他的方法(如deref等),但找不到解决方案。我对Clojure比较新手,希望能得到一些帮助。提前感谢您。Martin
2个回答

0

你正确地设置了 ':code' 的类型。这可以独立测试:

user> (def something ^{:ApiResponses {:code (int 200) :message "yay!"}} {:some :data :goes :here})
#'user/something

user> (meta something)
{:ApiResponses {:code 200, :message "yay!"}}

user> (-> (meta something) :ApiResponses :code type)
java.lang.Integer

如果没有进行转换,元数据将包含错误的类型:

user> (def something-wrong ^{:ApiResponses {:code 200 :message "yay!"}} {:some :data :goes :here})
#'user/something-wrong

user> (meta something)
{:ApiResponses {:code 200, :message "yay!"}}

user> (-> (meta something-wrong) :ApiResponses :code type)
java.lang.Long

从异常来看,可能是对ApiResponse的调用导致了崩溃。如果ApiResponse是一个期望数字而不是s表达式的宏,那么我可以看到它无法正确处理这个问题。如果它是一个函数,你需要查找为什么它会崩溃。

如果我为ApiResponse提供一个存根实现,那么它对我有效:

user> (definterface Fooi (Something []))
user.Fooi

user> (def ApiResponse identity)
#'user/ApiResponse

user> (deftype Foo []
        Fooi
        (Something
          ^{GET true
            Path "/{who}"
            ApiOperation {:value "Get a hello" :notes "simple clojure GET"}
            Produces ["text/plain; charset=UTF-8"]
            ApiResponses {:value [(ApiResponse {:code (int 200) :message "yay!"})]}}
          [this] (identity this)))
user.Foo

你能否包含ns声明,这样我就可以看到ApiResponse函数如何进入命名空间? - Arthur Ulfeldt

0

我对ApiResponse不太了解,也不太了解注释,但是:看起来像是某个宏(deftype?)正在为您生成注释,并且您需要将其视为int类型的200。Clojure没有int字面量,因此直接向宏传递Integer对象的唯一方法是通过调用其他调用它的宏。这不是一种很好的方式;据我所知,您要么使用eval,要么非常狭窄地针对int字面量。以下是解决方案的草图:

user> (use 'clojure.walk)
user> (defmacro with-int-literals [named-ints & body]
        (prewalk-replace (into {}
                               (for [[k v] (partition 2 named-ints)]
                                 [k (int v)]))
                         `(do ~@body)))

user> (map class (second (macroexpand-1 '(with-int-literals [x 100, y 200] [x y]))))
(java.lang.Integer java.lang.Integer)

因此,如果您将整个deftype(或生成这些注释的任何宏)包装在with-int-literals表单中,则可以为其生成整数而不是长整数。我实际上并不知道这是否有效;也许注释处理器中有某些基本上无法处理int的东西。但至少这样,您可以提供ints并希望获得最佳效果。

编辑

由于您实际上需要元数据中的int文字,而不是在“普通”代码中,因此prewalk实际上不会查看您关心的数据。您必须编写一个版本的walk以合理的方式处理元数据,然后在此处使用它而不是prewalk。


1
Clojure没有int字面量,因此将整数对象直接传递给宏的唯一方法是通过调用其他宏。我有点担心...我希望有类似于200M(即200I等)的东西。感谢澄清。 - mbedoian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接