Как исследовать методы Java через REPL

Я играю с Clojure и Java Interop, и я придумал следующее, чтобы проверить методы некоторого экземпляра:

(defn methods-of [instance & [string]]
  {:pre [(nil? instance)]}
  (filter #(re-find (re-pattern (or string #".*")) %) (map #(.getName %) (-> instance class .getMethods))))

Но мне было интересно, учитывая, что это очень практичный способ получить эту информацию из REPL, есть ли какая-то библиотека для достижения этого (и многого другого).


person Andrea Richiardi    schedule 30.08.2014    source источник
comment
Я знаю плагин emacs, который делает это.   -  person Anoop    schedule 30.08.2014
comment
Который из? Если есть возможность, было бы здорово портировать. Это не должно быть сложно.   -  person Andrea Richiardi    schedule 30.08.2014
comment
braveclojure.com/using-emacs-with-clojure . . эту ссылку я нашел в Интернете. Я не уверен, какой именно. Я видел, как человек использовал его на встрече.   -  person Anoop    schedule 30.08.2014


Ответы (2)


Clojure поставляется с пространством имен, которое помогает с отражением: clojure.reflect. Основная используемая функция — clojure.reflect/reflect.

user> (require '[clojure.reflect :as reflect])
nil
user> (clojure.pprint/pprint (reflect/reflect (java.util.Date.)))
{:bases
 #{java.io.Serializable java.lang.Comparable java.lang.Object
   java.lang.Cloneable},
 :flags #{:public},
 :members
 #{{:name getSeconds,
    :return-type int,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name serialVersionUID,
    :type long,
    :declaring-class java.util.Date,
    :flags #{:private :static :final}}
   {:name getCalendarDate,
    :return-type sun.util.calendar.BaseCalendar$Date,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:private :final}}
   {:name after,
    :return-type boolean,
    :declaring-class java.util.Date,
    :parameter-types [java.util.Date],
    :exception-types [],
    :flags #{:public}}
   {:name hashCode,
    :return-type int,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name wtb,
    :type java.lang.String<>,
    :declaring-class java.util.Date,
    :flags #{:private :static :final}}
   {:name setMonth,
    :return-type void,
    :declaring-class java.util.Date,
    :parameter-types [int],
    :exception-types [],
    :flags #{:public}}
   {:name getMonth,
    :return-type int,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name getCalendarSystem,
    :return-type sun.util.calendar.BaseCalendar,
    :declaring-class java.util.Date,
    :parameter-types [int],
    :exception-types [],
    :flags #{:private :static :final}}
   {:name fastTime,
    :type long,
    :declaring-class java.util.Date,
    :flags #{:transient :private}}
   {:name defaultCenturyStart,
    :type int,
    :declaring-class java.util.Date,
    :flags #{:private :static}}
   {:name writeObject,
    :return-type void,
    :declaring-class java.util.Date,
    :parameter-types [java.io.ObjectOutputStream],
    :exception-types [java.io.IOException],
    :flags #{:private}}
   {:name getMillisOf,
    :return-type long,
    :declaring-class java.util.Date,
    :parameter-types [java.util.Date],
    :exception-types [],
    :flags #{:static :final}}
   {:name getMinutes,
    :return-type int,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name ttb,
    :type int<>,
    :declaring-class java.util.Date,
    :flags #{:private :static :final}}
   {:name setDate,
    :return-type void,
    :declaring-class java.util.Date,
    :parameter-types [int],
    :exception-types [],
    :flags #{:public}}
   {:name setSeconds,
    :return-type void,
    :declaring-class java.util.Date,
    :parameter-types [int],
    :exception-types [],
    :flags #{:public}}
   {:name java.util.Date,
    :declaring-class java.util.Date,
    :parameter-types [long],
    :exception-types [],
    :flags #{:public}}
   {:name getTimeImpl,
    :return-type long,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:private :final}}
   {:name setYear,
    :return-type void,
    :declaring-class java.util.Date,
    :parameter-types [int],
    :exception-types [],
    :flags #{:public}}
   {:name normalize,
    :return-type sun.util.calendar.BaseCalendar$Date,
    :declaring-class java.util.Date,
    :parameter-types [sun.util.calendar.BaseCalendar$Date],
    :exception-types [],
    :flags #{:private :final}}
   {:name getHours,
    :return-type int,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name getYear,
    :return-type int,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name java.util.Date,
    :declaring-class java.util.Date,
    :parameter-types [int int int int int int],
    :exception-types [],
    :flags #{:public}}
   {:name java.util.Date,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name UTC,
    :return-type long,
    :declaring-class java.util.Date,
    :parameter-types [int int int int int int],
    :exception-types [],
    :flags #{:static :public}}
   {:name getTime,
    :return-type long,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name getJulianCalendar,
    :return-type sun.util.calendar.BaseCalendar,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:synchronized :private :static :final}}
   {:name getCalendarSystem,
    :return-type sun.util.calendar.BaseCalendar,
    :declaring-class java.util.Date,
    :parameter-types [sun.util.calendar.BaseCalendar$Date],
    :exception-types [],
    :flags #{:private :static :final}}
   {:name setTime,
    :return-type void,
    :declaring-class java.util.Date,
    :parameter-types [long],
    :exception-types [],
    :flags #{:public}}
   {:name setMinutes,
    :return-type void,
    :declaring-class java.util.Date,
    :parameter-types [int],
    :exception-types [],
    :flags #{:public}}
   {:name cdate,
    :type sun.util.calendar.BaseCalendar$Date,
    :declaring-class java.util.Date,
    :flags #{:transient :private}}
   {:name getDay,
    :return-type int,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name toString,
    :return-type java.lang.String,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name java.util.Date,
    :declaring-class java.util.Date,
    :parameter-types [int int int int int],
    :exception-types [],
    :flags #{:public}}
   {:name java.util.Date,
    :declaring-class java.util.Date,
    :parameter-types [int int int],
    :exception-types [],
    :flags #{:public}}
   {:name toInstant,
    :return-type java.time.Instant,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name clone,
    :return-type java.lang.Object,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name from,
    :return-type java.util.Date,
    :declaring-class java.util.Date,
    :parameter-types [java.time.Instant],
    :exception-types [],
    :flags #{:static :public}}
   {:name compareTo,
    :return-type int,
    :declaring-class java.util.Date,
    :parameter-types [java.util.Date],
    :exception-types [],
    :flags #{:public}}
   {:name toLocaleString,
    :return-type java.lang.String,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name convertToAbbr,
    :return-type java.lang.StringBuilder,
    :declaring-class java.util.Date,
    :parameter-types [java.lang.StringBuilder java.lang.String],
    :exception-types [],
    :flags #{:private :static :final}}
   {:name getTimezoneOffset,
    :return-type int,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name toGMTString,
    :return-type java.lang.String,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name normalize,
    :return-type sun.util.calendar.BaseCalendar$Date,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:private :final}}
   {:name parse,
    :return-type long,
    :declaring-class java.util.Date,
    :parameter-types [java.lang.String],
    :exception-types [],
    :flags #{:static :public}}
   {:name jcal,
    :type sun.util.calendar.BaseCalendar,
    :declaring-class java.util.Date,
    :flags #{:private :static}}
   {:name gcal,
    :type sun.util.calendar.BaseCalendar,
    :declaring-class java.util.Date,
    :flags #{:private :static :final}}
   {:name before,
    :return-type boolean,
    :declaring-class java.util.Date,
    :parameter-types [java.util.Date],
    :exception-types [],
    :flags #{:public}}
   {:name compareTo,
    :return-type int,
    :declaring-class java.util.Date,
    :parameter-types [java.lang.Object],
    :exception-types [],
    :flags #{:synthetic :bridge :public}}
   {:name getDate,
    :return-type int,
    :declaring-class java.util.Date,
    :parameter-types [],
    :exception-types [],
    :flags #{:public}}
   {:name readObject,
    :return-type void,
    :declaring-class java.util.Date,
    :parameter-types [java.io.ObjectInputStream],
    :exception-types
    [java.io.IOException java.lang.ClassNotFoundException],
    :flags #{:private}}
   {:name setHours,
    :return-type void,
    :declaring-class java.util.Date,
    :parameter-types [int],
    :exception-types [],
    :flags #{:public}}
   {:name getCalendarSystem,
    :return-type sun.util.calendar.BaseCalendar,
    :declaring-class java.util.Date,
    :parameter-types [long],
    :exception-types [],
    :flags #{:private :static :final}}
   {:name equals,
    :return-type boolean,
    :declaring-class java.util.Date,
    :parameter-types [java.lang.Object],
    :exception-types [],
    :flags #{:public}}
   {:name java.util.Date,
    :declaring-class java.util.Date,
    :parameter-types [java.lang.String],
    :exception-types [],
    :flags #{:public}}}}
nil
user> 

Иногда проще использовать bean, чтобы увидеть различные присутствующие поля.

user> (clojure.pprint/pprint (bean (java.util.Date.)))
{:seconds 9,
 :date 30,
 :class java.util.Date,
 :minutes 13,
 :hours 8,
 :year 114,
 :timezoneOffset 420,
 :month 7,
 :day 6,
 :time 1409411589031}
nil

Использование reflect/reflect для перечисления всех имен методов (как вы делали в своем примере):

user> (->> (reflect/reflect (java.util.Date.)) :members (filter :return-type) (map :name))
(getSeconds getCalendarDate after hashCode setMonth getMonth getCalendarSystem writeObject getMillisOf getMinutes setDate setSeconds getTimeImpl setYear normalize getHours getYear UTC getTime getJulianCalendar getCalendarSystem setTime setMinutes getDay toString toInstant clone from compareTo toLocaleString convertToAbbr getTimezoneOffset toGMTString normalize parse before compareTo getDate readObject setHours getCalendarSystem equals)
person noisesmith    schedule 30.08.2014
comment
Спасибо, очень красиво, но все еще многословно и без фильтрующей части (хотя, конечно, не сложно реализовать функциональность). Я изучу это. - person Andrea Richiardi; 30.08.2014
comment
Фильтрация может быть выполнена так же, как и для любых других собственных данных clojure. Например, вы можете сделать (->> (reflect/reflect (java.util.Date.)) :members (filter :return-type)), чтобы получить только методы, вы можете дополнительно фильтровать, чтобы удалить методы, которые возвращают или принимают определенные типы или количество аргументов... - person noisesmith; 30.08.2014

Взгляните на iroh.

> (.? String  #"^conta") ;; grep all fields/methods that start with conta
(#[contains :: (java.lang.String, java.lang.CharSequence) -> boolean])
> (.? String  #"^con" :name) ;; return just the name of the method/field
("concat" "contains" "contentEquals")
> (.? "string instance"  #"^con" :name) ;; works with instances also
("concat" "contains" "contentEquals")
> (.? "a string instance" :static :name :public :method) ; all public static methods
("copyValueOf" "format" "join" "valueOf")
> (.? "a string instance" #"^t" :instance :name :public :method) ;; all public instance methods that start with t
("toCharArray" "toLowerCase" "toString" "toUpperCase" "trim")
person DanLebrero    schedule 30.08.2014
comment
Вау, это то, что я искал! - person Andrea Richiardi; 30.08.2014
comment
Я разрываюсь между этим и другим, я хотел подождать, чтобы увидеть, сколько голосов получили оба. - person Andrea Richiardi; 04.09.2014