type-reflect

added
1.3

ns
clojure.reflect

type
function

(type-reflect typeref & options)

Alpha - subject to change.
Reflect on a typeref, returning a map with :bases, :flags, and
:members. In the discussion below, names are always Clojure symbols.

:bases            a set of names of the type's bases
:flags            a set of keywords naming the boolean attributes
of the type.
:members          a set of the type's members. Each member is a map
and can be a constructor, method, or field.

Keys common to all members:
:name             name of the type 
:declaring-class  name of the declarer
:flags            keyword naming boolean attributes of the member

Keys specific to constructors:
:parameter-types  vector of parameter type names
:exception-types  vector of exception type names

Key specific to methods:
:parameter-types  vector of parameter type names
:exception-types  vector of exception type names
:return-type      return type name

Keys specific to fields:
:type             type name

Options:

:ancestors     in addition to the keys described above, also
include an :ancestors key with the entire set of
ancestors, and add all ancestor members to
:members.
:reflector     implementation to use. Defaults to JavaReflector,
AsmReflector is also an option.

                ;;;; Alphabetically list all public static fields in java.lang.Integer

(use 'clojure.reflect)

(->> java.lang.Integer 
     clojure.reflect/type-reflect
     :members 
     (filter #(instance? clojure.reflect.Field %)) 
     (filter #(:public (:flags %)))
     (filter #(:static (:flags %)))
     (map #(vector (:name %) (:type %)))
     (sort)
     (pprint))

;;=> ([BYTES int]
;;    [MAX_VALUE int]
;;    [MIN_VALUE int]
;;    [SIZE int]
;;    [TYPE java.lang.Class])
            
                ;;;; List class hierarchy for a particular class 

(defn class-hierarchy [clazz]
  (let [refl (fn [c] (assoc (clojure.reflect/type-reflect c) :name c))]
    (loop [type (refl clazz) hierarchy '()]
      (let [parent (->> type
                        :bases
                        (map refl)
                        (remove #(:interface (:flags %)))
                        first)]
         (if parent
           (recur parent (conj hierarchy (:name type)))
           (conj hierarchy java.lang.Object))))))

(pprint (class-hierarchy javax.security.auth.login.CredentialNotFoundException))
;;=> (java.lang.Object
;;    java.lang.Throwable
;;    java.lang.Exception
;;    java.security.GeneralSecurityException
;;    javax.security.auth.login.LoginException
;;    javax.security.auth.login.CredentialException
;;    javax.security.auth.login.CredentialNotFoundException)

(pprint (class-hierarchy javax.swing.JPasswordField$AccessibleJPasswordField))
;;=> (java.lang.Object
;;    javax.accessibility.AccessibleContext
;;    java.awt.Component$AccessibleAWTComponent
;;    java.awt.Container$AccessibleAWTContainer
;;    javax.swing.JComponent$AccessibleJComponent
;;    javax.swing.text.JTextComponent$AccessibleJTextComponent
;;    javax.swing.JTextField$AccessibleJTextField
;;    javax.swing.JPasswordField$AccessibleJPasswordField)

            
                (require '(clojure [reflect :as cr] [pprint :as pp]))

;; Let us see what is available in the DynamicClassLoader
(->> clojure.lang.DynamicClassLoader 
     cr/type-reflect
     :members
     (sort-by :name)
     (pp/print-table [:name :flags :parameter-types]))
;|                           :name |                      :flags |                           :parameter-types |
;|---------------------------------+-----------------------------+--------------------------------------------|
;|                      EMPTY_URLS |           #{:static :final} |                                            |
;|                          addURL |                  #{:public} |                             [java.net.URL] |
;|                      classCache |                  #{:static} |                                            |
;| clojure.lang.DynamicClassLoader |                  #{:public} |                    [java.lang.ClassLoader] |
;| clojure.lang.DynamicClassLoader |                  #{:public} |                                         [] |
;|                    constantVals |                         #{} |                                            |
;|                     defineClass |                  #{:public} | [java.lang.String byte<> java.lang.Object] |
;|                       findClass |               #{:protected} |                         [java.lang.String] |
;|               findInMemoryClass |                  #{:static} |                         [java.lang.String] |
;|                    getConstants |                  #{:public} |                                      [int] |
;|                       loadClass | #{:synchronized :protected} |                 [java.lang.String boolean] |
;|               registerConstants |                  #{:public} |                   [int java.lang.Object<>] |
;|                              rq |           #{:static :final} |                                            |