【Java】動態(tài)生成Java代碼并編譯class文件加載

最近有個朋友在做一個爬蟲項(xiàng)目寝衫,問我是否可以考慮用Java代碼動態(tài)生成一個Java文件!在我寫完了之后拐邪,然后問他用這個來干啥慰毅,朋友很直接的說,存數(shù)據(jù)庫扎阶,我當(dāng)時(shí)的表情就是抚垃,日狗茉兰,你忙吧,我吃檸檬。坟募。。好吧粹湃,下面我說一下思路:

其實(shí)說難不難蕴侧,就這樣用最蠢的方式寫了一個代碼!
原理就是自己生成代碼谤逼,其實(shí)java里面自動生成代碼的框架很多贵扰,例如JAVAssist,而我流部,為了簡單思路戚绕,就直接用StringBuffer寫!

  1. 使用Gson分析枝冀,Gson會生成一個解析對象LinkedTreeMap舞丛,而里面的Entity內(nèi)部類保存著Gson的key-value鍵值對,其中value可能是LinkedTreeMap對象果漾,也可能是其它數(shù)據(jù)類型球切,我們姑且用Object來代替
  2. 怎么去寫這個類,首先肯定是寫類名绒障,然后寫變量名
    如果是基本數(shù)據(jù)類型和String吨凑,那么直接打印出來,變量名就是key值
    如果是List類型户辱,那么則需要導(dǎo)入ArrayList類型鸵钝,然后取第一個數(shù)據(jù),開始遞歸操作
    如果是數(shù)組類型(在Gson的解析里面是LinkedTreeMap)庐镐,那么就應(yīng)該重新聲明一個類恩商,開始進(jìn)行內(nèi)部類的遞歸操作,并添加變量和變量名必逆!
    如此一步一步下去怠堪,直到判斷所有變量都是基本數(shù)據(jù)類型|String|自定義類
  3. 使用java i/o操作揽乱,將StringBuffer對象寫進(jìn)文件。那么要把文件寫到哪個地方去粟矿,idea編譯器只認(rèn)識自己識別的文件路徑凰棉,所以file = getClass().getResource().getFile()+""+filename + ".java"
  4. 編譯java文件,并使用urlClassLoader加載Class文件就可以了
    代碼如下:

<pre>
package com.marco.test;

import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

/**

  • Created by KdMobiB on 2017/7/11.
    */
    public class Utils {
    File file;//java文件的生成目錄
    String rootName;

    /**

    • 開始解析Json數(shù)據(jù)
    • @param jsonStr
    • @return
      */
      @SuppressWarnings("unchecked")
      public HashMap<String, Object> getRootFromJson(String rootClass, String jsonStr) {
      LinkedTreeMap a = new Gson().fromJson(jsonStr, LinkedTreeMap.class);
      return getKidFromJson(rootClass, a, true);
      }

    public HashMap<String, Object> getListRootFromJson(String rootClass, String jsonStr) {
    LinkedTreeMap a = new Gson().fromJson(jsonStr, LinkedTreeMap.class);
    startChildArrayClass(rootClass);
    return getKidFromJson(rootClass, a, false);
    }

    /**

    • WRITE THE KIDCLASS

    • @param a

    • @return
      */
      public HashMap<String, Object> getKidFromJson(String childClass, LinkedTreeMap a, boolean disable) {
      if ((!rootName.equals(childClass)) && disable) {
      startChildClass(childClass);
      }

      HashMap<String, Object> maps = new HashMap<String, Object>();
      Set<LinkedTreeMap.Entry<String, Object>> entry = a.entrySet();
      Iterator<LinkedTreeMap.Entry<String, Object>> iterator = entry.iterator();
      while (iterator.hasNext()) {
      LinkedTreeMap.Entry<String, Object> stringObjectEntry = iterator.next();
      String sk = stringObjectEntry.getKey();
      Object sv = stringObjectEntry.getValue();
      if (sv instanceof LinkedTreeMap) {
      //如果TreeMap類型嚷炉,代表數(shù)據(jù)還有分支渊啰,繼續(xù)遍歷下去
      getKidFromJson(sk, (LinkedTreeMap) sv, true);
      stopChildClass();
      } else if (sv instanceof ArrayList) {
      //如果是List類型,列表內(nèi)的數(shù)據(jù)需要重新創(chuàng)建一個類
      getListRootFromJson(sk, new Gson().toJson(((ArrayList) sv).get(0)));
      stopChildClass();
      } else {
      //當(dāng)判斷不是數(shù)組類型或者列表類型申屹,直接將key寫入當(dāng)前的類
      sb.append("\t" + sv.getClass().getSimpleName() + " " + sk + ";\t\n");
      addGetAndSet(sb, sk, sv.getClass().getSimpleName());
      }
      maps.put(sk, sv);
      }
      return maps;
      }

    StringBuilder sb = new StringBuilder("\r\n");

    /**

    • 開始
    • @param root
      */
      public void startFileWrite(String root) {
      rootName = root;
      file = new File(getClass().getResource("").getFile() + "/" + root + ".java");
      sb.append(getClass().getPackage() + ";" + "\r\n");
      sb.append("public class " + root + "{" + "\r\n");
      }

    /**

    • 結(jié)束
      */
      public void finishFileWrite() {
      try {
      FileWriter fw = new FileWriter(file);
      sb.append("\r\n");
      sb.append("}");
      fw.write(sb.toString());
      fw.flush();
      fw.close();
      } catch (IOException e) {
      e.printStackTrace();
      }
      }

    public void startChildClass(String childName) {
    String childClass = childName + "Class";
    sb.append("public " + childClass + " " + childName + ";\r\n");
    sb.append("class " + childClass);
    sb.append("{" + "\r\n");
    }

    public void startChildArrayClass(String childName) {
    addLibsImport("import java.util.ArrayList;");
    String childClass = childName + "Class";
    sb.append("public ArrayList<" + childClass + "> " + childName + ";\r\n");
    sb.append("class " + childClass);
    sb.append("{" + "\r\n");
    }

    public void stopChildClass() {
    sb.append("\r\n");
    sb.append("}");
    }

    /**

    • 編寫Java文件
    • @param maps
      */
      public void writeInJava(HashMap<String, Object> maps) {
      Iterator<LinkedTreeMap.Entry<String, Object>> iterator = maps.entrySet().iterator();
      while (iterator.hasNext()) {
      LinkedTreeMap.Entry<String, Object> entry = iterator.next();
      if (entry.getValue() instanceof LinkedTreeMap) return;
      String key = entry.getKey();
      String FieldType = entry.getValue().getClass().getSimpleName();
      sb.append("\r\n\t");
      sb.append("public " + FieldType + " " + key + ";");
      sb.append("\r\n\t");
      addGetAndSet(sb, key, FieldType);
      }
      }

    public void addGetAndSet(StringBuilder sb, String name, String type) {
    sb.append("\r\n\t");
    sb.append("public void " + "set" + name);
    sb.append("(" + type + " " + name + "1" + ")");
    sb.append("{");
    sb.append("\r\n\t\t");
    sb.append("this." + name + "=" + name + "1" + ";");
    sb.append("\r\n\t");
    sb.append("}");

     sb.append("\r\n\t");
     sb.append("public " + type + " " + "get" + name);
     sb.append("(" + ")");
     sb.append("{");
     sb.append("\r\n\t\t");
     sb.append("return " + name + ";");
     sb.append("\r\n\t");
     sb.append("}");
     sb.append("\r\n");
    

    }

    /**

    • 編譯生成的Java文件
      */
      public void complie2Class() {
      JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
      StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
      Iterable units = fileMgr.getJavaFileObjects(file);
      JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
      t.call();
      try {
      fileMgr.close();
      } catch (IOException e) {
      e.printStackTrace();
      }
      }

    /**

    • 通過Url加載生成Class文件
    • @param className
      */
      public void loadClass(String className) {
      String fileUrl = "file:/" + file.getParent();
      System.out.println(fileUrl);
      try {
      URL[] urls = new URL[]{new URL(fileUrl)};
      URLClassLoader ul = new URLClassLoader(urls, ClassLoader.getSystemClassLoader());
      Class c = ul.loadClass(getClass().getPackage().getName() + "." + className);
      System.out.println(c.newInstance().getClass().getName());
      Object o = c.newInstance();
      } catch (MalformedURLException e) {
      e.printStackTrace();
      } catch (ClassNotFoundException e) {
      e.printStackTrace();
      } catch (InstantiationException e) {
      e.printStackTrace();
      } catch (IllegalAccessException e) {
      e.printStackTrace();
      }
      }

    /**

    • 添加第三方導(dǎo)包
      */
      public void addLibsImport(String lib) {
      String regex = getClass().getPackage() + ";" + "\r\n";
      if (!sb.toString().contains(lib)) {
      sb.insert(sb.indexOf(regex) + regex.length(), "\r\n" + lib + "\r\n");
      }
      }
      }
      </pre>

使用方式:
<pre>
package com.marco.test;

import com.google.gson.Gson;

import java.util.HashMap;

//1. 判斷當(dāng)前是否存在rootName相同類
//2.先寫rootClass類
//3.判斷是否需要創(chuàng)建新的類

/**

  • Created by KdMobiB on 2017/7/11.
    */
    public class Json2JavaObjcet {
    static String jsonStr = "{" +
    "animals:{" +
    "dog:[" +
    "{name:Rufus,breed:labrador,count:1,twoFeet:false}," +
    "{name:Marty,breed:whippet,count:1,twoFeet:false}" +
    "]," +
    "cat:{name:Matilda}" +
    "}" +
    "}";
    // static String jsonStr = "{cat:{name:Matilda}," +
    // "dog:{name:Matilda}," +
    // "elephant:{name:Matilda}}";

// static String jsonStr = "{" +
// "Id:[{name:myname},{name:myname}]," +
// "Name:Matilda," +
// "Age:52," +
// "Time:6" +
// "}";

public static void main(String args[]) {

    Utils utils = new Utils();
    String className = "RootName";
    utils.startFileWrite(className);//開始啟動
    utils.getRootFromJson(className,jsonStr);
    utils.finishFileWrite();

    utils.complie2Class();//編譯Java文件
    utils.loadClass(className);//加載Class文件

    System.out.println(utils.getClass().getPackage().getName());
}

}

</pre>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绘证,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子哗讥,更是在濱河造成了極大的恐慌嚷那,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件杆煞,死亡現(xiàn)場離奇詭異魏宽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)决乎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門队询,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人构诚,你說我怎么就攤上這事蚌斩。” “怎么了范嘱?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵送膳,是天一觀的道長。 經(jīng)常有香客問我丑蛤,道長叠聋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任受裹,我火速辦了婚禮碌补,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘棉饶。我一直安慰自己脑慧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布砰盐。 她就那樣靜靜地躺著,像睡著了一般坑律。 火紅的嫁衣襯著肌膚如雪岩梳。 梳的紋絲不亂的頭發(fā)上囊骤,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機(jī)與錄音冀值,去河邊找鬼也物。 笑死,一個胖子當(dāng)著我的面吹牛列疗,可吹牛的內(nèi)容都是我干的滑蚯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼抵栈,長吁一口氣:“原來是場噩夢啊……” “哼告材!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起古劲,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤斥赋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后产艾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體疤剑,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年闷堡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了隘膘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡杠览,死狀恐怖弯菊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情倦零,我是刑警寧澤误续,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站扫茅,受9級特大地震影響蹋嵌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜葫隙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一栽烂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧恋脚,春花似錦腺办、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至船响,卻和暖如春躬拢,著一層夾襖步出監(jiān)牢的瞬間躲履,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工聊闯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留工猜,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓菱蔬,卻偏偏與公主長得像篷帅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拴泌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法魏身,類相關(guān)的語法,內(nèi)部類的語法弛针,繼承相關(guān)的語法叠骑,異常的語法,線程的語...
    子非魚_t_閱讀 31,631評論 18 399
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)削茁。 張土汪:刷leetcod...
    土汪閱讀 12,744評論 0 33
  • 多態(tài) 任何域的訪問操作都將有編譯器解析宙枷,如果某個方法是靜態(tài)的,它的行為就不具有多態(tài)性 java默認(rèn)對象的銷毀順序與...
    yueyue_projects閱讀 942評論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理茧跋,服務(wù)發(fā)現(xiàn)慰丛,斷路器,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • 來我們這的有很多是都有被騙的經(jīng)歷瘾杭,也有一些是加入別的團(tuán)隊(duì)诅病,出現(xiàn)沒人教沒人理的狀況才來我們這。有時(shí)候人運(yùn)氣不好粥烁,跌入...
    75659599bc44閱讀 150評論 0 1