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

来源:互联网 发布:第三次工业革命 知乎 编辑:程序博客网 时间:2024/06/06 09:32

前几天看到国外有报道说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();//去除typevar 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 -->alertthis.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 += "}";//创建一个jsjvmvar 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

原创粉丝点击