利用泛型、自定義註解和反射實現PO與VO的快捷轉換

     咱們不少狀況下,前臺須要從新定義一個ValueObject即VO對象來轉換後臺的實體對象PO。主要的做用有隱藏不暴露PO的一些屬性,前臺只需關心展現視圖須要的部分屬性便可。VO通常要進行傳輸,所以咱們定義VO通常會實現序列化,以提升對象的傳輸效率。PO與VO的屬性轉換,傳統比較笨拙的辦法固然就是本身手動寫一個又一個的getter和setter。相對比較繁瑣吧!java

      固然開源的apache common  util包下有個BeanUtils工具類也能夠方便兩個實體之間的通用快速轉換,但我這裏要講的不是這個。這裏要說的是,咱們自定義本身的註解,而後經過指定須要綁定的轉換的屬性,利用Java的反射機制,實現一種相對比較通用的PO與VO的轉換方式。apache

首先,咱們來定義兩個註解,主要的思路和做用是標記VO與PO類的綁定,和VO定義的屬性中與PO對應的屬性的綁定。好了,直接來看看下面自定義註解的實現代碼:app

BinEntity.javaide

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.javathis

/**
 * 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方法的具體實現代碼:blog

/**
     * 獲取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轉換器的代碼了。get

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代碼,各位有興趣的童鞋,本身去完善吧。

相關文章
相關標籤/搜索