【问题标题】:java interop and clojure macrosjava互操作和clojure宏
【发布时间】:2017-03-25 14:29:55
【问题描述】:

我面临以下问题。我正在尝试在 hapi-fhir api 之上构建一个函数(宏)

function (macro) on topo of hapi-fhir api
  (defmacro search-patient-resource
  "This macro searches for a specified resource based on the
  Patient Id"
  [res id json?]
  (let [tmp (symbol res)]
    (if json?
         `(. (. (. (. (. (. @restful-client search) (forResource ~(symbol res))) encodedJson) (where (. (. ~(resolve tmp)  PATIENT)
                    (hasId (str ~id))))) (returnBundle Bundle)) execute)
    )))

此宏在执行类似操作时起作用

(let [id 10465]
 (search-patient-resource "Observation" id true))
=>#object[ca.uhn.fhir.model.dstu2.resource.Bundle 0x520a3cc9 "Bundle[id=Bundle/9ca62ae1-82af-488f-a166-5b014f45886e]"]

但不是在我这样做的时候

 (let [id 10465 res "Observation"]
 (search-patient-resource "Observation" id true))
=> CompilerException java.lang.NullPointerException, compiling:(apycare_emrspp/hapi_fhir_helper.clj:122:1)

我当然不能写(符号~res),因为那时读者会评估 (符号“观察”)在编译时,我得到

 CompilerException java.lang.IllegalArgumentException: No matching method found: forResource for class ca.uhn.fhir.rest.client.GenericCl
 ient$SearchInternal, compiling:(apycare_emrspp/hapi_fhir_helper.clj:122:1)

也没有

   (resolve (symbol ~res) 

也没有

   (resolve ~(symbol re) 

工作。

原来的java代码是这样的

 FhirContext ctx = FhirContext.forDstu2();
 String serverBase = "fhirtest.uhn.ca/baseDstu2";
 IGenericClient client = ctx.newRestfulGenericClient(serverBase); 
 Bundle results = client .search() .forResource(Observation.class) 
.where(Observation.PATIENT.hasId("1234")) 
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class) 
.execute(); 

我所做的是尝试拨打电话

 client
 .search() 
 .forResource(another-resource.class) 
 .where(another-resource.PATIENT.hasId(another-id)) 
 .returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class) 
 .execute();

【问题讨论】:

  • 我不明白你为什么要把它写成一个宏。看来你可以把它写成一个函数来避免这个问题。
  • 怎么样?我试图把它写成一个函数,但是如何在没有 clojure 编译器抱怨的情况下传递任意方法名称?例如,假设我想通过 [Observation] 来调用 (.resource Observation)。如果我将它作为字符串传递,那么 (.resource (symbol "Observation)) 将不起作用,除非通过宏从列表中扩展。
  • 请说明它的工作方式。
  • 传递一个字符串和Id作为参数,该字符串必须转换为同名的java方法并被调用。这有效,但在我预定义字符串时无效。那就是当我通过“观察”时,我将 (forResource ~(symbol res)) 转换为 (forResource Observation) ,但如果我这样做 (def st "Observation") 那么我得到 (forResource st)。
  • 我试图创建一个函数来从字符串创建符号,但它不起作用

标签: clojure macros clojure-java-interop


【解决方案1】:

好的。我面临的问题也是由于我在从不同的命名空间调用代码时忽略了导入适当的符号。 当 res = "Resource" 在上面的代码中 那么

 ~(symbol "Resource")

如果我没有先添加,则无法预先解决

(import '(ca.uhn.fhir.model.dstu2.resource.Resource))  

在命名空间中调用了宏。 这使得代码在大多数情况下都能正常工作。使其功能齐全 我不得不改变

 ~(symbol "Resource")

到 (身份~(符号“资源”))

这是java的正确翻译

Resource.class 到 Clojure 代码

最后,宏采用以下形式:

 (defmacro search-patient-resource
 "This macro searches for a specified resource based on the
  Patient Id"
 [res id json?]
 (let [tmp (symbol res)]
   (if json?
     `(. (. (. (. (. (. @restful-client search)
                     (forResource (identity ~(symbol res))))
                  encodedJson)
               (where
                 (.
                  (. ~(resolve tmp)  PATIENT)
                  (hasId (~str ~id)))))
            (returnBundle Bundle))
         execute)
     `(. (. (. (. (. @restful-client search)
                  (forResource (identity ~(symbol res))))
               (where (. (. ~(symbol res)
                            PATIENT)
                         (hasId (str ~id)))))
            (returnBundle Bundle))
         execute))))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-12
    • 1970-01-01
    • 1970-01-01
    • 2019-07-18
    • 2012-08-09
    • 2014-03-31
    相关资源
    最近更新 更多