Clojure 对java对象使用类似于解构的语法
我正在编写代码,因此我必须遍历作为Java类实现的相当复杂的nexted数据结构,主要是POJO。我喜欢在使用clojure映射或记录时如何使用多级解构语法——我认为这比使用。或->操作 例如,我希望能够编写以下代码(由以下代码组成): 我现在的做法是,我有一组“桥接”函数,可以将给定类型的Java对象转换为映射。例如,它可能如下所示:Clojure 对java对象使用类似于解构的语法,clojure,Clojure,我正在编写代码,因此我必须遍历作为Java类实现的相当复杂的nexted数据结构,主要是POJO。我喜欢在使用clojure映射或记录时如何使用多级解构语法——我认为这比使用。或->操作 例如,我希望能够编写以下代码(由以下代码组成): 我现在的做法是,我有一组“桥接”函数,可以将给定类型的Java对象转换为映射。例如,它可能如下所示: (defn map-account [account] {:registration-date (.getRegistrationDate account)
(defn map-account [account]
{:registration-date (.getRegistrationDate account)
:order-history (map bean (.getOrderHistory account))
:personal-data (bean (.getPersonalData account)})
这是可行的,但是有很多容易出错的样板文件(例如,假设account.getPersonalData()返回null),我想知道是否有一种方法可以使用类似映射分解的语法来处理Java对象,这种语法或多或少是“开箱即用”的
经过思考,如果它是实际的解构或类似的东西(例如,一些古怪的宏),只要它能给我与前者相比的表现力,我就不珍贵了。如果可以用一种惰性的方式完成,例如,对象图的分支根本不会被遍历,除非它们被实际访问
编辑:使用clojure.core.bean
或clojure.java.data
可以实现类似的功能,后者是递归的,前者不是。我知道他们可能会扮演一个角色,事实上,我在上面的例子中使用bean
我使用这些方法的主要问题是它们缺乏灵活性,不允许对结果进行任何调整。举几个可能非常有用的例子:
- 其中一个对象可能与JavaBeans约定部分不兼容
- 可能需要扁平化层次结构的某些部分,尤其是在底层JavaAPI非常惯用的情况下。在某些API中,经常会为通常组合在一起的成对对象创建实用程序类,例如。在Clojure中,它只会使代码更加复杂
- 对递归应该走多远的控制是有限的。对于重要的对象图,它可能非常昂贵
clojure.core/bean
(bean (java.util.Date.))
这将使用getter和setter将Java对象转换为Clojure映射:
{:day 3,
:date 8,
:time 1578498930902,
:month 0,
:seconds 30,
:year 120,
:class java.util.Date,
:timezoneOffset 0,
:hours 15,
:minutes 55}
尽管它不会递归执行,但为此,您可以使用
clojure.java.data
。这是在这个问题中描述的:我认为这个问题更多的是关于如何将对象转换为Clojure数据,而不是具体的关于解构,即如果您解决了转换问题,那么解构问题已经解决了
Clojure 1.10定义了和。您可以为您的类型扩展Datafiable
协议,并完全控制它们如何表示为数据。下面是一个使用java.net.URI
的简单示例:
(extend-protocol Datafiable
java.net.URI
(datafy [u]
{:host (.getHost u)}))
(datafy (java.net.URI. "http://clojure.org"))
=> {:host "clojure.org"}
它还定义和可导航
,可用于延迟导航,例如处理循环结构或实现成本高昂的数据
我认为
bean
类函数(涵盖一般情况)与datafy
和nav
的某种组合应该会给您提供所需的所有控制/灵活性。您检查过吗?有用的库。但我认为java.data是另一种方式?例如,从clojure映射到对象?哦,等等,您也有,自述文件中没有提到它。正如我在下面回答的,我的bean和java.data的主要问题是无法自定义映射。有些对象可能不是完全一致的,而且根本无法解决itI问题。在我目前针对某些对象的方法中,我使用bean。我对bean和java.data的主要问题是不可能定制映射。有些对象可能不是完全一致的,根本没有地方可以解决它。另一个有点小的问题是,它不处理循环,尽管在我的案例中这不是一个问题,是的,我也偶然发现了这一点,并开始使用它。这并不理想,因为纯解构将允许延迟查找,而datafy必须预先构建图形。如果有一个称为Destructurable的协议,那就太好了,它将实现一个等价于使用密钥获取的协议。不过,这很好
(extend-protocol Datafiable
java.net.URI
(datafy [u]
{:host (.getHost u)}))
(datafy (java.net.URI. "http://clojure.org"))
=> {:host "clojure.org"}