-
Notifications
You must be signed in to change notification settings - Fork 8
/
reflect.clj
118 lines (107 loc) · 3.96 KB
/
reflect.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
(ns lambdaisland.witchcraft.reflect
(:require [lambdaisland.classpath :as licp])
(:import (org.reflections Reflections Store)
(org.reflections.util ConfigurationBuilder
ClasspathHelper
FilterBuilder)
(javassist.bytecode MethodInfo)
(java.lang.reflect Modifier)
(org.reflections.vfs Vfs Vfs$File)
(org.reflections.adapters MetadataAdapter)
(org.reflections.scanners Scanner
AbstractScanner
TypeElementsScanner
SubTypesScanner
MethodParameterScanner)))
(set! *warn-on-reflection* true)
(def packages
["org.bukkit"
"net.kyori"
#_"net.minecraft"
"co.aikar"
"com.destroystokyo"
"io.papermc"
"org.spigotmc"
"net.glowstone"])
(defn assoc-sig [m sig klassname]
(assoc! m sig ((fnil conj #{}) (get m sig) klassname)))
(defn classloaders []
;; shenanigans because paper's pluginclassloader hides what its parents
;; provide
(let [plugin-loader (when-let [instance-var (resolve 'lambdaisland.witchcraft.plugin/instance)]
(.getClassLoader (.getClass ^Object @@instance-var)))]
(cond-> [(licp/context-classloader)]
plugin-loader
(conj plugin-loader
(.getParent plugin-loader)))))
(defn reflect-config []
(let [config (ConfigurationBuilder.)
loaders (into-array ClassLoader (classloaders))]
(doseq [pkg packages]
(.addUrls config (ClasspathHelper/forPackage pkg loaders)))
config))
(defn load-reflections []
(let [config (reflect-config)
files (mapcat #(.getFiles (Vfs/fromURL %)) (.getUrls config))
adapt (.getMetadataAdapter config)]
(persistent!
(reduce
(fn [m ^Vfs$File file]
(if (.acceptsInput adapt (.getRelativePath file))
(let [klass (.getOrCreateClassObject adapt file)
klassname (.getClassName adapt klass)]
(if-not (some #(.startsWith klassname %) packages)
m
(reduce
(fn [m method]
(if (.isPublic adapt method)
(-> m
(assoc-sig
(str
(when (Modifier/isStatic (.getAccessFlags ^MethodInfo method))
"static ")
(.getMethodName adapt method)
"("
(apply str
(interpose ","
(.getParameterNames adapt method)))
")")
klassname)
(assoc-sig
(str
(when (Modifier/isStatic (.getAccessFlags ^MethodInfo method))
"static ")
(.getReturnTypeName adapt method)
" "
(.getMethodName adapt method)
"("
(apply str
(interpose ","
(.getParameterNames adapt method)))
")")
klassname))
m))
m
(.getMethods adapt klass))))
m))
(transient {})
files))))
(defonce reflections
(delay (load-reflections)))
(defmacro extend-signatures
{:style/indent [1 :form [1]]}
[protocol & sig-impl]
`(extend-protocol ~protocol
~@(as-> sig-impl $
(for [[sig impl] (partition 2 $)
klass (get @reflections sig)]
{:class (symbol klass)
:fntail impl})
(group-by :class $)
(for [[klass impls] $
form (cons klass (map :fntail impls))]
form))))
(comment
(filter #(.contains (key %) "Lore") @reflections)
(load-reflections)
)