如何在GWT中使用反射机制?

在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"/>

 

你可能感兴趣的:(JavaScript,框架,Web,ant,gwt)