Clojure: how to switch to Java classes

I have a java class in clojure that comes from a method that returns classes. I want the case to switch to them, for example:

            (case type
                java.lang.String (println "Found String" name)
                java.lang.Long (println "Found Long" name)
                java.nio.ByteBuffer (println "Found ByteBuffer" name)
                java.lang.Boolean (println "Found Boolean" name)
                java.math.BigDecimal (println "Found BigDecimal" name)
                java.lang.Double (println "Found Double" name)
                java.lang.Float (println "Found Float" name)
                java.net.InetAddress (println "Found InetAddress" name)
                java.lang.Integer (println "Found Integer" name)
                java.util.Date (println "Found Date" name)
                java.util.UUID (println "Found UUID" name)
                java.math.BigInteger (println "Found BigInteger" name)
                java.util.List (println "Found List" name)
                java.util.Set (println "Found Set" name)
                java.util.Map (println "Found Map" name))

      

But when I run this I get

 java.lang.IllegalArgumentException: No matching clause: class java.util.UUID

      

This is what is thrown in when no suitable case is found. How do I match a class in a case clause?

+3


source to share


4 answers


You can't do anything better than cheshire , which basically repeats calls instance?

like:

(condp instance? x
  String :string
  Integer :int
  :unknown)

      



If you don't want to pay attention to subtyping and only use exact matches on type x, you can use instead (condp = (class x) ...)

.

+4


source


Use a map instead of a form case

:

def case-map
  {java.util.Set "Set",
   java.math.BigInteger "BigInteger",
   java.lang.Double "Double",
   java.math.BigDecimal "BigDecimal",
   java.util.List "List",
   java.lang.Float "Float",
   java.util.UUID "UUID",
   java.lang.String "String",
   java.lang.Integer "Integer",
   java.nio.ByteBuffer "ByteBuffer",
   java.lang.Boolean "Boolean",
   java.net.InetAddress "InetAddress",
   java.util.Date "Date",
   java.util.Map "Map",
   java.lang.Long "Long"})

(defn what-is [x] (str (case-map (type x)) " " x))

      

For instances:



(what-is (java.util.Date.))
"Date Mon Sep 22 08:17:55 BST 2014"

(what-is (java.util.UUID. 0 0))
"UUID 00000000-0000-0000-0000-000000000000"

      


Edit: The warning in @cgrand's answer against compiling AOT seems to apply to this solution as well.

+3


source


Here's how to trick this issue:

=> (map #(case (class %)
           #=java.lang.String (str "Found String " %)
           #=java.lang.Long (str "Found Long " %))
     ["a" 42])
("Found String a" "Found Long 42")

      

However, since classes do not have a stable hashcode, never use this for compiled AOT code.

+1


source


I ended up using multimethods

(defmulti get-row-data-for-class (fn [type-class name row] type-class))
(defmethod get-row-data-for-class java.lang.Boolean [type-class name row] (.getBool row name))
(defmethod get-row-data-for-class java.lang.Double [type-class name row] (.getDouble row name))
(defmethod get-row-data-for-class java.lang.Float [type-class name row] (.getFloat row name))

      

Then something like

(let [data (get-row-data-for-class type-class name row)])

      

0


source







All Articles