在GWT中,Java的很多机制都是不支持的,比如:
不支持类的动态加载
不支持Java的反射机制
不支持标准Java序列化
不支持WEB模式下的Java对象清理
不支持strictfp关键字,要避免在客户端代码中进行精确精度的计算
......
如果我们想让GWT支持反射机制,可以使用GWT Reflection框架扩展实现。以下简单介绍其实现步骤:
1、到http://gwtreflection.sourceforge.net/网站下载GWT Reflection框架文件,将ant.jar、antlr-2.7.7.jar、commons-cli-1.0.jar、gwtr-core.jar、gwtr-emule.jar、stringtemplate.jar这些jar文件拷贝到工程的lib目录下。
2、修改gwtr-emule.jar的JavaToJSArrayUtil.java源文件,将包含long和Long的代码段去掉,重新编译后覆盖gwtr-emule.jar里面对应的class文件和java文件。
如果不这样做的话,在启动工程时会抛出以下异常信息:
[ERROR] Errors in 'jar:file:/E:/gwtext/web/WEB-INF/lib/gwtr-emule.jar!/pl/rmalinowski/gwtreflect/client/utils/JavaToJSArrayUtil.java'
[ERROR] Line 90: Parameter 'value': type 'long' is not safe to access in JSNI code
那是因为:
在GWT1.5中,现在Java long类型可以正确的工作,允许你给一个64位的整数一个完全适当的范围。然而,由于JavaScript缺少真正的64位整型,long 被视为一对32位整型,使用JavaScript的标准数学符号不能很好的工作。
如果你给JSNI传入一个long型值,GWT1.5编译器会产生错误,此时在你不完全需要long范围的地方,推荐方式是把类型改为double 。事实上,如果你使用long返回System.currentTimeMillis(),我们推荐你使用新建的Duration类来作为替换方式。对于JSNI 方法来说,它使用派生对象(opaque objects 不能进行任何数学计算)来处理long 值,你可以使用UnsafeNativeLong annotation 来欺瞒编译器。但是我们强烈建议您避免这种方式,因为很容易忘掉JSNI方法中该值是一个非数值型的。
修改pl.rmalinowski.gwtreflect.tool.AntAttributeStrategy类的源码为:
public class AntAttributeStrategy implements ClassFindingStrategy { public boolean isClassReflectable(Class clazz) { Class[] classes = clazz.getInterfaces(); if(classes!=null && classes.length>0){ for(int i=0;i<classes.length;i++){ if(classes[i].getSimpleName().equals("Reflectable")){ return true; } } } return false; } }
,这样,只有实现了Reflectable接口的类才会生成其反射代理类。
3、如果要让一个类支持通过反射机制进行实例化,该类必须实现GWT Reflection框架中的Reflectable接口,其范例如下:
public class TicketRecievePanel extends BasePanel implements Reflectable{ public TicketRecievePanel(){ setTitle("票证领取:TicketRecievePanel"); setClosable(true); } @Override public void onLoad() { MessageBox.setMinWidth(150); MessageBox.alert(this.getTitle()); } }
通过反射实例化一个类的方法是:调用GWT Reflection框架中的Class类的forName方法。其范例如下:
String panelName = "com.cjm.client.ticket.TicketRecievePanel"; BasePanel panel = (BasePanel)pl.rmalinowski.gwtreflect.client.reflect.Class.forName(panelName).newInstance();
4、生成类的反射代理类和反射代理类的注册器类
一个类在能够支持通过反射进行实例化之前,必须要用GWT Reflection框架提供的ant命令 GWTReflect 来生成该类的反射代理类和反射代理类的注册器类,然后调用注册器类的registerAll方法注册反射代理类之后,才能使反射机制生效。
注册反射代理类的范例代码:
ClassRegistrator.registerAll();
先注册反射代理类,再调用Class类的forName方法。
在调用ant命令 GWTReflect 生成类的反射代理类之前,必须先将类打包成一个jar文件
ant任务定义文件源码如下:
<?xml version="1.0" encoding="UTF-8"?> <!-- 主要功能: 1、清除之前生成的文件 2、将类打包成jar文件 3、生成反射代理类 4、将反射代理类复制到java源码目录 --> <project default="main" basedir="."> <property name="path.webinf" value="${basedir}/web/WEB-INF"/> <path id="lib.path"> <fileset dir="${path.webinf}/lib" includes="*.jar"/> </path> <!-- 将类打包成jar文件 --> <target name="buildJar"> <jar destfile="ticket.jar"> <fileset dir="${basedir}/build/classes/"> <exclude name="com/cjm/client/gwtr/**"/> <!-- 排除反射代理类 --> <exclude name="com/cjm/public/**"/> <exclude name="com/cjm/server"/> </fileset> </jar> </target> <target name="clean"> <delete file="${basedir}/ticket.jar"/> <!-- 删除java源码目录中的反射代理类 --> <delete dir="${basedir}/src/com/cjm/client/gwtr"/> <delete dir="${basedir}/gwtr_src"/> <mkdir dir="${basedir}/gwtr_src"/> </target> <!-- 用于生成反射代理类的task --> <taskdef name="gwtreflect" classname="pl.rmalinowski.gwtreflect.ant.GWTReflect" classpathref="lib.path" /> <!-- outdir:生成类的输出目录 source:需要生成反射代理类的目标类的jar文件及其依赖jar文件 packagein:目标类的包路径 packageout:反射代理类的包路径 templatepath:模板所在路径 --> <target name="main" depends="clean,buildJar"> <gwtreflect outdir="${basedir}/gwtr_src" source="${basedir}/ticket.jar;${path.webinf}/lib/gwtext.jar;${path.webinf}/lib/gwt-user.jar;${path.webinf}/lib/gwtr-core.jar;${path.webinf}/lib/gwtr-emule.jar" packagein="com.cjm.client" packageout="com.cjm.client.gwtr" templatepath="${basedir}/st"> </gwtreflect> <!-- 将反射代理类复制到java源码目录 --> <copy todir="${basedir}/src"> <fileset dir="${basedir}/gwtr_src"/> </copy> <delete dir="${basedir}/gwtr_src"/> </target> </project>
对于范例中的TicketRecievePanel类,将生成以下两个Java类:
TicketRecievePanel__GWTR 反射代理类
ClassRegistrator 反射代理类的注册类。一个包下有一个注册类
5、需要在模块配置文件增加以下信息:
<inherits name="pl.rmalinowski.gwtreflect.GWTReflect"/>