栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java对象拷贝时根据枚举自动转换属性值

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java对象拷贝时根据枚举自动转换属性值

问题描述:在copyProperties(A,B)拷贝对象时,需要将A.type(Integer)拷贝到B.type(String),但是A.type是类型的数字编码,B.type是类型的描述,通过给B.type加一个注解指定枚举类,实现在拷贝属性的时候,自动转换类型编码到类型描述并赋值B.type;

JDK版本 >= 1.8 

枚举接口定义:
package com.example.visy.test;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


public interface EnumConvert{
    //将映射关系缓存到Map中,便于快速查找
    Map map = new HashMap<>();

    //key映射道value
    default Object mapping(Object key){
        this.initMap();
        return map.get(String.valueOf(key));
    }

    default void initMap(){
        if(!map.isEmpty()){
            return;
        }
        for (EnumConvert item : getValues()) {
            map.put(String.valueOf(item.getKey()), item.getValue());
        }
    }

    Object getKey();
    // 返回的实际类型必须和目标属性的类型一致
    Object getValue();
    EnumConvert[] getValues();
}
 枚举定义:
package com.example.visy.test;

import lombok.AllArgsConstructor;
import lombok.Getter;


@Getter
@AllArgsConstructor
public enum DirectionEnum implements EnumConvert {
    TOP(1, "上"),
    DOWN(2, "下"),
    LEFt(3, "左"),
    RIGHt(4, "右");

    private final Integer code;
    private final String desc;

    @Override
    public Object getKey() {
        return code;
    }

    @Override
    public Object getValue() {
        //注意:必须和待转换的目标属性类型相同,否则不会生效
        return desc;
    }

    @Override
    public EnumConvert[] getValues() {
        return DirectionEnum.values();
    }
}
注解定义:
package com.example.visy.test;

import java.lang.annotation.*;
import java.lang.annotation.Target;


@documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EnumMapper {
    //指定枚举Class
    Class> value();
    //指定源对象中对应的属性别名(属性名相同时,无需指定alias)
    String alias() default "";
}
 拷贝工具定义:
package com.example.visy.test;

import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


public class BeanUtils {
    private static final Map> TARGET_FIELD_MAP = new HashMap<>();
    private static final Map> SOURCE_FIELD_MAP = new HashMap<>();

    public static void copyProperties(Object source, Object target) throws IllegalAccessException {
        List targetFields = getFields(target);
        if(Objects.isNull(targetFields) || targetFields.isEmpty()){
            return;
        }

        for(Field targetField: targetFields){
            Field sourceField = getField(source, targetField.getName());

            if(targetField.isAnnotationPresent(EnumMapper.class)){ //检查注解
                EnumMapper enumMapper = targetField.getAnnotation(EnumMapper.class);

                String aliasName = enumMapper.alias();
                if(Objects.nonNull(aliasName) && !aliasName.isEmpty()){
                    //指定了别名的情况,优先使用别名
                    sourceField = getField(source, aliasName);
                }

                if(Objects.isNull(sourceField)){
                    continue; //源属性为空->不拷贝
                }

                if(enumMapper.value().isEnum()){//注解中指定的Class必须是枚举
                    Enum mapper = enumMapper.value().getEnumConstants()[0]; //随便取一个枚举值
                    if(mapper instanceof EnumConvert){//枚举必须实现了EnumConvert接口
                        Object oldValue = sourceField.get(source);
                        //转换后拷贝
                        Object newValue = ((EnumConvert) mapper).mapping(oldValue);
                        if(Objects.nonNull(newValue) && targetField.getType().equals(newValue.getClass())){
                            targetField.set(target, newValue);
                            continue;
                        }
                    }
                }
            }

            if(Objects.isNull(sourceField)){
                continue; //源属性为空->不拷贝
            }

            if(!targetField.getType().equals(sourceField.getType())){
                continue; //两个属性类型不一致->不拷贝
            }

            //拷贝
            targetField.set(target, sourceField.get(source));
        }

    }

    private static List getFields(Object obj){
        Class clazz = obj.getClass();
        String key = clazz.getName();
        List fields = TARGET_FIELD_MAP.get(key);
        if(Objects.isNull(fields)){
            Field[] fieldArray = clazz.getDeclaredFields();
            Field.setAccessible(fieldArray, true);
            fields = Arrays.stream(fieldArray).collect(Collectors.toList());
            TARGET_FIELD_MAP.put(key, fields);
        }
        return fields;
    }

    private static Field getField(Object obj, String fieldName){
        Class clazz = obj.getClass();
        String key = clazz.getName();
        Map map = SOURCE_FIELD_MAP.get(key);
        if(Objects.isNull(map)){
            Field[] fieldArray = clazz.getDeclaredFields();
            Field.setAccessible(fieldArray, true);
            map = Arrays.stream(fieldArray).collect(Collectors.toMap(Field::getName, Function.identity()));
            SOURCE_FIELD_MAP.put(key, map);
        }
        return map.get(fieldName);
    }
}
源对象:
package com.example.visy.test;

import lombok.Data;


@Data
public class Source {
    private Integer top = 1;
    private Integer down = 2;
    private Integer left = 3;
    private Integer right = 4;
    private Integer center = 5;

    private String name = "张三";
}
 目标对象:
package com.example.visy.test;

import lombok.Data;


@Data
public class Target {
    //和Source.top同名
    //Long和枚举的getValue()的实际类型(String)不匹配
    //Long和Source.top类型(Integer)不匹配
    //结果为:null
    @EnumMapper(DirectionEnum.class)
    private Long top;

    //和Source.down同名
    //Integer和枚举的getValue()的实际类型(String)不匹配
    //Integer和Source.down类型(Integer)匹配
    //结果为:2
    @EnumMapper(DirectionEnum.class)
    private Integer down;

    //和Source.left同名
    //String和枚举的getValue()的实际类型(String)匹配
    //结果为:"左"
    @EnumMapper(DirectionEnum.class)
    private String left;

    //和Source.right不同名,但指定了别名"right"
    //String和枚举的getValue()的实际类型(String)匹配
    //结果为:"右"
    @EnumMapper(value = DirectionEnum.class, alias = "right")
    private String rightStr;

    //无需转换的属性只要同名且类型一致就可正常拷贝
    private String name;
}
测试类:
package com.example.visy.test;


public class Test {
    public static void main(String[] args) throws Exception{
        Source source = new Source();
        Target target = new Target();

        BeanUtils.copyProperties(source, target);

        System.out.println(target);
    }
}
打印结果:
 Target(top=null, down=2, left=左, rightStr=右, name=张三)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/709217.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号