我们很多情况下,前台需要重新定义一个ValueObject即VO对象来转换后台的实体对象PO。主要的作用有隐藏不暴露PO的一些属性,前台只需关心展示视图需要的部分属性即可。VO一般要进行传输,因此我们定义VO一般会实现序列化,以提高对象的传输效率。PO与VO的属性转换,传统比较笨拙的办法当然就是自己手动写一个又一个的getter和setter。相对比较繁琐吧!
当然开源的apache common util包下有个BeanUtils工具类也可以方便两个实体之间的通用快速转换,但我这里要讲的不是这个。这里要说的是,我们自定义自己的注解,然后通过指定需要绑定的转换的属性,利用Java的反射机制,实现一种相对比较通用的PO与VO的转换方式。
首先,我们来定义两个注解,主要的思路和作用是标记VO与PO类的绑定,和VO定义的属性中与PO对应的属性的绑定。好了,直接来看看下面自定义注解的实现代码:
BinEntity.java
package org.haycco;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 声明需要绑定的实体注解
*
* @author haycco
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface BindEntity {
Class<?> value();
}
BindFieldName.java
package org.haycco;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 声明需要绑定的属性名注解
*
* @author haycco
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface BindFieldName {
String value();
}
好了,我们以上的代码定义了两个注解,接下来写两个简单的PO和VO类。代码如下所示:
UserPO.java
/**
* CopyRright (C) 2013: haycco All Rights Reserved.
*/
package org.haycco;
/**
* @author haycco
*/
public class UserPO {
private long id;
private String account;
private String name;
private String password;
public UserPO(long id, String account, String name, String password) {
this.id = id;
this.account = account;
this.name = name;
this.password = password;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
UserVO.java
/**
* CopyRright (C) 2013: haycco All Rights Reserved.
*/
package org.haycco;
import java.io.Serializable;
/**
* @author haycco
*/
@BindEntity(UserPO.class)
public class UserVO implements Serializable {
private static final long serialVersionUID = -1197093269635543264L;
@BindFieldName("id")
private Integer id;
@BindFieldName("account")
private String userName;
@BindFieldName("name")
private String name;
@BindFieldName("password")
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "id=" + id + ", name=" + name + ", userName=" + userName + ", password=" + password;
}
}
那到接下来看看如何利用Java的反射机制来调用setter和getter方法的具体实现代码:
/**
* 获取get方法
*
* @param objectClass
* @param fieldName
* @return
*/
@SuppressWarnings("unchecked")
public static Method getGetMethod(Class objectClass, String fieldName) {
StringBuffer sb = new StringBuffer();
sb.append("get");
sb.append(fieldName.substring(0, 1).toUpperCase());
sb.append(fieldName.substring(1));
try {
return objectClass.getMethod(sb.toString());
} catch (Exception e) {
}
return null;
}
/**
* 获取set方法
*
* @param objectClass
* @param fieldName
* @return
*/
@SuppressWarnings("unchecked")
public static Method getSetMethod(Class objectClass, String fieldName) {
try {
Class[] parameterTypes = new Class[1];
Field field = objectClass.getDeclaredField(fieldName);
parameterTypes[0] = field.getType();
StringBuffer sb = new StringBuffer();
sb.append("set");
sb.append(fieldName.substring(0, 1).toUpperCase());
sb.append(fieldName.substring(1));
Method method = objectClass.getMethod(sb.toString(), parameterTypes);
return method;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 执行set方法
*
* @param o
* @param fieldName
* @param value
*/
public static void invokeSet(Object o, String fieldName, Object value) {
Method method = getSetMethod(o.getClass(), fieldName);
try {
method.invoke(o, new Object[] { value });
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 执行get方法
*
* @param o
* @param fieldName
* @return
*/
public static Object invokeGet(Object o, String fieldName) {
Method method = getGetMethod(o.getClass(), fieldName);
try {
return method.invoke(o, new Object[0]);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
此上的代码片断是比较通用的调用setter和getter的方式。那接下来我们就要定义自己的VO转换器了,为了进一步抽象化通用,这里我们通过泛型的方式来实现,废话少说吧,直接上所有的VO转换器的代码了。
ValueObjectTransfer.java
/**
* CopyRright (C) 2013: haycco All Rights Reserved.
*/
package org.haycco;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* VO转换器
*
* @author haycco
*/
@SuppressWarnings("rawtypes")
public class ValueObjectTransfer<VO, PO> {
public static void main(String[] args) throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
List<UserPO> poList = new ArrayList<UserPO>();
poList.add(new UserPO(1, "first", "Haycco", "1234"));
poList.add(new UserPO(2, "second", "Haycco", "2345"));
ValueObjectTransfer<UserVO, UserPO> transfer = new ValueObjectTransfer<UserVO, UserPO>();
List<UserVO> voList = transfer.cast(poList, UserVO.class);
int j = 0;
for (UserVO vo : voList) {
System.out.println("*****************************************ValueObject: " + ++j);
System.out.println("UserVO: " + vo.toString());
}
}
/**
* 转换PO列表
*
* @param poList 需要转换的PO列表
* @param voClass 需要转换后的VO类
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
public List<VO> cast(List<PO> poList, Class<VO> voClass) throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
List<VO> voList = new ArrayList<VO>();
for (PO po : poList) {
VO vo = this.cast(po, voClass);
voList.add(vo);
}
return voList;
}
/**
* PO->VO
* @param po 需要转换的PO
* @param voClass 需要转换后的VO类
* @return
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
*/
@SuppressWarnings("unchecked")
public VO cast(PO po, Class<VO> voClass) throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
// 判断需要转换的PO是否跟VO所绑定的PO一致
if (!voClass.isAnnotationPresent(BindEntity.class)) {
//需要转换的PO与VO所绑定的PO不一致
return null;
}
// 反射获取VO的实例
VO vo = (VO) ClassLoader.getSystemClassLoader().loadClass(voClass.getName()).newInstance();
// 遍历VO所有声明的属性
for (Field field : voClass.getDeclaredFields()) {
Class type = field.getType();
String name = field.getName();
// 判断是否包含声明为BindFieldName注解的属性
if (field.isAnnotationPresent(BindFieldName.class)) {
BindFieldName bindFieldName = field.getAnnotation(BindFieldName.class);
// 反射调用绑定的PO属性的get方法进行取值
Object value = invokeGet(po, bindFieldName.value());
// 反射调用执行该VO属性的set方法设置值
//TODO 需要完善各种属性类型的转换
if(type.isInstance(value)) {
invokeSet(vo, name, value);
}
}
}
return vo;
}
/**
* 获取get方法
*
* @param objectClass
* @param fieldName
* @return
*/
@SuppressWarnings("unchecked")
public static Method getGetMethod(Class objectClass, String fieldName) {
StringBuffer sb = new StringBuffer();
sb.append("get");
sb.append(fieldName.substring(0, 1).toUpperCase());
sb.append(fieldName.substring(1));
try {
return objectClass.getMethod(sb.toString());
} catch (Exception e) {
}
return null;
}
/**
* 获取set方法
*
* @param objectClass
* @param fieldName
* @return
*/
@SuppressWarnings("unchecked")
public static Method getSetMethod(Class objectClass, String fieldName) {
try {
Class[] parameterTypes = new Class[1];
Field field = objectClass.getDeclaredField(fieldName);
parameterTypes[0] = field.getType();
StringBuffer sb = new StringBuffer();
sb.append("set");
sb.append(fieldName.substring(0, 1).toUpperCase());
sb.append(fieldName.substring(1));
Method method = objectClass.getMethod(sb.toString(), parameterTypes);
return method;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 执行set方法
*
* @param o
* @param fieldName
* @param value
*/
public static void invokeSet(Object o, String fieldName, Object value) {
Method method = getSetMethod(o.getClass(), fieldName);
try {
method.invoke(o, new Object[] { value });
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 执行get方法
*
* @param o
* @param fieldName
* @return
*/
public static Object invokeGet(Object o, String fieldName) {
Method method = getGetMethod(o.getClass(), fieldName);
try {
return method.invoke(o, new Object[0]);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
以上就是所有实现代码,利用Java的泛型、注解和反射的方式。需要测试的童鞋,只需执行ValueObjectTransfer.java的main方法即可。这样的方式,在通用性来说还是比较灵活的,在VO对象用@BindEntity注解绑定对应的PO类,需要自动赋值的VO属性也只需加上@BindFieldName注解进行标记就可以了,但目前上面的代码只是做到同类型属性的setter和getter。还有待完善各种属性类型值的转换,由于需要浩大的if else代码,各位有兴趣的童鞋,自己去完善吧。