POJO转换类工具类


javaweb项目中,少不了需要领域类之间的转换,比如po类转换为dto。
这个功能很多第三方工具类都有提供,比如比如org.apache.commons包中的BeanUtils。本文也提供了一个pojo的转换工具类,经测算,该工具类的运行效率比BeanUtils快20倍。

下文是工具类代码:

/**
 * 实体类转化工具类
 * @author 漆可
 * @date 2017年12月27日 下午4:53:46
 */
public class PojoConvertUtil
{
    /**
     * 变量缓存
     */
    private static final Map<String, Map<String, Field>> cacheFields = new ConcurrentHashMap<>();

    //基础数据类型
    private static final Set<Class<?>> basicClass = new HashSet<>();
    static
    {
        basicClass.add(Integer.class);
        basicClass.add(Character.class);
        basicClass.add(Byte.class);
        basicClass.add(Float.class);
        basicClass.add(Double.class);
        basicClass.add(Boolean.class);
        basicClass.add(Long.class);
        basicClass.add(Short.class);
        basicClass.add(String.class);
        basicClass.add(BigDecimal.class);
    }

    /**
     * 将具有相同属性的类型进行转换
     * @param orig
     * @param <T>
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static <T> T convertPojo(Object orig, Class<T> targetClass)
    {
        try
        {
            T target = targetClass.newInstance();

            if (orig == null)
            {
                return target;
            }

            // 获取源对象中的所有field
            Class<? extends Object> origClass = orig.getClass();
            Field[] fields = getFieldFromClass(origClass);

            for (Field field : fields)
            {

                if (isStatic(field))
                {//跳过静态属性
                    continue;
                }

                // 获取目标对象中的对应的field
                Field targetField = getTargetField(targetClass, field.getName());
                if (targetField == null)
                    continue;

                Object value = getFiledValue(field, orig);
                if (value == null)
                    continue;
                Class orginType = field.getType();
                Class targetType = targetField.getType();
                // 两个类型是否相同
                boolean sameType = orginType.equals(targetType);
                if (isBasicType(orginType))
                {
                    if (sameType)
                        setFieldValue(targetField, target, value);
                } else if (value instanceof Map && Map.class.isAssignableFrom(targetType))
                {   
                    // map类型拷贝
                    setMap((Map) value, field, targetField, target);
                } else if (value instanceof Set && Set.class.isAssignableFrom(targetType))
                {
                    // set类型拷贝
                    setCollection((Collection) value, field, targetField, target);
                } else if (value instanceof List && List.class.isAssignableFrom(targetType))
                {
                    // list类型拷贝
                    setCollection((Collection) value, field, targetField, target);
                } else if (value instanceof Enum && Enum.class.isAssignableFrom(targetType))
                {
                    //enum拷贝
                    setEnum((Enum) value, field, targetField, target);
                } else if (value instanceof java.util.Date
                        && java.util.Date.class.isAssignableFrom(targetType))
                {
                    //对日期类型拷贝,不处理如joda包之类的扩展时间,不处理calendar
                    setDate((Date) value, targetField, targetType, target, sameType);
                }else{
                    @SuppressWarnings("unchecked")
                    T convertPojo = (T) convertPojo(value, targetType);
                    setFieldValue(targetField, target, convertPojo);
                }
            }
            return target;
        } catch (Throwable t)
        {
            t.printStackTrace();
            throw new RuntimeException(t.getMessage());
        }
    }

    // 获取类中的field变量,包括父类
    private static Field[] getFieldFromClass(Class<? extends Object> origClass)
    {
        List<Field> fields = new ArrayList<>(Arrays.asList(origClass.getDeclaredFields()));

        if (origClass.getSuperclass() != null)
        {
            fields.addAll(Arrays.asList(getFieldFromClass(origClass.getSuperclass())));
        }

        return fields.toArray(new Field[fields.size()]);
    }

    /**
     * 获取字段值
     * @param field
     * @param obj
     * @return
     */
    private static Object getFiledValue(Field field, Object obj) throws IllegalAccessException
    {
        // 获取原有的访问权限
        boolean access = field.isAccessible();
        try
        {
            // 设置可访问的权限
            field.setAccessible(true);
            return field.get(obj);
        } finally
        {
            // 恢复访问权限
            field.setAccessible(access);
        }
    }

    /**
     * 设置方法值
     * @param field
     * @param obj
     * @param value
     * @throws IllegalAccessException
     */
    private static void setFieldValue(Field field, Object obj, Object value)
            throws IllegalAccessException
    {
        // 获取原有的访问权限
        boolean access = field.isAccessible();
        try
        {
            // 设置可访问的权限
            field.setAccessible(true);
            field.set(obj, value);
        } finally
        {
            // 恢复访问权限
            field.setAccessible(access);
        }
    }

    /**
     * 转换list
     * @param orig
     * @param targetClass
     * @param <T>
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static <T> List<T> convertPojos(List orig, Class<T> targetClass)
    {
        List<T> list = new ArrayList<>(orig.size());
        for (Object object : orig)
        {
            list.add(convertPojo(object, targetClass));
        }
        return list;
    }

    /**
     * 设置Map
     * @param value
     * @param origField
     * @param targetField
     * @param targetObject
     * @param <T>
     */
    @SuppressWarnings(
    { "rawtypes", "unchecked" })
    private static <T> void setMap(Map value, Field origField, Field targetField, T targetObject)
            throws IllegalAccessException, InstantiationException
    {
        Type origType = origField.getGenericType();
        Type targetType = targetField.getGenericType();
        if (origType instanceof ParameterizedType && targetType instanceof ParameterizedType)
        {// 泛型类型
            ParameterizedType origParameterizedType = (ParameterizedType) origType;
            Type[] origTypes = origParameterizedType.getActualTypeArguments();
            ParameterizedType targetParameterizedType = (ParameterizedType) targetType;
            Type[] targetTypes = targetParameterizedType.getActualTypeArguments();
            if (origTypes != null && origTypes.length == 2 && targetTypes != null
                    && targetTypes.length == 2)
            {// 正常泛型,查看第二个泛型是否不为基本类型
                Class clazz = (Class) origTypes[1];
                if (!isBasicType(clazz) && !clazz.equals(targetTypes[1]))
                {// 如果不是基本类型并且泛型不一致,则需要继续转换
                    Set<Map.Entry> entries = value.entrySet();
                    Map targetMap = value.getClass().newInstance();
                    for (Map.Entry entry : entries)
                    {
                        targetMap.put(entry.getKey(),
                                convertPojo(entry.getValue(), (Class) targetTypes[1]));
                    }
                    setFieldValue(targetField, targetObject, targetMap);
                    return;
                }
            }
        }
        setFieldValue(targetField, targetObject, value);
    }

    /**
     * 设置集合
     * @param value
     * @param origField
     * @param targetField
     * @param targetObject
     * @param <T>
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    @SuppressWarnings(
    { "rawtypes", "unchecked" })
    private static <T> void setCollection(Collection value, Field origField, Field targetField,
            T targetObject) throws IllegalAccessException, InstantiationException
    {
        Type origType = origField.getGenericType();
        Type targetType = targetField.getGenericType();
        if (origType instanceof ParameterizedType && targetType instanceof ParameterizedType)
        {// 泛型类型
            ParameterizedType origParameterizedType = (ParameterizedType) origType;
            Type[] origTypes = origParameterizedType.getActualTypeArguments();
            ParameterizedType targetParameterizedType = (ParameterizedType) targetType;
            Type[] targetTypes = targetParameterizedType.getActualTypeArguments();
            if (origTypes != null && origTypes.length == 1 && targetTypes != null
                    && targetTypes.length == 1)
            {// 正常泛型,查看第二个泛型是否不为基本类型
                Class clazz = (Class) origTypes[0];
                if (!isBasicType(clazz) && !clazz.equals(targetTypes[0]))
                {// 如果不是基本类型并且泛型不一致,则需要继续转换
                    Collection collection = value.getClass().newInstance();
                    for (Object obj : value)
                    {
                        collection.add(convertPojo(obj, (Class) targetTypes[0]));
                    }
                    setFieldValue(targetField, targetObject, collection);
                    return;
                }
            }
        }
        setFieldValue(targetField, targetObject, value);
    }

    /**
     * 设置枚举类型
     * @param value
     * @param origField
     * @param targetField
     * @param targetObject
     * @param <T>
     */
    @SuppressWarnings("rawtypes")
    private static <T> void setEnum(Enum value, Field origField, Field targetField, T targetObject)
            throws Exception
    {
        if (origField.equals(targetField))
        {
            setFieldValue(targetField, targetObject, value);
        } else
        {
            // 枚举类型都具有一个static修饰的valueOf方法
            Method method = targetField.getType().getMethod("valueOf", String.class);
            setFieldValue(targetField, targetObject, method.invoke(null, value.toString()));
        }
    }

    /**
     * 设置日期类型
     * @param value
     * @param targetField
     * @param targetFieldType
     * @param targetObject
     * @param <T>
     */
    @SuppressWarnings("rawtypes")
    private static <T> void setDate(Date value, Field targetField, Class targetFieldType,
            T targetObject, boolean sameType) throws IllegalAccessException
    {
        Date date = null;
        if (sameType)
        {
            date = value;
        } else if (targetFieldType.equals(java.sql.Date.class))
        {
            date = new java.sql.Date(value.getTime());
        } else if (targetFieldType.equals(java.util.Date.class))
        {
            date = new Date(value.getTime());
        } else if (targetFieldType.equals(java.sql.Timestamp.class))
        {
            date = new java.sql.Timestamp(value.getTime());
        }
        setFieldValue(targetField, targetObject, date);
    }

    /**
     * 获取适配方法
     * @param clazz
     * @param fieldName
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static Field getTargetField(Class clazz, String fieldName)
    {
        String classKey = clazz.getName();
        Map<String, Field> fieldMap = cacheFields.get(classKey);
        if (fieldMap == null)
        {
            fieldMap = new HashMap<>();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields)
            {
                if (isStatic(field))
                    continue;
                fieldMap.put(field.getName(), field);
            }
            cacheFields.put(classKey, fieldMap);
        }
        return fieldMap.get(fieldName);
    }

    /**
     * 判断数据类型是否是否为基础类型
     */
    public static boolean isBasicType(Class<?> clazz)
    {
        return clazz.isPrimitive() || basicClass.contains(clazz);
    }

    /**
     * 判断变量是否有静态修饰符static
     */
    public static boolean isStatic(Field field)
    {
        return ( Modifier.STATIC & field.getModifiers()) ==  Modifier.STATIC;
    }
}

用法:

List<StudentsDto> dtos = PojoConvertUtil.convertPojos(list, StudentsDto.class)

其中list是实体类的集合。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值