Welcome! Please see the About page for a little more info on how this works.

0 votes
in java.data by

(clojure.java.data/from-java-deep Class {}) throws StackOverflowError.

The docs don't say anything about this, but I'd like to see this case covered by java.data.

You can find a tiny example in https://github.com/henrik42/java.data-with-Class/tree/master

This shows the error.

clj -X main/this-call-throws
Execution error (StackOverflowError) at clojure.java.data/add-deep-getter-fn (data.clj:121).

As a workaround I'm using (defmethod j/from-java-deep Class [clazz _] {:class clazz}) -- but this is not really a solution since it does not even give you what (from-java-shallow Class {}) would give you.

clj -X main/this-call-works
(j/from-java-deep Class) ;=>  {:class java.lang.Class}


(defmethod j/from-java-deep Class [clazz _] (j/from-java-shallow Class {}))

instead isn't much better because it's not a deep-copy either.

3 Answers

0 votes
selected by
Best answer

https://clojure.atlassian.net/browse/JDATA-23 -- I probably won't get to it this month, but the exact solution needs some analysis anyway.

0 votes

Is clojure.java.reflect a better match for what you're trying to do?

There is obviously a lot of circularity in Class and its fields.

I'd really like to use clojure.java.data and its conversion logic. Since I do not control the classes I'm using, it'd be great, if c.j.d would just not throw for java.lang.Class. From there on I'm fine and know what to do.
0 votes

I guess my question would be:

What do you think (j/from-java-deep Class {}) should produce?

When you do (j/from-java-shallow Class {}) you can see a lot of properties that are of type array of Class so if you try to "convert" those from Java to Clojure, you'll get recursion -- and in the case of Class there is no "bottom" to that recursion.

For from-java-deep to not blow up here, there needs to be some "bottom" to that recursion. Either an arbitrary depth or tracking all the Java objects you've seen and not expanding an identical object further down the tree (assuming that check is sufficient to create a "bottom"). But then there's also the question of what from-java-deep should do at that point: return nil for that subtree, return some other sentinel value, return the Java object itself, throwing a different exception (to indicate which getter expansion failed, so you could try again and tell it not to expand that getter)?

Yes that's all true. So my minimum requirement would be that `(j/from-java-deep Class {})` does not throw. Thinking about my workaround, maybe `{:class java.lang.Class}` isn't such a bad result for this case. If it's documented users can detect this case and do whatever they think is appropriate for their use case. There are some other cases in `clojure.java.data` that receive special treatment so this would be the n+1-th case.