2020-06-02 10:01:56 +00:00
|
|
|
/// <reference types="@ccms/types/dist/typings/jdk" />
|
|
|
|
|
2019-09-07 04:23:15 +00:00
|
|
|
/**
|
|
|
|
* 反射工具类
|
2019-11-04 12:19:50 +00:00
|
|
|
* Created by MiaoWoo on 2017/2/9 0009.
|
2019-09-07 04:23:15 +00:00
|
|
|
*/
|
2020-06-02 10:01:56 +00:00
|
|
|
const JavaClass = Java.type('java.lang.Class')
|
2019-09-27 10:40:35 +00:00
|
|
|
const JavaObject = Java.type('java.lang.Object')
|
2020-06-02 10:01:56 +00:00
|
|
|
const NoSuchFieldException = Java.type('java.lang.NoSuchFieldException')
|
|
|
|
const methodCache = []
|
2019-09-07 04:23:15 +00:00
|
|
|
|
|
|
|
class Reflect {
|
2020-06-02 10:01:56 +00:00
|
|
|
private obj: java.lang.Object
|
|
|
|
private class: java.lang.Class
|
2019-09-07 04:23:15 +00:00
|
|
|
|
|
|
|
constructor(obj: any) {
|
2019-11-04 12:19:50 +00:00
|
|
|
// if (obj === undefined || obj === null) { throw Error(`reflect object can't be ${obj}!`) }
|
2019-09-07 04:23:15 +00:00
|
|
|
if (obj instanceof JavaClass) {
|
2020-06-02 10:01:56 +00:00
|
|
|
this.obj = null
|
|
|
|
this.class = obj
|
2019-09-07 04:23:15 +00:00
|
|
|
} else {
|
2020-06-02 10:01:56 +00:00
|
|
|
this.obj = obj
|
2019-09-21 07:06:17 +00:00
|
|
|
if (obj !== null && obj !== undefined && obj.class) {
|
2020-06-02 10:01:56 +00:00
|
|
|
this.class = obj.class
|
2019-09-21 07:06:17 +00:00
|
|
|
}
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-02 10:01:56 +00:00
|
|
|
method(name: string, ...args: any[]) {
|
|
|
|
return declaredMethod(this.class, name, args)
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
methods() {
|
2020-06-02 10:01:56 +00:00
|
|
|
return Java.from(declaredMethods(this.class))
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
2020-06-02 10:01:56 +00:00
|
|
|
field(name: string | java.lang.String): Reflect {
|
2019-09-07 04:23:15 +00:00
|
|
|
try {
|
|
|
|
// Try getting a public field
|
2020-06-02 10:01:56 +00:00
|
|
|
let field = this.class.getField(name)
|
|
|
|
return on(field.get(this.obj))
|
2019-09-07 04:23:15 +00:00
|
|
|
} catch (ex) {
|
|
|
|
// Try again, getting a non-public field
|
2020-06-02 10:01:56 +00:00
|
|
|
return on(accessible(declaredField(this.class, name)).get(this.obj))
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
2020-06-02 10:01:56 +00:00
|
|
|
}
|
2019-09-07 04:23:15 +00:00
|
|
|
|
2020-06-02 10:01:56 +00:00
|
|
|
fields(declared = false): java.lang.reflect.Field[] {
|
|
|
|
return Java.from(declared ? this.class.getDeclaredFields() : this.class.getFields())
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
2019-09-21 07:06:17 +00:00
|
|
|
values(declared = false) {
|
2020-06-02 10:01:56 +00:00
|
|
|
return this.fields(declared).reduce((cache, field) => { return cache[field.getName()] = this.field(field.getName()).get() }, {}) as any
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
2020-06-02 10:01:56 +00:00
|
|
|
call(...args: any[]): Reflect {
|
|
|
|
let params = args.slice(1)
|
|
|
|
let method = accessible(declaredMethod(this.class, args[0], ...types(params)))
|
|
|
|
let result = method.invoke(this.get(), params)
|
|
|
|
return result && on(result)
|
|
|
|
}
|
2019-09-07 04:23:15 +00:00
|
|
|
|
2020-06-02 10:01:56 +00:00
|
|
|
get(): any
|
|
|
|
get(index: number, declared?: boolean): Reflect
|
|
|
|
get(prop: string): Reflect
|
|
|
|
get(param?: string | number, declared: boolean = true): Reflect | any {
|
|
|
|
if (param == undefined || param == null) return this.obj
|
|
|
|
if (typeof param == "number") {
|
|
|
|
return on(accessible(this.fields(declared)[param]).get(this.obj))
|
|
|
|
}
|
|
|
|
if (typeof param == "string") {
|
|
|
|
return this.field(param)
|
|
|
|
}
|
|
|
|
}
|
2019-09-07 04:23:15 +00:00
|
|
|
|
2020-06-02 10:01:56 +00:00
|
|
|
set(name: any, value: any): Reflect {
|
|
|
|
accessible(declaredField(this.class, name)).set(this.obj, value)
|
|
|
|
return this
|
|
|
|
}
|
2019-09-07 04:23:15 +00:00
|
|
|
|
2019-09-21 07:06:17 +00:00
|
|
|
create(...args): Reflect {
|
2020-06-02 10:01:56 +00:00
|
|
|
return on(declaredConstructor(this.class, args).newInstance(args))
|
|
|
|
}
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get an array of types for an array of objects
|
|
|
|
*/
|
2020-06-02 10:01:56 +00:00
|
|
|
function types(values: any[], def?: any) {
|
2019-09-07 04:23:15 +00:00
|
|
|
if (values === null) {
|
2020-06-02 10:01:56 +00:00
|
|
|
return []
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
2020-06-02 10:01:56 +00:00
|
|
|
let result: java.lang.Class[] = []
|
|
|
|
values.forEach(t => result.push((t || def) ? JavaObject.class : t instanceof JavaClass ? t : t.class))
|
|
|
|
return result
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
2020-06-02 10:01:56 +00:00
|
|
|
function accessible<T extends java.lang.reflect.AccessibleObject>(accessible: T): T {
|
2019-09-07 04:23:15 +00:00
|
|
|
if (accessible === null) {
|
2020-06-02 10:01:56 +00:00
|
|
|
return null
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
if (!accessible.isAccessible()) {
|
2020-06-02 10:01:56 +00:00
|
|
|
accessible.setAccessible(true)
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
2020-06-02 10:01:56 +00:00
|
|
|
return accessible
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function declaredConstructor(clazz, param) {
|
2020-06-02 10:01:56 +00:00
|
|
|
let constructor
|
2019-09-07 04:23:15 +00:00
|
|
|
try {
|
2020-06-02 10:01:56 +00:00
|
|
|
constructor = clazz.getDeclaredConstructor(types(param))
|
2019-09-07 04:23:15 +00:00
|
|
|
} catch (ex) {
|
|
|
|
try {
|
2020-06-02 10:01:56 +00:00
|
|
|
constructor = clazz.getDeclaredConstructor(types(param, true))
|
2019-09-07 04:23:15 +00:00
|
|
|
} catch (ex) {
|
2020-06-02 10:01:56 +00:00
|
|
|
constructor = clazz.getDeclaredConstructors()[0]
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-02 10:01:56 +00:00
|
|
|
return accessible(constructor)
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
2020-06-02 10:01:56 +00:00
|
|
|
function declaredField(clazz: java.lang.Class, name: string | java.lang.String) {
|
2019-11-04 12:19:50 +00:00
|
|
|
if (!clazz) { throw Error(`target class can't be ${clazz}!`) }
|
2020-06-02 10:01:56 +00:00
|
|
|
let target = clazz
|
|
|
|
let field = null
|
2019-09-07 04:23:15 +00:00
|
|
|
// noinspection JSUnresolvedVariable
|
2019-11-04 12:19:50 +00:00
|
|
|
while (target !== JavaObject.class) {
|
2019-09-07 04:23:15 +00:00
|
|
|
try {
|
2020-06-02 10:01:56 +00:00
|
|
|
field = target.getDeclaredField(name)
|
|
|
|
if (field !== null) { break }
|
2019-09-07 04:23:15 +00:00
|
|
|
} catch (e) {
|
2020-06-02 10:01:56 +00:00
|
|
|
if (target === undefined) { break }
|
|
|
|
target = target.getSuperclass()
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (field === null) {
|
2020-06-02 10:01:56 +00:00
|
|
|
throw new NoSuchFieldException(name + " is not found in " + clazz.getName())
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
2020-06-02 10:01:56 +00:00
|
|
|
return field
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
2020-06-02 10:01:56 +00:00
|
|
|
function declaredMethod(clazz: java.lang.Class, name: string, ...clazzs: any[]): java.lang.reflect.Method {
|
|
|
|
let key = clazz.getName() + '.' + name + ':' + (clazzs || []).join(':')
|
2019-09-07 04:23:15 +00:00
|
|
|
if (!methodCache[key]) {
|
|
|
|
try {
|
2020-06-02 10:01:56 +00:00
|
|
|
methodCache[key] = clazz.getMethod(name, clazzs as any)
|
2019-09-07 04:23:15 +00:00
|
|
|
} catch (ex) {
|
2019-09-21 07:06:17 +00:00
|
|
|
try {
|
2020-06-02 10:01:56 +00:00
|
|
|
methodCache[key] = clazz.getDeclaredMethod(name, clazzs as any)
|
2019-09-21 07:06:17 +00:00
|
|
|
} catch (ex) {
|
|
|
|
for (const m of Java.from(declaredMethods(clazz))) {
|
|
|
|
if (m.name == name) {
|
2020-06-02 10:01:56 +00:00
|
|
|
methodCache[key] = m
|
|
|
|
break
|
2019-09-21 07:06:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-02 10:01:56 +00:00
|
|
|
return methodCache[key]
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function declaredMethods(clazz) {
|
2020-06-02 10:01:56 +00:00
|
|
|
return clazz.declaredMethods
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
2020-06-02 10:01:56 +00:00
|
|
|
let classMethodsCache: any[] = []
|
2019-09-07 04:23:15 +00:00
|
|
|
|
|
|
|
function mapToObject(javaObj) {
|
|
|
|
if (!javaObj || !javaObj.class) { throw new TypeError(`参数 ${javaObj} 不是一个Java对象!`) }
|
2020-06-02 10:01:56 +00:00
|
|
|
let target = {}
|
|
|
|
getJavaObjectMethods(javaObj).forEach(t => mapMethod(target, javaObj, t))
|
|
|
|
return target
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function getJavaObjectMethods(javaObj) {
|
2020-06-02 10:01:56 +00:00
|
|
|
let className = javaObj.class.name
|
2019-09-07 04:23:15 +00:00
|
|
|
if (!classMethodsCache[className]) {
|
2020-06-02 10:01:56 +00:00
|
|
|
let names: any[] = []
|
|
|
|
let methods = javaObj.class.methods
|
2019-09-27 10:40:35 +00:00
|
|
|
for (let i in methods) {
|
2020-06-02 10:01:56 +00:00
|
|
|
names.push(methods[i].name)
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
2020-06-02 10:01:56 +00:00
|
|
|
classMethodsCache[className] = names
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
2020-06-02 10:01:56 +00:00
|
|
|
return classMethodsCache[className]
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function mapMethod(target, source, name) {
|
|
|
|
target[name] = function __SimpleDynamicMethod__(...args) {
|
|
|
|
if (args.length > 0) {
|
2020-06-02 10:01:56 +00:00
|
|
|
return source[name](args)
|
2019-09-07 04:23:15 +00:00
|
|
|
} else {
|
2020-06-02 10:01:56 +00:00
|
|
|
return source[name]()
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
2020-06-02 10:01:56 +00:00
|
|
|
}
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function on(obj) {
|
2019-09-21 07:06:17 +00:00
|
|
|
// if (!obj || !obj.class) { throw new TypeError(`参数 ${obj} 不是一个Java对象!`) }
|
2020-06-02 10:01:56 +00:00
|
|
|
return new Reflect(obj)
|
2019-09-07 04:23:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export = {
|
|
|
|
on,
|
|
|
|
accessible,
|
|
|
|
declaredMethods,
|
|
|
|
mapToObject
|
2020-04-01 03:08:15 +00:00
|
|
|
}
|