前言:经常在网络上看见一些关于json自动转换成javaBean的jar包,项目组里的人也在用,稍稍研究了下,都是用的反射来做的。我细细想了下里面的逻辑,我觉得直接生成JavaBean代码岂不是更加直接,反射在移动端,怎么说都是消耗资源的。
Java Bean 类的结构
首先要梳理下,到底Bean类是一个什么样的文件,很简单的是有很多属性的class文件,属性有很多类别,但是从json的角度来看,类别又是有限的:基本类型和List。我们可以用python来模拟下:
# encoding: utf-8 ''' Created on 2014.12.24 @author: 13051041 ''' class JavaClass(object): ''' class templete ''' def __init__(self, name): ''' Constructor ''' self.mName = name; self.mIntegerList = [] self.mStrList = [] self.mBolList = [] self.mListList = [] self.mClassList = [] self.mInClassTypeList = [] self.mIsParcelable = True self.mPackageName = "package com.codegenerator;" def addIntAttribute(self, str1): ''' add String attribute ''' self.mIntegerList.append(str1) def addUnicodeAttribute(self, str1): ''' add String attribute ''' self.mStrList.append(str1) def addBooleanAttribute(self, bol): ''' add Boolean attribute ''' self.mBolList.append(bol) def addListAttribute(self, list1): ''' add List attribute ''' self.mListList.append(list1) def addClassAttribute(self, cls): ''' add Class attribute ''' self.mClassList.append(cls) def addInClassType(self, inClass): ''' add Inner Class attribute ''' self.mInClassTypeList.append(inClass) def test(self): print "-----this is JavaClass information start-----" print "class's name is %s" % self.mName print "class's integer is %s " % self.mIntegerList print "class's String is %s " % self.mStrList print "class's Boolean is %s " % self.mBolList print "class's List is %s " % self.mListList print "class's inner class is %s " % self.mClassList print "class's inner class type is %s " % self.mInClassTypeList print "-----this is JavaClass information end-----" classNum = 0 def autoGeneratorClassName(): global classNum classNum = classNum + 1 return "class%d" % classNum def buildJavaClassNode(jsonObject, className): javaclass = JavaClass(className) keys = jsonObject.keys() for key in keys: t = type(jsonObject[key]) if t == int: javaclass.addIntAttribute(key) if t == unicode: javaclass.addUnicodeAttribute(key) if t == bool: javaclass.addBooleanAttribute(key) if t == dict: newClassName = autoGeneratorClassName() javaclass.addClassAttribute((newClassName, key)) javaclass.addInClassType(buildJavaClassNode(jsonObject[key], newClassName)) if t == list: t2 = type(jsonObject[key][0]) if t2 == dict: newClassName = autoGeneratorClassName() javaclass.addListAttribute((newClassName, key)) javaclass.addInClassType(buildJavaClassNode(jsonObject[key][0], newClassName)) else: javaclass.addListAttribute((t2, key)) return javaclass
生成java文件,递归才是王道
我们一个叫javaclass的python类了,用python读取json,直接生成实例。现在的任务是把这个实例,写到文件里面。想想class的嵌套关系,生成最好的方法就是递归:
# encoding: utf-8 ''' Created on 2014.12.26 @author: 13051041 ''' Class_import = ''' %s import java.util.ArrayList; import java.util.List; import org.json.JSONArray; import org.json.JSONObject; import org.json.JSONException; ''' Class_import_parcelable = ''' import android.os.Parcel; import android.os.Parcelable; ''' Class_HEAD = ''' public %s class %s { ''' Class_HEAD_parcelable = ''' public %s class %s implements Parcelable{ public %s() { } public %s(Parcel in) { readFromParcel(in); } ''' Class_Method_END = "} " Attribute_TEMP = "public %s %s; " Method_Analyzer = ''' public void analyzerJson(JSONObject jsonObject) throws JSONException { if(jsonObject == null){ return; } ''' Method_TEMP = "public %s %s(%s)throws JSONException { " Method_GET_INT = '''%s = GetJsonAttributeUtil.getInt(jsonObject, "%s");''' Method_GET_String = '''%s = GetJsonAttributeUtil.getString(jsonObject,"%s");''' Method_GET_Boolean = '''%s = GetJsonAttributeUtil.getBoolean(jsonObject,"%s");''' Method_GET_CLASS = '''%s = new %s(); %s.analyzerJson(GetJsonAttributeUtil.getJSONObject(jsonObject,"%s"));''' Method_GET_List = ''' %s= new ArrayList<%s>(); JSONArray array%s = GetJsonAttributeUtil.getJSONArray(jsonObject,"%s"); int %sLen = array%s.length(); for(int i = 0;i<%sLen;i++){ %s item = new %s(); item.analyzerJson(array%s.getJSONObject(i)); %s.add(item); } ''' Method_Parcelable_Write = '''public void writeToParcel(Parcel dest, int flags) { ''' Mehtod_Parcelable_Value_Write = "dest.write%s(%s); " Method_Parcelable_Read = '''public void readFromParcel(Parcel in) { ''' Mehtod_Parcelable_Value_Read = "%s= in.readString(); " IS_PARCELABLE = True FILE_NAME = "Bean" def writeParcelabelMethod(f, jcls): # writeToParcel method f.write(Method_Parcelable_Write) for attribute in jcls.mIntegerList: f.write("dest.writeInt(%s); " % (attribute)) for attribute in jcls.mStrList: f.write("dest.writeString(%s); " % (attribute)) for attribute in jcls.mBolList: f.write("dest.writeByte((byte) (%s ? 1 : 0)); " % (attribute)) for attribute in jcls.mListList: f.write("dest.writeTypedList(%s);" % (attribute[1])) for attribute in jcls.mClassList: f.write("dest.writeParcelable(%s, PARCELABLE_WRITE_RETURN_VALUE);" % attribute[1]) f.write(Class_Method_END) # readFromParcel method f.write(Method_Parcelable_Read) for attribute in jcls.mIntegerList: f.write("%s= in.readInt(); " % (attribute)) for attribute in jcls.mStrList: f.write("%s= in.readString(); " % (attribute)) for attribute in jcls.mBolList: f.write("%s = in.readByte() != 0; " % (attribute)) for attribute in jcls.mListList: f.write("%s = new ArrayList<%s>();" % (attribute[1], attribute[0])) f.write("in.readTypedList(%s, %s.CREATOR);" % (attribute[1], attribute[0])) for attribute in jcls.mClassList: f.write("%s = in.readParcelable(%s.class.getClassLoader());" % (attribute[1], attribute[0])) f.write(Class_Method_END) # describeContents method f.write("public int describeContents() {return 0;}") f.write(''' public static final Parcelable.Creator<%s> CREATOR = new Parcelable.Creator<%s>() { public %s createFromParcel(Parcel in) { return new %s(in); } public %s[] newArray(int size) { return new %s[size]; } }; ''' % (jcls.mName, jcls.mName, jcls.mName, jcls.mName, jcls.mName, jcls.mName)) pass def writeCls2File(jcls, f): f.seek(0, 2) # write class header if IS_PARCELABLE: # if need implement parcelable if jcls.mName == FILE_NAME: f.write(Class_HEAD_parcelable % ("", jcls.mName, jcls.mName, jcls.mName)) else: f.write(Class_HEAD_parcelable % ("static", jcls.mName, jcls.mName, jcls.mName)) else: f.write(Class_HEAD % ("", jcls.mName)) # write class's attribute for attribute in jcls.mIntegerList: f.write(Attribute_TEMP % ('int', attribute)) for attribute in jcls.mStrList: f.write(Attribute_TEMP % ('String', attribute)) for attribute in jcls.mBolList: f.write(Attribute_TEMP % ('Boolean', attribute)) for attribute in jcls.mListList: f.write(Attribute_TEMP % ('List<' + attribute[0] + '>', attribute[1])) for attribute in jcls.mClassList: f.write(Attribute_TEMP % (attribute[0], attribute[1])) # write class's method analyzerJson f.write(Method_Analyzer) for attribute in jcls.mIntegerList: f.write(Method_GET_INT % (attribute, attribute)) for attribute in jcls.mStrList: f.write(Method_GET_String % (attribute, attribute)) for attribute in jcls.mBolList: f.write(Method_GET_Boolean % (attribute, attribute)) for attribute in jcls.mClassList: f.write(Method_GET_CLASS % (attribute[1], attribute[0], attribute[1], attribute[1])) for attribute in jcls.mListList: f.write(Method_GET_List % (attribute[1], attribute[0], attribute[1], attribute[1], attribute[1], attribute[1], attribute[1], attribute[0], attribute[0], attribute[1], attribute[1])) f.write(Class_Method_END) # write parcelable method if IS_PARCELABLE: writeParcelabelMethod(f, jcls) # the method toString f.write("public String toString(){") f.write("String allInfo = ") for attribute in jcls.mIntegerList: f.write(''' " %s="+%s + ''' % (attribute, attribute)) for attribute in jcls.mStrList: f.write(''' " %s="+%s + ''' % (attribute, attribute)) for attribute in jcls.mBolList: f.write(''' " %s="+%s + ''' % (attribute, attribute)) for attribute in jcls.mListList: f.write(''' " %s="+%s.toString() + ''' % (attribute[1], attribute[1])) for attribute in jcls.mClassList: f.write(''' " %s="+%s.toString() + ''' % (attribute[1], attribute[1])) f.write('''" ";''') f.write("return allInfo;") f.write(Class_Method_END) # write class's class for innerClass in jcls.mInClassTypeList: writeCls2File(innerClass, f) pass f.write(Class_Method_END) pass def generatorClsFile(jcls): global IS_PARCELABLE global FILE_NAME IS_PARCELABLE = jcls.mIsParcelable FILE_NAME = jcls.mName f = open(FILE_NAME + ".java", 'w') f.write(Class_import % jcls.mPackageName) if IS_PARCELABLE: f.write(Class_import_parcelable) writeCls2File(jcls, f)
完整项目:http://files.cnblogs.com/files/chenjie0949/CodeGenerator1.3.zip