使用Javassist重写Java Bean的toString方法

项目中有很多的界面对象描述类,他们都是接口View的实现,在输出的时候,需要按照特定格式输出成xml表现;

起初采用Commons beanutils的分析对象的方法,获取所有属性的值,构建格式输出;

如有以下的Class

class LabelView implements View {
private String id;
private String value;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}
}

有对应的类

LabelView label = new LabelView();
label.setId("label1");
label.setValue("Hello, world.");

前端需要的输出格式内容为

<label id="label1" value="Hello, world."></label>


另有以下的Class

class TextfieldView implements View {
private String id;
private String name;
private String value;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}
}


有对应的类

TextfieldView textfield = new TextfieldView();
textfield.setId("field1");
textfield.setName("field1");
textfield.setValue("张三");

前端需要的输出格式内容为

<textfield id="field1" name="field1" value="张三"></textfield>



实际使用的时候,由于存在众多的界面对象描述类需要解析,发现beanutils的时间效率比较低下;

后来考虑采用字节码操作工具对类进行改写,达到自动生成toString()方法的目的;比较了asm和javassist,发现asm的代码太复杂了,所以决定采用javassist;

对class的属性分析代码与beanutils的方式类似,只是需要新生成一个class而已;

过程是这样的:
[list]
[*]通过javassist生成一个新的class,如LabelView,则生成LabelViewAccess extends LabelView

ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(View.class));

CtClass ccOld = pool.get(className);
CtClass ccNew = pool.makeClass(className + "Access");
ccNew.setSuperclass(ccOld);

[*]读取LabelView的结构,取得所有的get和is方法

CtMethod[] methods = ccOld.getMethods();
for (CtMethod method : methods) {
if (method.getName().startsWith("set")) {
String shortName = method.getName().substring(3);
String fieldName = shortName.toLowerCase();
if (method.getParameterTypes()[0].getName().equals(boolean.class.getName())) {
// is
} else {
// get
}
}
}


[*]利用javassist构建toString()方法,将上面取得的方法进行字符串拼接

String n = ..; // TODO 取得className LabelView对应的输出名称label

StringBuffer strbuff = new StringBuffer();
strbuff.append("java.lang.StringBuffer sb = new java.lang.StringBuffer();");
strbuff.append("sb.append(\"<" + n + "\");");

// TODO 以下代码嵌入上面的循环内部
if (method.getParameterTypes()[0].getName().equals(boolean.class.getName())) {
strbuff.append("sb.append(\" " + fieldName + "=\\\"\"+is" + shortName + "()+\"\\\"\");");
} else {
strbuff.append("sb.append(\" " + fieldName + "=\\\"\"+get" + shortName + "()+\"\\\"\");");
}

strbuff.append("sb.append(\">\");");
strbuff.append("sb.append(\"</" + n + ">\");");
strbuff.append("return sb.toString();");

CtMethod sm = new CtMethod(pool.get("java.lang.String"), "toString", null, ccNew);
sm.setBody("{" + strbuff.toString() + "}");
ccNew.addMethod(sm);


[*]调用javassist的CtClass.toClass()方法返回LabelView的真实class LabelViewAccess,并存储起来备用

Map<String, Class> classMap = new HashMap<String, Class>();
classMap.put(className, ccNew.toClass());


[*]使用的时候,获得上面的LabelViewAccess,然后class.getConstructor().newInstance()获取带有格式化输出toString方法的LabelView对象

classMap.get(className).newInstance().toString();

[/list]

采用javassist之后,时间效率明显提高,基本上就等于手写的toString方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值