作用说明
这是一个工具方法,有以下作用。
(1)快速生成实体类的getter和setter方法;
(2)为类添加注释,鼠标悬浮在new后的类名上可以在代码助手中提示相应类的说明;
(3)为getter和setter方法添加注释,在调用时代码助手中提示相应方法的说明;
(4)生成的setter方法会返回当前类的对象,以满足链式set的调用形式。
工具代码
话不多说,直接上代码:
package com.po;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class _produceGS {
public static void main(String[] args) {
FileWriter fw = null;
String path = "src/com/po/Student.java";
try {
List<String> sL = Files.readAllLines(Paths.get(path));
Map<String, List<Map<String, String>>> m = new HashMap<>();
int lv = 0; List<String> classNameL = new ArrayList<>();
boolean func = false;
for(String s : sL) { // 第一次循环找出所有类下的所有属性
if(s.indexOf("class ") > -1 && s.indexOf("{") > s.indexOf("class ")) { // 是类
classNameL.add(s.substring(s.indexOf("class ") + 6, s.indexOf("{")).trim());lv++;} // 取类名
if(s.indexOf(";") > 0 && s.indexOf("package ") < 0 && s.indexOf("import ") < 0 && s.indexOf("this.") < 0 && s.indexOf("return ") < 0) { // 是属性
String strTemp = "";
List<Map<String, String>> l = m.get(classNameL.get(lv - 1));
if(l == null) {l = new ArrayList<>();}
Map<String, String> propM = new HashMap<>();
if(s.indexOf("=") > 0 && s.indexOf("=") < s.indexOf(";")) {
strTemp = s.substring(0, s.indexOf("=")).trim();
propM.put("value", s.substring(s.indexOf("=") + 1, s.indexOf(";")).trim()); // 属性值
}else{strTemp = s.substring(0, s.indexOf(";")).trim();} // 截止到属性名称结束的所有内容
propM.put("name", strTemp.substring(strTemp.lastIndexOf(" ") + 1)); // 属性名
strTemp = strTemp.substring(0, strTemp.lastIndexOf(" ")).trim(); // 截止到属性类型结束的所有内容;
if(strTemp.lastIndexOf(" ") < 0) {propM.put("type", strTemp); // 说明属性类型起始
}else{ // 说明属性类型前面还有修饰符
if(s.indexOf("final ") > -1) {propM.put("isFinal", "1");}
propM.put("type", strTemp.substring(strTemp.lastIndexOf(" ") + 1));
}
if(s.indexOf("//") > -1){propM.put("remark", s.substring(s.indexOf("//") + 2).trim());} // 有注释
l.add(propM);
m.put(classNameL.get(lv - 1), l);
}
if(s.indexOf("(") > 0 && s.indexOf(")") > 0 && s.indexOf("{") > 0) {func = true;}
if(s.indexOf("}") > -1) {
if(func) {func = false;}else {classNameL.remove(classNameL.size() - 1);lv--;}
} // 为了让所有属性紧贴一起而不被getter和setter方法分开,第二次循环再统一插入getter和setter。
}
StringBuffer rs = new StringBuffer();
String tab = "";
for(String s : sL) {
if(s.indexOf("package ") > -1 || s.indexOf("import ") > -1 || "".equals(s.trim())
|| s.indexOf(";") > 0 && s.indexOf("this.") < 0 && s.indexOf("return ") < 0) {rs.append(s + "\r\n");}
if(s.indexOf("class ") > -1 && s.indexOf("{") > s.indexOf("class ")) { // 是类
classNameL.add(s.substring(s.indexOf("class ") + 6, s.indexOf("{")).trim()); // 取类名
if(s.indexOf("//") > -1) {rs.append(tab + "/**" + s.substring(s.indexOf("//") + 2).trim() + "*/\r\n");}
lv++;rs.append(s + "\r\n");}
if(s.indexOf("(") > 0 && s.indexOf(")") > 0 && s.indexOf("{") > 0) {func = true;}
if(s.indexOf("}") > -1) {
if(func) {func = false;continue;}
List<Map<String, String>> l = m.get(classNameL.get(lv - 1));
if(l != null) {
for(Map<String, String> p : l) {
if(p.get("remark") != null) { // 当前属性有注释
rs.append(tab + "/**获取:" + p.get("remark") + (p.get("value") != null ? " | 默认值:" + p.get("value") : "") + "*/\r\n");
}
rs.append(tab + "public " + p.get("type") + " get" + p.get("name").substring(0, 1).toUpperCase()
+ p.get("name").substring(1) + "(){return " + p.get("name") + ";}\r\n"); // getter方法
if(p.get("isFinal") != null) {continue;} // 有final修饰(不允许有set方法)
if(p.get("remark") != null) {
rs.append(tab + "/**设置:" + p.get("remark") + (p.get("value") != null ? " | 默认值:" + p.get("value") : "") + "*/\r\n");
}
rs.append(tab + "public " + classNameL.get(lv - 1) + " set" + p.get("name").substring(0, 1).toUpperCase()
+ p.get("name").substring(1) + "(" + p.get("type") + " " + p.get("name") + "){this."
+ p.get("name") + "=" + p.get("name") + ";return this;}\r\n"); // setter方法
}
}
classNameL.remove(classNameL.size() - 1); lv--; rs.append(s + "\r\n");
}
tab = "";
for(int i=0;;i++) {
if(s.length() > i+1 && s.charAt(i) == '\t') {tab += "\t";}else{break;}
}
}
fw = new FileWriter(path, false);
fw.write(rs.toString());
} catch (IOException e) {e.printStackTrace();}
if(fw != null) {try {fw.close();} catch (IOException e) {}}
}
}
以上这段代码就是生成工具,在 path 变量中指定相应的实体类文件路径,执行代码就会自动在该实体类中生成注释。
演示示例
假定我们有一个学生实体类Student,代码如下:
package com.po;
import java.util.List;
public class Student <T> { // 学生实体类
private Integer id; // in10-学生id,主键自增
public int type = 1; // ti1-学生类型:1普通学生,2理科生,3文科生,4艺术生,5体育生
protected String name; // va4-学生姓名(不超过4个字符)
private static boolean isGirl;
Score score; // 成绩分数
private static final double num = Math.E;
public class Score{ // 成绩分数实体类
private Integer chinese; // 语文成绩
private Integer maths; // 数学成绩
private Integer art = 60; // 艺术成绩
}
private List<Experience> expL; // 实践经历
class Experience{
private Integer id; // 经历的id
private Event event; // 经历的事情
protected class Event {
private Long time; // 事情起始的时间
private String describe; // 事情经过的描述
private String result; // 事情的结果及评价
}
}
private List<String> hobbyL; // 学生爱好
private T t;
}
这个实体类中有各种类型的数据,甚至还包括内部类、泛型。
如果用IDE自动生成getter和setter(Source - Generate Getters and Setters...),则不会带上注释。简单的实体类还好,如果是复杂的实体类,有几十个甚至上百个属性,或者还存在复杂的属性,没办法直接从属性名上看出来值是怎么回事的(比如例中type属性,1表示什么,2表示什么……),时间长了难免会忘记。这时我们用工具方法直接生成getter、setter方法和注释,运行工具方法后实体类Student变化结果如下:
package com.po;
import java.util.List;
/**学生实体类*/
public class Student <T> { // 学生实体类
private Integer id; // in10-学生id,主键自增
public int type = 1; // ti1-学生类型:1普通学生,2理科生,3文科生,4艺术生,5体育生
protected String name; // va4-学生姓名(不超过4个字符)
private static boolean isGirl;
Score score; // 成绩分数
private static final double num = Math.E;
/**成绩分数实体类*/
public class Score{ // 成绩分数实体类
private Integer chinese; // 语文成绩
private Integer maths; // 数学成绩
private Integer art = 60; // 艺术成绩
/**获取:语文成绩*/
public Integer getChinese(){return chinese;}
/**设置:语文成绩*/
public Score setChinese(Integer chinese){this.chinese=chinese;return this;}
/**获取:数学成绩*/
public Integer getMaths(){return maths;}
/**设置:数学成绩*/
public Score setMaths(Integer maths){this.maths=maths;return this;}
/**获取:艺术成绩 | 默认值:60*/
public Integer getArt(){return art;}
/**设置:艺术成绩 | 默认值:60*/
public Score setArt(Integer art){this.art=art;return this;}
}
private List<Experience> expL; // 实践经历
class Experience{
private Integer id; // 经历的id
private Event event; // 经历的事情
protected class Event {
private Long time; // 事情起始的时间
private String describe; // 事情经过的描述
private String result; // 事情的结果及评价
/**获取:事情起始的时间*/
public Long getTime(){return time;}
/**设置:事情起始的时间*/
public Event setTime(Long time){this.time=time;return this;}
/**获取:事情经过的描述*/
public String getDescribe(){return describe;}
/**设置:事情经过的描述*/
public Event setDescribe(String describe){this.describe=describe;return this;}
/**获取:事情的结果及评价*/
public String getResult(){return result;}
/**设置:事情的结果及评价*/
public Event setResult(String result){this.result=result;return this;}
}
/**获取:经历的id*/
public Integer getId(){return id;}
/**设置:经历的id*/
public Experience setId(Integer id){this.id=id;return this;}
/**获取:经历的事情*/
public Event getEvent(){return event;}
/**设置:经历的事情*/
public Experience setEvent(Event event){this.event=event;return this;}
}
private List<String> hobbyL; // 学生爱好
private T t;
/**获取:in10-学生id,主键自增*/
public Integer getId(){return id;}
/**设置:in10-学生id,主键自增*/
public Student <T> setId(Integer id){this.id=id;return this;}
/**获取:ti1-学生类型:1普通学生,2理科生,3文科生,4艺术生,5体育生 | 默认值:1*/
public int getType(){return type;}
/**设置:ti1-学生类型:1普通学生,2理科生,3文科生,4艺术生,5体育生 | 默认值:1*/
public Student <T> setType(int type){this.type=type;return this;}
/**获取:va4-学生姓名(不超过4个字符)*/
public String getName(){return name;}
/**设置:va4-学生姓名(不超过4个字符)*/
public Student <T> setName(String name){this.name=name;return this;}
public boolean getIsGirl(){return isGirl;}
public Student <T> setIsGirl(boolean isGirl){this.isGirl=isGirl;return this;}
/**获取:成绩分数*/
public Score getScore(){return score;}
/**设置:成绩分数*/
public Student <T> setScore(Score score){this.score=score;return this;}
public double getNum(){return num;}
/**获取:实践经历*/
public List<Experience> getExpL(){return expL;}
/**设置:实践经历*/
public Student <T> setExpL(List<Experience> expL){this.expL=expL;return this;}
/**获取:学生爱好*/
public List<String> getHobbyL(){return hobbyL;}
/**设置:学生爱好*/
public Student <T> setHobbyL(List<String> hobbyL){this.hobbyL=hobbyL;return this;}
public T getT(){return t;}
public Student <T> setT(T t){this.t=t;return this;}
}
效果截图
其实就是添加上了【/** xxx */】注释,注释的内容取的就是每个类名或每个属性后面【//】后的内容。这个注释有什么好处呢?
好处显而易见了吧。如果生成了注释之后发现注释写错了,或者日后注释需要发生变化,只需要修改相应双斜线后面的后的注释内容,然后直接再次运行本工具方法重新生成getter和setter注释即可。(无需删除原有的getter和setter注释。)
规则与限制
(1)生成的getter和setter方法都是public,不加其它逻辑,并且方法本身没有换行。如果希望生成的方法或注释需要变动及加工或美化等,请自行修改标有【// getter方法】、【// setter方法】注释及【rs.append(tab + "/**获取:"】、【rs.append(tab + "/**设置:"】中的内容。
(2)虽然生成后的getter和setter方法没有换行,但类中的属性请注意换行,属性的声明不要和类声明【public class ...】、类结束符【}】以及其它属性共同写在一行内,否则运行该方法会出错。
(3)所有的类或属性注释必须在相应行末用双斜线【//】继续写注释,且不支持换行书写,不管注释有多长,都要写在同一行。并且,本工具不判断属性是否被注释掉。即便被注释掉的属性(例如:【// private String name2;】),本工具同样会生成getter和setter方法。
(4)本工具方法只会保留如该例子(实体类Student)中的包路径【package ...】、类引用【import ...】、空行、类或方法的声明、类结束符【}】。其它内容在运行本工具方法时将全部被删除。例如您自己编写的文档注释【/** xxx */】或段落注释【/* xxx */】,以及其它您自己写的方法(如构造方法、toString() 方法等)。不推荐您在这个实体类中编写任何其它方法,因为很容易导致当前工具运行时产生错误。
(5)因本工具是按照空格来拆分各个部分的,所以属性的类型中不要有空格,否则生成的getter和setter方法会出错。例如【private Map<String, Object> data;】,因为属性类型【Map<String, Object>】中的【,】后面与【Object】前面有一个空格,所以会出错,去掉这个空格即可。
(注:本示例中,生成之后的实体类Student会出现一个警告,因为isGirl属性是有static(静态的)修饰的,在setter方法中不应该使用this.isGirl,应该用Student.isGirl。不过this关键字在这里本来代表的就是当前类Student,使用this.isGirl不会引起问题,所以这个警告作者并不打算修复,有强迫症的朋友请自行修改工具类或手动修改生成之后的setter方法。)
郑重声明
因为本工具方法是直接修改原实体类中的内容,在运行本工具方法之前,请先将原实体类做备份。一旦本软件有任何疏漏或错误导致您原实体类中的数据被破坏或丢失,无法复原,因此给您造成的损失,作者不承担任何责任。
(提示:若被修改的实体类在ide中是打开的状态下,使用本工具软件修改后,如果发现有问题,可以在该实体类窗口中按ctrl+z撤销,回到之前的状态。)
方法就说明到这里,希望这个小工具能帮助到大家。
虽然本示例中已经尽可能多的考虑到各种情况,但由于实体类的内容千变万化,作者也不能全部都考虑到。如果方法中还有疏漏或隐患,还望各位不吝赐教。