4

The following code

(-> (.getField (Class/forName
                "ccg.flow.processnodes.text.retrievers.Dictionary.Dictionary")
     "wordsTuples") .getType)

tells me that wordsTuples is a java.util.ArrayList. But what I would like to be able to learn is that it is an ArrayList with elements of type String[], since it happens to be declared like this:

public class Dictionary extends ProcessNode {
    public ArrayList<String[]> wordsTuples;

    public ArrayList<String> words;
...

Is there a way to obtain the "type hint" information programmatically within Clojure?

Joe Corneli
  • 642
  • 1
  • 6
  • 18
  • I think this IntelliJ Plugin does what you're looking for: https://cursiveclojure.com/ – kuporific May 28 '15 at 14:29
  • "It will be a commercial product, with pricing to be released soon." - I'd like a generic solution. – Joe Corneli May 28 '15 at 14:32
  • I think you can use `class` instead of that more complicated expression to identify the object as an `ArrayList`. e.g. `(class (java.util.ArrayList. ["a" "b" "c"])) ;=> java.util.ArrayList`. – Mars May 28 '15 at 15:39
  • 1
    This question appears to be incorrectly titled. Type-hints in Clojure are there to improve performance of certain operations by hinting types to the Clojure compiler. The question's real concern appears to be about how one would obtain the generic type parameter from a generic Java collection. Perhaps asker would like to revise the title? – Scott May 28 '15 at 15:59
  • See here: http://stackoverflow.com/questions/1942644/get-generic-type-of-java-util-list – BillRobertson42 May 28 '15 at 19:51
  • This is a duplicate of: stackoverflow.com/questions/14402585/how-do-you-get-listtype-with-reflection - I voted to close and it was removed wtf. If you want free stackoverflow points, port that answer to Java interop now, lol. – Leon Grapenthin May 28 '15 at 21:09
  • @ScottLowe thanks, I've revised the title to be more descriptive, and I put _type hints_ in scare quotes in the body of the question. – Joe Corneli May 29 '15 at 11:27
  • @Bill, thanks that link seems to have what I needed. I modified the example code into a candidate answer, below. – Joe Corneli May 29 '15 at 11:27

3 Answers3

1

No, because of type erasure. https://docs.oracle.com/javase/tutorial/java/generics/erasure.html

There is a wealth of data on your erasure on google.

freakhill
  • 628
  • 3
  • 6
0

You may use a simple hack based on fact which data is in your list.

E.g. you have got some list of strings:

(def lst (java.util.ArrayList. ["my" "list" "of" "strings"]))

Then you can get type of item:

(if (and (instance? java.util.List lst) 
         (not (.isEmpty lst))) 
   (.getName (.getClass (.get lst 0))))

Drawback of this workaround is that you cannot get reflection info about empty list b/c of erasure mentioned by freakhill, but who cares about empty lists ;)?

Hope this helps.

Community
  • 1
  • 1
domax
  • 649
  • 3
  • 13
0

Thanks to the comments, I found this answer on the question Get generic type of java.util.List. And from there, a simple modification of my sample code now works as desired:

(-> (.getField (Class/forName
             "ccg.flow.processnodes.text.retrievers.Dictionary.Dictionary")
     "wordsTuples") .getGenericType)

Returns:

#<ParameterizedTypeImpl java.util.ArrayList<java.lang.String[]>>
Community
  • 1
  • 1
Joe Corneli
  • 642
  • 1
  • 6
  • 18