1+ package io .github .freehij .loader .util ;
2+
3+ import java .lang .reflect .*;
4+ import java .util .ArrayList ;
5+ import java .util .List ;
6+
7+ public class Reflector {
8+ private final Class <?> clazz ;
9+ private final Object object ;
10+
11+ public Reflector (Class <?> clazz , Object object ) {
12+ this .clazz = clazz ;
13+ this .object = object ;
14+ }
15+
16+ public Object get () {
17+ return object ;
18+ }
19+
20+ public int getInt () {
21+ return (int ) object ;
22+ }
23+
24+ public long getLong () {
25+ return (long ) object ;
26+ }
27+
28+ public float getFloat () {
29+ return (float ) object ;
30+ }
31+
32+ public double getDouble () {
33+ return (double ) object ;
34+ }
35+
36+ public byte getByte () {
37+ return (byte ) object ;
38+ }
39+
40+ public char getChar () {
41+ return (char ) object ;
42+ }
43+
44+ public short getShort () {
45+ return (short ) object ;
46+ }
47+
48+ public boolean getBoolean () {
49+ return (boolean ) object ;
50+ }
51+
52+ public String getString () {
53+ return (String ) object ;
54+ }
55+
56+ public Class <?> getActualClass () {
57+ return clazz ;
58+ }
59+
60+ public Reflector getField (String fieldName ) {
61+ //if this.object is null get a static variable else from an instanced class
62+ //returns Reflector with field value
63+ //throws Exception if field is not static and no object instance is presented
64+ //throws RuntimeException when other errors occur
65+ try {
66+ Field field = this .clazz .getDeclaredField (fieldName );
67+ field .setAccessible (true );
68+
69+ Object value ;
70+ if (this .object == null ) {
71+ if (!Modifier .isStatic (field .getModifiers ())) {
72+ throw new Exception ("Not a static field: " + fieldName );
73+ }
74+ value = field .get (null );
75+ } else {
76+ value = field .get (this .object );
77+ }
78+
79+ return new Reflector (field .getType (), value );
80+ } catch (Exception e ) {
81+ throw new RuntimeException ("Failed to get field: " + fieldName , e );
82+ }
83+ }
84+
85+ public void setField (String fieldName , Object value ) {
86+ //if this.object is null set a static variable else in an instanced class
87+ //throws Exception if field is not static and no object instance is presented
88+ //throws RuntimeException when other errors occur
89+ try {
90+ Field field = clazz .getDeclaredField (fieldName );
91+ field .setAccessible (true );
92+
93+ if (object == null ) {
94+ if (!Modifier .isStatic (field .getModifiers ())) {
95+ throw new Exception ("Not a static field: " + fieldName );
96+ }
97+ field .set (null , value );
98+ } else {
99+ field .set (object , value );
100+ }
101+ } catch (Exception e ) {
102+ throw new RuntimeException ("Failed to set field: " + fieldName , e );
103+ }
104+ }
105+
106+ public Reflector invoke (String methodName , String descriptor , Object ... args ) {
107+ //calculate the paramTypes and call invokeRaw
108+ return this .invokeRaw (methodName , parseDescriptor (descriptor ), args );
109+ }
110+
111+ public Reflector invokeRaw (String methodName , Class <?>[] paramTypes , Object ... args ) {
112+ //should call the method using paramTypes and args
113+ //if this.object is null call method as static else call from instanced class
114+ //returns Reflector with methods return
115+ //throws Exception if method is not static and no object instance is presented
116+ //throws RuntimeException when other errors occur
117+ try {
118+ Method method = clazz .getDeclaredMethod (methodName , paramTypes );
119+ method .setAccessible (true );
120+
121+ Object result ;
122+ if (object == null ) {
123+ if (!Modifier .isStatic (method .getModifiers ())) {
124+ throw new Exception ("Not a static method: " + methodName );
125+ }
126+ result = method .invoke (null , args );
127+ } else {
128+ result = method .invoke (object , args );
129+ }
130+
131+ return new Reflector (method .getReturnType (), result );
132+ } catch (Exception e ) {
133+ throw new RuntimeException ("Failed to invoke method: " + methodName , e );
134+ }
135+ }
136+
137+ public Reflector newInstance (String descriptor , Object ... args ) {
138+ //should calculate the paramTypes and call newInstanceRaw
139+ return newInstanceRaw (parseDescriptor (descriptor ), args );
140+ }
141+
142+ public Reflector newInstanceRaw (Class <?>[] paramTypes , Object ... args ) {
143+ //create new instance of this.clazz
144+ //return Reflector with newly created class instance
145+ //throws RuntimeException when errors occur
146+ try {
147+ Constructor <?> constructor = clazz .getDeclaredConstructor (paramTypes );
148+ constructor .setAccessible (true );
149+ Object instance = constructor .newInstance (args );
150+ return new Reflector (clazz , instance );
151+ } catch (Exception e ) {
152+ throw new RuntimeException ("Failed to create new instance" , e );
153+ }
154+ }
155+
156+ static Class <?>[] parseDescriptor (String descriptor ) {
157+ List <Class <?>> classes = new ArrayList <>();
158+ boolean isArray = false ;
159+ for (int i = 0 ; i < descriptor .length (); i ++) {
160+ switch (descriptor .charAt (i )) {
161+ case '[' :
162+ isArray = true ;
163+ break ;
164+ case 'Z' :
165+ classes .add (isArray ? boolean [].class : boolean .class );
166+ isArray = false ;
167+ break ;
168+ case 'B' :
169+ classes .add (isArray ? byte [].class : byte .class );
170+ isArray = false ;
171+ break ;
172+ case 'C' :
173+ classes .add (isArray ? char [].class : char .class );
174+ isArray = false ;
175+ break ;
176+ case 'S' :
177+ classes .add (isArray ? short [].class : short .class );
178+ isArray = false ;
179+ break ;
180+ case 'I' :
181+ classes .add (isArray ? int [].class : int .class );
182+ isArray = false ;
183+ break ;
184+ case 'J' :
185+ classes .add (isArray ? long [].class : long .class );
186+ isArray = false ;
187+ break ;
188+ case 'F' :
189+ classes .add (isArray ? float [].class : float .class );
190+ isArray = false ;
191+ break ;
192+ case 'D' :
193+ classes .add (isArray ? double [].class : double .class );
194+ isArray = false ;
195+ break ;
196+ case 'L' :
197+ StringBuilder className = new StringBuilder ();
198+ while (i + 1 < descriptor .length () && descriptor .charAt (i + 1 ) != ';' ) {
199+ className .append (descriptor .charAt (i + 1 ));
200+ i ++;
201+ }
202+ String clsName = className .toString ().replace ("/" , "." );
203+ try {
204+ classes .add (isArray ? Array .newInstance (Class .forName (clsName ), 0 ).getClass () : Class .forName (clsName ));
205+ } catch (ClassNotFoundException e ) {
206+ throw new RuntimeException ("Failed to load class: " + clsName , e );
207+ }
208+ isArray = false ;
209+ break ;
210+ case ')' :
211+ return classes .toArray (new Class <?>[0 ]);
212+ }
213+ }
214+ return classes .toArray (new Class <?>[0 ]);
215+ }
216+ }
0 commit comments