Clojure注释和整数

时间:2013-08-16 19:20:08

标签: clojure clojure-java-interop

我正在向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很新,并且迫切需要一些帮助。

提前致谢

马丁

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

我真的不知道ApiResponse,或者很多关于注释的内容,但是:看起来有些宏(deftype?)正在为你生成注释,你需要它来看200 INT。 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(或任何生成这些注释的宏),您可以为它生成整数而不是long。我实际上并不知道这会起作用;或许注释处理器中的某些东西由于某种原因从根本上无法处理整数。但至少通过这种方式,你可以提供它并希望最好。

修改

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