利用泛型、自定义注解和反射实现PO与VO的快捷转换

     我们很多情况下,前台需要重新定义一个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代码,各位有兴趣的童鞋,自己去完善吧。

  

  

转载于:https://www.cnblogs.com/haycco/p/3416665.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
假设我们有一个形状接口 Shape 和两个具体的形状类 Circle 和 Rectangle。我们可以定义一个泛型方法来计算不同形状的面积,代码如下: ``` public interface Shape { double getArea(); } public class Circle implements Shape { private double radius; public Circle(double radius) { this.radius = radius; } public double getArea() { return Math.PI * radius * radius; } } public class Rectangle implements Shape { private double width; private double height; public Rectangle(double width, double height) { this.width = width; this.height = height; } public double getArea() { return width * height; } } public class AreaCalculator { public static <T extends Shape> double calculateArea(T shape) { return shape.getArea(); } } ``` 在这个示例中,我们定义了一个 Shape 接口,其中包括一个 getArea() 方法来计算形状的面积。然后,我们创建了两个具体的形状类 Circle 和 Rectangle,并分别实现了 Shape 接口中的 getArea() 方法。 最后,我们定义了一个泛型方法 calculateArea(),它接受一个泛型类型 T,该类型必须是 Shape 的子类。该方法调用传递给它的形状的 getArea() 方法来计算面积,并返回结果。 使用示例: ``` Circle circle = new Circle(5.0); Rectangle rectangle = new Rectangle(10.0, 5.0); double circleArea = AreaCalculator.calculateArea(circle); double rectangleArea = AreaCalculator.calculateArea(rectangle); System.out.println("Circle area: " + circleArea); System.out.println("Rectangle area: " + rectangleArea); ``` 输出: ``` Circle area: 78.53981633974483 Rectangle area: 50.0 ``` 在这个例子中,我们创建了一个 Circle 对象和一个 Rectangle 对象,并分别计算它们的面积。我们使用泛型方法 calculateArea() 来计算它们的面积,它会调用传递给它的形状对象的 getArea() 方法来计算面积。最后,我们输出计算出的面积。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值