com.google.gwt.reflect.shared.JsMemberPool Maven / Gradle / Ivy
The newest version!
package com.google.gwt.reflect.shared;
import com.google.gwt.core.client.JavaScriptObject;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public final class JsMemberPool extends JavaScriptObject {
public static native int constId(Class cls)
/*-{
[email protected]::getName()(); // ensures constId is initialized
return [email protected]::constId;
}-*/;
public static native JsMemberPool createMemberPool(Class type)
/*-{
return {
$:type,
_:{},// array classes
a:{},// annotations
c:{},// constructors
f:{},// fields
i:{},// interfaces
m:{},// methods
t:{},// inner types
};
}-*/;
public static JsMemberPool getMembers(final Class cls) {
final int constId = constId(cls);
JsMemberPool members = findMembers(constId);
if (members == null) {
members = createMemberPool(cls);
setMembers(constId, members);
}
return members;
}
@SuppressWarnings("rawtypes")
static void addConstructor(final Class cls, final Constructor c) {
final JsMemberPool pool = getMembers(cls);
pool.addConstructor(c);
}
static void addField(final Class cls, final Field f) {
final JsMemberPool pool = getMembers(cls);
pool.addField(f);
}
static void addMethod(final Class cls, final Method m) {
final JsMemberPool pool = getMembers(cls);
pool.addMethod(m);
}
static void addAnnotation(final Class cls, final Annotation a, final boolean declared) {
final JsMemberPool pool = getMembers(cls);
pool.addAnnotation(a, declared);
}
static native int getSeedId(Class cls)
/*-{
return [email protected]::typeId;
}-*/;
static String getSignature(final Class ... signature) {
final StringBuilder key = new StringBuilder();
for (int i = 0; i < signature.length; i++) {
key.append('_');
key.append(constId(signature[i]));
}
return key.toString();
}
private static Annotation[] annoArray() {return new Annotation[0];}
private static Class[] classArray() {return new Class[0];}
@SuppressWarnings("unchecked")
private static Constructor[] constructorArray() {return new Constructor[0];}
private static Field[] fieldArray() {return new Field[0];}
@SuppressWarnings("rawtypes")
private static native void fillConstructors(JsMemberPool pool, Constructor[] array)
/*-{
for (var i in pool.c)
if (pool.c.hasOwnProperty(i))
array[array.length] = pool.c[i];
}-*/;
private static native void fillFields(JsMemberPool pool, Field[] array)
/*-{
for (var i in pool.f)
if (pool.f.hasOwnProperty(i))
array[array.length] = pool.f[i];
}-*/;
private static native void fillMethods(JsMemberPool pool, Method[] array)
/*-{
for (var i in pool.m)
if (pool.m.hasOwnProperty(i))
array[array.length] = pool.m[i];
}-*/;
private static native Constructor findConstructor(JsMemberPool pool, String id)
/*-{
return pool.c.hasOwnProperty(id) && pool.c[id];
}-*/;
private static native Field findField(JsMemberPool pool, String id)
/*-{
return pool.f.hasOwnProperty(id) && pool.f[id];
}-*/;
private static native JsMemberPool findMembers(int constId)
/*-{
return $wnd.GwtReflect.$$[constId];
}-*/;
private static native Method findMethod(JsMemberPool pool, String id)
/*-{
return pool.m.hasOwnProperty(id) && pool.m[id];
}-*/;
private static native boolean isUnique(JavaScriptObject set, String key)
/*-{
return set[key] ? false : (set[key] = true);
}-*/;
private static Method[] methodArray() {return new Method[0];}
private static native void setMembers(int constId, JsMemberPool members)
/*-{
$wnd.GwtReflect.$$[constId]=members;
}-*/;
protected JsMemberPool() {}
public final void addAnnotation(final Annotation a, final boolean declared) {
addAnnotation(a.annotationType().getName(), a, declared);
}
@SuppressWarnings("rawtypes")
public final void addConstructor(final Constructor c) {
addConstructor(getSignature(c.getParameterTypes()), c);
}
public final void addField(final Field f) {
addField(f.getName(), f);
}
public final void addMethod(final Method m) {
final String name = m.getName()+getSignature(m.getParameterTypes());
addMethod(name, m);
}
public final native A getAnnotation(Class annoCls)
/*-{
return this.a[[email protected]::getName()()];
}-*/;
public final native Annotation[] getAnnotations()
/*-{
var array = @com.google.gwt.reflect.shared.JsMemberPool::annoArray()();
for (var i in this.a) {
if (this.a.hasOwnProperty(i))
array.push(this.a[i]);
}
return array;
}-*/;
public final Class[] getClasses() {
return getType().getClasses();
}
@SuppressWarnings({"rawtypes", "unchecked"})
public final Constructor getConstructor(final Class ... params) throws NoSuchMethodException {
final String id = getSignature(params);
JsMemberPool pool = this;
final Constructor method = findConstructor(pool, id);
if (method == null) {
pool = pool.getSuperclass();
} else if (Modifier.isPublic(method.getModifiers())){
return method;
}
throw new NoSuchMethodException("Could not find public constructor "+getType().getSimpleName()+
"("+ReflectUtil.joinClasses(",", params)+")");
}
@SuppressWarnings({"rawtypes", "unchecked"})
public final Constructor[] getConstructors() {
final Constructor[] ctors = constructorArray();
final JsMemberPool pool = this;
final JavaScriptObject set = JavaScriptObject.createObject();
for (final Constructor declared : pool.getDeclaredConstructors()) {
if (Modifier.isPublic(declared.getModifiers()) &&
isUnique(set, getSignature(declared.getParameterTypes()))) {
// javascript actually likes this; preallocating arrays doesn't save time
ctors[ctors.length] = declared;// gwt-dev must never call this.
}
}
return ctors;
}
public final native A getDeclaredAnnotation(Class annoCls)
/*-{
var anno = this.a[[email protected]::getName()()];
return anno && anno.declared && anno || null;
}-*/;
public final native Annotation[] getDeclaredAnnotations()
/*-{
var array = @com.google.gwt.reflect.shared.JsMemberPool::annoArray()();
for (var i in this.a) {
if (this.a.hasOwnProperty(i) && this.a[i].declared)
array.push(this.a[i]);
}
return array;
}-*/;
public final Constructor getDeclaredConstructor(final Class ... params) throws NoSuchMethodException {
final String id = getSignature(params);
final Constructor ctor = findConstructor(this, id);
if (ctor != null) {
return ctor;
}
throw new NoSuchMethodException("Could not find declared constructor "+getType().getSimpleName()+
"("+ReflectUtil.joinClasses(",", params)+") in "+getType());
}
public final Constructor[] getDeclaredConstructors() {
final Constructor[] ctors = constructorArray();
fillConstructors(this, ctors);
return ctors;
}
public final Field getDeclaredField(final String name) throws NoSuchFieldException {
final Field field = findField(this, name);
if (field != null) {
return field;
}
throw new NoSuchFieldException("Could not find declared field "+name+" in "+getTypeName());
}
public final Field[] getDeclaredFields() {
final Field[] fields = fieldArray();
fillFields(this, fields);
return fields;
}
public final Method getDeclaredMethod(final String name, final Class ... params) throws NoSuchMethodException {
final String id = name + getSignature(params);
final Method method = findMethod(this, id);
if (method != null) {
return method;
}
throw new NoSuchMethodException("Could not find declared method "+name+
"("+ReflectUtil.joinClasses(",", params)+") in "+getType());
}
public final Method[] getDeclaredMethods() {
final Method[] methods = methodArray();
fillMethods(this, methods);
return methods;
}
public final Field getField(final String name) throws NoSuchFieldException {
JsMemberPool pool = this;
while (pool != null) {
final Field field = findField(pool, name);
if (field == null) {
pool = pool.getSuperclass();
} else if (Modifier.isPublic(field.getModifiers())){
return field;
}
else {
break; // super classes can't match if the subclass has a lower privacy method
}
}
throw new NoSuchFieldException("Could not find public field "+name+ " in "+getTypeName());
}
public final Field[] getFields() {
final Field[] fields = fieldArray();
JsMemberPool pool = this;
final JavaScriptObject set = JavaScriptObject.createObject();
while (pool != null) {
for (final Field declared : pool.getDeclaredFields()) {
if (Modifier.isPublic(declared.getModifiers()) &&
isUnique(set, declared.getName())) {
fields[fields.length] = declared;
}
}
pool = pool.getSuperclass();
}
return fields;
}
public final Class[] getInterfaces() {
return getType().getInterfaces();
}
public final Method getMethod(final String name, final Class ... params) throws NoSuchMethodException {
final String id = name + getSignature(params);
JsMemberPool pool = this;
while (pool != null) {
final Method method = findMethod(pool, id);
if (method == null) {
pool = pool.getSuperclass();
} else if (Modifier.isPublic(method.getModifiers())){
return method;
}
else {
break; // super classes can't match if the subclass has a lower privacy method
}
}
throw new NoSuchMethodException("Could not find public method "+name+
"("+ReflectUtil.joinClasses(",", params)+") in "+getType());
}
@SuppressWarnings("rawtypes")
public final Method[] getMethods() {
final Method[] methods = methodArray();
JsMemberPool pool = this;
final JavaScriptObject set = JavaScriptObject.createObject();
final JsMemberPool[] all = new JsMemberPool[]{};
if (pool.getType().isInterface()) {
all[all.length] = this;
for (final Class iface : pool.getInterfaces()) {
all[all.length] = getMembers(iface);
}
} else {
while(pool != null) {
all[all.length] = pool;
pool = pool.getSuperclass();
}
}
for(final JsMemberPool cls : all) {
for (final Method declared : cls.getDeclaredMethods()) {
if (Modifier.isPublic(declared.getModifiers()) &&
isUnique(set, declared.getName()+getSignature(declared.getParameterTypes()))) {
// javascript actually likes this; preallocating arrays doesn't save time
methods[methods.length] = declared;
}
}
}
return methods;
}
public final JsMemberPool getSuperclass() {
final Class superClass = getType().getSuperclass();
assert superClass != getType();
return superClass == null ? null : getMembers(superClass);
}
public final native Class getType()
/*-{
return this.$;
}-*/;
public final native String getTypeName()
/*-{
try {
return [email protected]::getName()();
}catch(e) {
return "";
}
}-*/;
private final native void addAnnotation(String key, Annotation a, boolean declared)
/*-{
this.a[key] = a;
if (declared) {
a.declared = true;
}
}-*/;
@SuppressWarnings("rawtypes")
private final native void addConstructor(String key, Constructor c)
/*-{
this.c[key] = c;
}-*/;
private final native void addField(String key, Field f)
/*-{
this.f[key] = f;
}-*/;
private final native void addMethod(String key, Method m)
/*-{
this.m[key] = m;
}-*/;
}