`
wzucxd
  • 浏览: 25205 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

[用js写java jvm]1.js解析java bean中的属性和基本类型

 
阅读更多

前几天看到国外有报道说js实现了大部分的jvm功能,最近也一直在考虑如何用js实现一个jvm功能。

后来想了下,还是可行的,其实只是用js实现jvm规范,例如对于java来说有一个System.out,println("test");这样的语句一出现就会在控制台输出:"test"

这个语法对应javascript也就是

var System ={};

System.out={

println:function(val){

//实现具体的功能

alert(val);

}

}


如java中java.lang.String 也可以参照上术方式实现,api按此方式慢慢实现

那对于如何转换一个java bean对象也是今天所要讲的重点,不知道如果将一个java bean转换为javascript object的方法,那么即使实现了api也没有环境让java语言运行起来。

接着将介绍转换方法:

首先我们先来看一个简单的java bean和javascript object有什么区别

public class Test{
    private int a;

    public int getA(){
        reutrn a;    
    }
}
function Test{
    
}
Test.prototype.a = 0;
Test.prototype.getA = function(){
    return this.a;
}
看到这2种写法,应该能比较清楚的看出朝着这个方法转变就行。
好了,现在开始进行解析

解析过程:

1.类名的提取

根据java规范,我们知道一个类的命名必须是class name{...}这种方式,前面要有修饰符,内部类也是这种方式

可以写一个正则匹配这种内容,只需要匹配第一个出现{的字符串,提取里面的classname

或者采用正则(public|private|protected)?\s*class\s*\w+?{ 或者 class(.+?){ 匹配出所有符合规则的数据,将内部类名字也匹配出来

具体代码可参考Class.getName();

2.属性的提取

也可以采用正则方法处理,java成员变量的特点:修饰符(可有可无)+变量类型+成员名称+";"(注意后面还有一个;结束符)

和局部变量的区别在于有返回值类型,和method的区别在于没有(){...}代码片段

所以属性的提取可以采用正则

/(private|public)?\s+(void|int|float|boolean|double|String)[A-Za-z0-9|\s|_]+;

在处理属性的过程中,我们需要对变量类型做处理,如java中int类型的成员变量默认值是0等等。。。

于是我们定义一个于成员变量类型对应的var Type = {

"int":0,

"boolean":false

}

假设我们匹配到了"public int a;"这个字符串

接着我们就可以处理成这样了

classname.prototype.a =Type[int];


3.方法的提取(先介绍主函数main方法的处理)

method的提取相对比较麻烦点,需要考虑{}标签闭合的处理

main方法也是主入口函数,如果存在则会执行里面的内容,必须是public void static main(String[] args)...{....}这种方式,而且在一个类中只有一个,期中args是参数入口,对应arguments

转换成对应的js就是

classname.prototype.ininv = function(){....};

对于复杂方法的提取,这里暂时先不展开。


4.执行转换后代码

以Test.java为例

public class Test{
    public void static main(String[] args){
        System.out.println("test");
    }
}

转换成js后的var source = "function Test(){};"

source += "Test.prototype.initv = function(){System.out.println(\"test\")}";

然后<script>document.write(source)</script>,

这样就能在window["Test"]下拿到这个Test对象,执行他的方法了。

具体源码可以参考Class._creatInitV()

另外还需要模拟一个很重要的入口,Class.forname方法,实现这个方法可以帮助我们很好的寻找处理java类


源码:

<script>
/*
 * 扩展jtrim方法,使用方法有下面几种
 * trim()   去除字符串左右两端的空格 
 * trim("xyz")  去除字符串左右两端的字符xyz 
 * trim(/[0-9]/g)  去除字符串左右两端的数字 
 * trim(2)  去除字符串左端2个字符
 * trim(0,3)  去除字符串右端3个字符
 * trim(2,3)  去除字符串左端2个字符右端3个字符
 */
String.prototype.trim = function(){
    var _argument = arguments[0] == undefined ? " " : arguments[0];
    if(typeof(_argument) == "string"){
        if (_argument == " ") {
            return this.replace(/(^(\s|\u3000)*)|((\s|\u3000)*$)/g, "");
        } else {
            return this.replace(new RegExp("(^" + _argument + "*)|(" + _argument + "*$)", "g"), "");
        }
    }else if(typeof(_argument) == "object"){
        return this.replace(_argument, "");
    }else if(typeof(_argument) == "number"){
        if (arguments.length == 1) {
            return this.substring(arguments[0])
        } else if(typeof(arguments[1]) == "number") {
            return this.substring(arguments[0], this.length-arguments[1]);
        }
    }
    return this;
};
//对应java种的system类,这种类的功能只需要按下面这种格式逐个翻译成js class即可
var System = {}
System.out ={
		println:function(val){
			this.print(val + "\r\n");
		},
		print:function(val){
			val = val == undefined ? "undefined" : val;
			if(typeof(val) == "string"){
			    alert(val);
			}
		}
}
//js jvm对应的基础类型,目前先支持这4种基础类型
var Type = {
		"int" : 0,
		"boolean" : false,
		"float" : 0.0,
		"double" : 0.0,
		"String" : null,
		"void" : null,
}

//获取解析java对象核心的功能,相当于java中的class.forname获得一个对象
var Class = {
		source : "",
		//处理初始化对象
		javasource : "",
		forName:function(javasource){
			this.javasource = javasource;//记录javasource,分析过程中会需要原始数据
			var classname = this.getName();
			this.source += "function "+classname+"(){}";//类名解析,转换到js obj上的时候classname是创建jsobj的关键
			//this.source += classname+"prototype."+
			this.source += this._createInitV(classname);//主main方法识别创建
			this.source += this._createAttributes(classname);//创建属性
			//this.getDeclaredFields();
			this.source += this._createMethods(classname);//todo 创建方法
			return this;
		},
		//初始化函数的创建,检测是否存在public static void main方法
		_createInitV:function(classname){
			
		    var str = "";
			var initv = String.trim(this.javasource).match(/public static void main\(String\[\].+?\){(.+?)}/);
		    if(initv.length >= 1){
		    	str += classname+".prototype.initv=function(){";
		    	str += (initv.length == 2)? initv[1]:"";//init[1]是匹配后main方法内的数据
		    	str += "};";
		    }
			return str;
		},
		//创建对象属性
		//这个正则对方法内的变量申明不能很好识别
		//todo public void getXXX(){int xxx;}这里的int xxx;也会被识别,需要先处理method后再处理attribute
		//todo 还不支持abstract字段
		_createAttributes : function(classname){
			var value = "";
			var attrs = String.trim(this.javasource).match(/(private|public)?\s+(void|int|float|boolean|double|String)[A-Za-z0-9|\s|_]+;/g);
		    var attr="";
			for(var i=0,length=attrs.length;i<length;i++){
		    	attr = String.trim(attrs[i]);
		    	if(attr != ""){
		    		//先去除开头的public private protected,以及末尾的;符号
		    	    if(attr.indexOf("public") == 0){
		    	    	attr = attr.substring("public".length,attr.length-1).trim();
		    	    }else if(attr.indexOf("private") == 0){
		    	    	attr = attr.substring("private".length,attr.length-1).trim();
		    	    }else if(attr.indexOf("protected")){
		    	    	attr = attr.substring("protected".length,attr.length-1).trim();
		    	    }
		    	    
		    		//接着剩下的都是类型+名称的变量字符串了。。。
		    		//根据类型要赋一些初始值
		    		var typevalue = Type[attr.substring(0,attr.indexOf(" "))];//获取type对应的默认value
		    		var attrname = attr.substring(attr.indexOf(" ")).trim();//获取attribute name
		    		//开始组装js对应的属性
		    		value += classname + ".prototype."+ attrname;
		    		value += "=";
		    		value += typevalue;
		    		value += ";";
		    	}
		    }
			return value;
		},
		//为对象创建method
		//(private|public)?\s+(void|int|float|boolean|double|String)[A-Za-z0-9|\s]+\((void|int|float|boolean|double|String)?(.+)?\)\s+{\s+([\r|\n|\t])?.+\s+([\r|\n|\t])?}
		//理论上只需要转换public方法即可,private方法无法调用转换,转换后采用_methodname表示私有方法
		_createMethods : function(classname){
			var value = "";
			//处理public方法
			var methods = String.trim(this.javasource).match(/(public)?\s+(void|int|float|boolean|double|String)[A-Za-z0-9|\s]+\((void|int|float|boolean|double|String)?(.+)?\)\s+{\s+([\r|\n|\t])?.+\s+([\r|\n|\t])?}/ig);
			if(methods){
				for(var i=0,length = methods.length;i<length;i++){
					value = this.javaMethodTojsFunction(methods[i]);
				}
			}
			//处理private方法
			return "";
		},
		//java method转为js function
		//public int getXXX(){}   --> getXXX : function(){}
		//todo 如果不带修饰符的时候如何处理?目前当作public处理,也是符合java规范的
		_javaMethodTojsFunction : function(val){
			
			if(val.indexOf("public") == 0){
				val = val.substring("public".length).trim();//去掉开始的public,public在js中没有这种关键字,默认已经是public
			}
			val = val.substring(val.indexOf(" ")).trim();//去除type
			var methodname = val.substring(0,val.indexOf("(")).trim();//根据(符合决定方法名,因为method定义后面必须要有()
		    var functioncontent = val.substring(val.indexOf("(")).trim();//除方法名外,其他都是function内容
		    functioncontent = "function"+ functioncontent;//改变为function(){}    (){}这种之后在java中是执行代码片段,这种代码可以直接转换为js代码片段
		    
		},
		//解析return方法
		_returnCompile : function(val){
			
		},
		getDeclaredFields:function(){
			this.source += "Test.prototype = {";
			this.source += "initv:function(){";
			//initv逻辑解析-->检测入口,方法,字段等等
			//...
			//处理system.out.println method -->alert
			this.source += "alert(\"hello world\");";
			this.source += "}";
			this.source += "}";
		},
		//获取对象名字
		getName:function(){
			//类的名字可以根据 class name {匹配,找到第1个就是类名,
		    //如果有多个,那么后面的属于内部类
			var names = String.trim(this.javasource).match(/class(.+?){/g);
			var name = names[0].substring("class".length,names[0].length-1);
			return String.trim(name);
		}
}

function JVM(){
	
}
JVM.prototype ={
		compile:function(javasource){
			var obj = new Object();
			obj = Class.forName(javasource);
			//obj = eval(obj.source);
			///obj.initv();
			document.write("<script>"+obj.source+"<\/script>");//todo 需要改进为在自己的package下,引入namespaces后再扩展这部分
			return window[obj.getName()]; //classname还是比较好分析获取的
		}
}


var javasource = "public class Test { ";

javasource += "private int tmpa;";
javasource += "private boolean tmpb;";
javasource += "private float tmpc;";
javasource += "private double tmpd;";
javasource += "private String tmpe;";
javasource += "private Object tmpf;";

javasource += "public int getTmpa(){";
javasource += "    return tmpa;";
javasource += "}";

javasource += "public static void main(String[] args){";
javasource += "System.out.println(\"hello world\");";
javasource += "System.out.println(\"world is round\");";
javasource += "}";

javasource += "class Test2 {";
javasource += "private int tmpz;";	
javasource += "};"
javasource += "}";


//创建一个jsjvm
var jsjvm = new JVM();
//编译java源代码
var obj = jsjvm.compile(javasource);
//创建对象
var tes = new obj();
//调用方法,main方法转为init方法,改天写这个解析逻辑
tes.initv();
alert(tes.tmpb);
alert(tes.tmpe);




//alert("   123".trim())


//(public)?\s*(void|int|float|boolean|double|String)[A-Za-z0-9|\s]+\((void|int|float|boolean|double|String)?(.+)?\)\s*{\s*([\r|\n|\t])*.+\s*([\r|\n|\t])?*}


</script>


今天先介绍到这里,下周继续介绍如何处理成员方法和控制bean对象的加载卸载

如果没周写一篇这样贴代码的文章,然后后面再跟着http://ditu.alibaba.com,不知道又能赚多少外链。

Google   作者:陈旭东   email:wzucxd@gmail.com 2011.12.25

分享到:
评论

相关推荐

    Java 面试宝典

    1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? ...... 7 2、Java 有没有 goto? .......................................................................................................

    JAVA上百实例源码以及开源项目源代码

    在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天...

    JAVA上百实例源码以及开源项目

    在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天...

    java面试宝典

    203、编程用JAVA解析XML的方式. 49 204、EJB2.0有哪些内容?分别用在什么场合? EJB2.0和EJB1.1的区别? 51 205、EJB与JAVA BEAN的区别? 51 206、EJB的基本架构 51 207、MVC的各个部分都有那些技术来实现?如何实现? 52...

    Java面试宝典-经典

    给一个 Bean 的 message 属性, 字符串类型, 注入值为 "Hello" 的 XML 配置文件该怎么写? 125 19、Jdo是什么? 125 20、什么是spring的IOC AOP 126 21、STRUTS的工作流程! 126 22、spring 与EJB的区别!! 126 八. ...

    java面试题大全(2012版)

    给一个 Bean 的 message 属性, 字符串类型, 注入值为 "Hello" 的 XML 配置文件该怎么写? 125 19、Jdo是什么? 125 20、什么是spring的IOC AOP 126 21、STRUTS的工作流程! 126 22、spring 与EJB的区别!! 126 八. ...

    最新Java面试宝典pdf版

    给一个 Bean 的 message 属性, 字符串类型, 注入值为 "Hello" 的 XML 配置文件该怎么写? 125 19、Jdo是什么? 125 20、什么是spring的IOC AOP 126 21、STRUTS的工作流程! 126 22、spring 与EJB的区别!! 126 八. ...

    Java面试笔试资料大全

    给一个 Bean 的 message 属性, 字符串类型, 注入值为 "Hello" 的 XML 配置文件该怎么写? 125 19、Jdo是什么? 125 20、什么是spring的IOC AOP 126 21、STRUTS的工作流程! 126 22、spring 与EJB的区别!! 126 八. ...

    java面试宝典2012

    给一个 Bean 的 message 属性, 字符串类型, 注入值为 "Hello" 的 XML 配置文件该怎么写? 137 19、Jdo是什么? 137 20、什么是spring的IOC AOP 137 21、STRUTS的工作流程! 137 22、spring 与EJB的区别!! 137 八. ...

    JAVA面试宝典2010

    给一个 Bean 的 message 属性, 字符串类型, 注入值为 "Hello" 的 XML 配置文件该怎么写? 125 19、Jdo是什么? 125 20、什么是spring的IOC AOP 126 21、STRUTS的工作流程! 126 22、spring 与EJB的区别!! 126 八. ...

    Java面试宝典2012新版

    给一个 Bean 的 message 属性, 字符串类型, 注入值为 "Hello" 的 XML 配置文件该怎么写? 125 19、Jdo是什么? 125 20、什么是spring的IOC AOP 126 21、STRUTS的工作流程! 126 22、spring 与EJB的区别!! 126 八. ...

    Java面试宝典2012版

    给一个 Bean 的 message 属性, 字符串类型, 注入值为 "Hello" 的 XML 配置文件该怎么写? 125 19、Jdo是什么? 125 20、什么是spring的IOC AOP 126 21、STRUTS的工作流程! 126 22、spring 与EJB的区别!! 126 ...

    千方百计笔试题大全

    156、在jsp:useBean语法中使用beanName有何好处? 37 157、当我使用时,在浏览器的地址栏没有改变? 37 158、如何转换JSP 0.9版本的文件到JSP1.1? 37 160、JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么...

Global site tag (gtag.js) - Google Analytics