【问题标题】:java.lang.StackOverflowError in clojure.java.data from-javajava.lang.StackOverflowError in clojure.java.data from-java
【发布时间】:2017-06-20 04:57:49
【问题描述】:

我有一个由 Protocol Buffers 生成的 Java 类,称为 TextLine。当我实例化 Java 对象时:

(def tb (-> (TextLine/newBuilder) (.setText "this is a text line") (.build)))

然后调用:

(from-java tb)

我收到 StackOverflowError:

java.lang.StackOverflowError: null
 at java.lang.Class.getMethods (Class.java:1614)
clojure.lang.Reflector.getMethods (Reflector.java:373)
clojure.lang.Reflector.invokeNoArgInstanceMember (Reflector.java:311)
clojure.java.data$add_getter_fn.invokeStatic (data.clj:38)
clojure.java.data$add_getter_fn.invoke (data.clj:37)
clojure.core.protocols$fn__6755.invokeStatic (protocols.clj:167)
clojure.core.protocols/fn (protocols.clj:124)
clojure.core.protocols$fn__6710$G__6705__6719.invoke (protocols.clj:19)
clojure.core.protocols$seq_reduce.invokeStatic (protocols.clj:31)
clojure.core.protocols$fn__6732.invokeStatic (protocols.clj:75)
clojure.core.protocols/fn (protocols.clj:75)
clojure.core.protocols$fn__6684$G__6679__6697.invoke (protocols.clj:13)
clojure.core$reduce.invokeStatic (core.clj:6545)
clojure.core$reduce.invoke (core.clj:6527)
clojure.java.data$eval554$fn__555.invoke (data.clj:135)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
clojure.java.data$make_getter_fn$fn__501.invoke (data.clj:35)
clojure.java.data$eval554$fn__555$iter__556__560$fn__561.invoke (data.clj:136)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.next (RT.java:688)
clojure.core$next__4341.invokeStatic (core.clj:64)
clojure.core.protocols$fn__6755.invokeStatic (protocols.clj:168)
clojure.core.protocols/fn (protocols.clj:124)
clojure.core.protocols$fn__6710$G__6705__6719.invoke (protocols.clj:19)
clojure.core.protocols$seq_reduce.invokeStatic (protocols.clj:31)
clojure.core.protocols$fn__6738.invokeStatic (protocols.clj:75)
clojure.core.protocols/fn (protocols.clj:75)
clojure.core.protocols$fn__6684$G__6679__6697.invoke (protocols.clj:13)
clojure.core$reduce.invokeStatic (core.clj:6545)
clojure.core$into.invokeStatic (core.clj:6610)
clojure.core$into.invoke (core.clj:6604)
clojure.java.data$eval554$fn__555.invoke (data.clj:136)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
clojure.java.data$make_getter_fn$fn__501.invoke (data.clj:35)
clojure.java.data$eval554$fn__555$iter__556__560$fn__561.invoke (data.clj:136)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.next (RT.java:688)
clojure.core$next__4341.invokeStatic (core.clj:64)
clojure.core.protocols$fn__6755.invokeStatic (protocols.clj:168)
clojure.core.protocols/fn (protocols.clj:124)
clojure.core.protocols$fn__6710$G__6705__6719.invoke (protocols.clj:19)
clojure.core.protocols$seq_reduce.invokeStatic (protocols.clj:31)
clojure.core.protocols$fn__6738.invokeStatic (protocols.clj:75)
clojure.core.protocols/fn (protocols.clj:75)
clojure.core.protocols$fn__6684$G__6679__6697.invoke (protocols.clj:13)
clojure.core$reduce.invokeStatic (core.clj:6545)
clojure.core$into.invokeStatic (core.clj:6610)
clojure.core$into.invoke (core.clj:6604)
clojure.java.data$eval554$fn__555.invoke (data.clj:136)
clojure.lang.MultiFn.invoke (MultiFn.java:229)
clojure.java.data$make_getter_fn$fn__501.invoke (data.clj:35)
clojure.java.data$eval554$fn__555$iter__556__560$fn__561.invoke (data.clj:136)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.next (RT.java:688)
clojure.core$next__4341.invokeStatic (core.clj:64)
clojure.core.protocols$fn__6755.invokeStatic (protocols.clj:168)
clojure.core.protocols/fn (protocols.clj:124)
clojure.core.protocols$fn__6710$G__6705__6719.invoke (protocols.clj:19)
....

关于可能导致此问题的原因或解决问题的最佳方法有什么想法吗?我真的很想将 Java 对象作为 Clojure 映射进行交互。

【问题讨论】:

  • 您可能希望在 Google 网上论坛邮件列表 clojure@googlegroups.com 上提出这个问题

标签: clojure clojure-java-interop clojure-contrib


【解决方案1】:

我不建议在任何事情上使用clojure.data.java/from-java。简单函数可以将任意 Java 对象转换为合理的 Clojure 映射而不需要任何源对象的领域知识的想法是一厢情愿的想法。

我在今天之前没有听说过它,但是我去查看了源代码,正如预期的那样,它基本上只是clojure.core/bean 的扩展,这是对一个不可能的问题的又一次有希望的尝试。具体来说,它使用 javabean 自省来尝试猜测什么 getter 和 setter 代表有意义的字段。但是,现在,与许多并非设计用作 bean 的 Java 类一样,protobuf 类包含循环引用,这意味着递归地对它们进行 bean 化是一项无限的任务,最终会导致堆栈溢出。

该怎么做呢?我建议只通过 Java 互操作使用生成的 Java protobuf 类,或者尝试找到一个好的 Clojure protobuf 库。不要尝试将 Java 对象转换为惯用的 Clojure 数据。

【讨论】:

  • 谢谢!我敢肯定,你救了我几天的挫败感。我发现似乎是一个有信誉的Clojure protobuf library。你会碰巧知道它是否支持proto3吗?另外,根据您的经验,使用 Java protobuf 类而不是像这个库这样的东西会更好吗?
  • 几年前,我编写了一段代码,可以将或多或少的通用 Apache Thrift 对象树转换为 Clojure 数据结构。我没有在生成的类中枚举字段,而是使用了一些 Thrift 生成的对象中可用的元数据。我可以获得每个类的“业务”字段及其类型。因此,我避免了仅用于 Thrift 的额外字段。也许类似的方法也可以应用于 Protobuf。
  • @ez121sl 是的,这正是 Clojure 的一个好的 protobuf 库会做的事情,它之所以有效,是因为 protobuf 和 thrift 一样,有足够的元数据来有意义地描述对象。
  • 我尝试让 clojure-protobufproto3 一起工作,但没有成功。最后一次提交是 2013 年 10 月。如果性能不是问题,为什么不直接从 JSON 反序列化/到 JSON 并转换成 Clojure 映射?看起来这将是使用惯用 Clojure 结构的最简单的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-02
  • 1970-01-01
  • 1970-01-01
  • 2022-12-01
相关资源
最近更新 更多