场景:
注意: 不涉及任何业务逻辑
在系统间接口调用,存在各种对象的转换, 这里指的是将 A 类中的 a 的值,赋值给 B 类中的 b . 然后自己系统的数据库存的是 B。
最恐怖的是, 如果进行数据下载的时候, 我们还要把 B 原封不动转换成 A .供其他系统调用.
如下图:
一个完整的 Student 类 ,由3个不同的类的字段值拼凑得到。
然后进行数据下载的时候, 还是把 Student中某些指定的属性,转换成映射的对象.
这里只是模拟一下
SubjectInfo subjectInfo = new SubjectInfo("语文","80.36");
UserInfo userInfo = new UserInfo("英旭","30","2020-07-08 12:25:12",subjectInfo);
EmailInfo email =new EmailInfo("inxu","@163.com",20);
Student student = new Student();
student.setName(userInfo.getUname());
student.setSubName(userInfo.getSubjectInfo().getName());
student.setEmail(email.getAddr());
问题: 如果字段多了呢??
眼要写瞎了. 我太难了 o(╥﹏╥)o
/**
* @program: springBootStudy
* @Date: 2020/7/10 20:54
* @Author: Inxu
* @Description:
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface AimField {
/*目标对象的属性名*/
String value();
/*目标对象的属性类型 基本类型 */
Class type();
}
/**
* @program: springBootStudy
* @Date: 2020/7/10 20:49
* @Author: Inxu
* @Description:
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.TYPE,ElementType.FIELD})
public @interface AimObject {
Class value() ;
}
/**
* @program: springBootStudy
* @Date: 2020/7/11 13:36
* @Author: Inxu
* @Description:
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface AimOther {
/*目标对象的属性名*/
String value();
/*目标对象的属性类型 基本类型 */
Class type();
/*映射的指定类*/
Class clazz();
}
完整代码如下:
/**
* @program: springBootStudy
* @Date: 2020/7/10 20:59
* @Author: Inxu
* @Description: 对象属性复制类
*/
public class BeanCopyUtil {
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static final String DATE="Date";
private static final String LOCAL_DATE_TIME="LocalDateTime";
/**
* 对象属性赋值方法
* 将 S 中的属性值,按照属性名的对应关系, 复制到 T 中
* @param s 源对象数据
* @param t 目标对象 类的实例
* @param 泛型
* @param 泛型
* @return
* @throws IllegalAccessException
* @throws InstantiationException
* @throws ParseException
* @throws NoSuchObjectException
*/
public static <S,T> T copy(S s,T t) throws IllegalAccessException,
InstantiationException, ParseException,
NoSuchObjectException, NoSuchMethodException,
NoSuchFieldException, InvocationTargetException {
Class<?> clazz = s.getClass();
AimObject type_AimObject = clazz.getAnnotation(AimObject.class);
Class type_Class = type_AimObject.value();
if( !type_Class.isAssignableFrom(t.getClass())){
throw new NoSuchObjectException("注解的映射类与目标类不匹配.");
}
// 获取要映射的类的实例
Object newInstance =null;
if(null ==t){
newInstance = type_Class.newInstance();
}else {
newInstance=t;
}
// 1 : 反射得到 源对象的属性列表
Field[] s_Fields = clazz.getDeclaredFields();
for (Field sField : s_Fields) {
sField.setAccessible(true);
// 2: 获取源对象中, 属性上需要映射的类
AimObject field_AimObject = sField.getAnnotation(AimObject.class);
if(null != field_AimObject){
// 如果源对象中的 对象属性 的映射类 和源对象映射的类一致, 继续延用当前的 对象(newInstance)
if(field_AimObject.value().isAssignableFrom(type_Class)){
copy(sField.get(s),newInstance);
}else {
continue;
}
field_AimObject=null;
}
// 3: 获取源对象中属性的映射
AimField aimField = sField.getAnnotation(AimField.class);
if(null == aimField && null == field_AimObject){
continue;
}
// Class field_orm_other_obj = aimField.clazz();
// 获取目标类的属性名
String target_Field = aimField.value();
// 获取目标类的 属性类型
Class target_Field_Type = aimField.type();
// 获取源对象 的 属性值 , 最终把它赋值给目标类的属性 target_Field
Object o = sField.get(s);
if(null == o) {
continue;
}
/*获取源对象属性的类型*/
Class<?> s_field_Type = sField.getType();
// 赋值
setTargetFieldValueByNameAndValue(newInstance,target_Field,target_Field_Type,o,s_field_Type);
}
return t;
}
/**
* 对象属性赋值方法
* 将 S 属性中的 @AimOther注解 ,根据属性名和指定的类, 复制到 T
* @param s 源对象
* @param t 目标对象
* @param 泛型
* @param 泛型
* @return
* @throws IllegalAccessException
* @throws InstantiationException
* @throws NoSuchObjectException
* @throws NoSuchMethodException
* @throws NoSuchFieldException
* @throws ParseException
* @throws InvocationTargetException
*/
public static <S,T> T copyPartByAimOther(S s ,T t) throws IllegalAccessException,
InstantiationException, NoSuchObjectException,
NoSuchMethodException, NoSuchFieldException, ParseException,
InvocationTargetException {
if(null == s || null == t){
throw new NullPointerException("源对象 或者 目标对象 不能为空.");
}
Field[] fields = s.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
AimOther type_Aim_other = field.getAnnotation(AimOther.class);
if(null == type_Aim_other){
continue;
}
Class type_Class = type_Aim_other.clazz();
if(!type_Class.isAssignableFrom(t.getClass())){
continue;
}
String target_Field = type_Aim_other.value();
Class target_Field_Type = type_Aim_other.type();
Class<?> s_field_Type = field.getType();
Object o = field.get(s);
if(null == o) {
continue;
}
setTargetFieldValueByNameAndValue(t,target_Field,target_Field_Type,o,s_field_Type);
}
return t;
}
/**
*
* @param s
* @param t
* @param
* @param
* @return
* @throws IllegalAccessException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws ParseException
* @throws InstantiationException
* @throws NoSuchObjectException
* @throws NoSuchFieldException
*/
public static <S,T> T copyPartByAimObjectOnField(S s ,T t) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException, ParseException, InstantiationException, NoSuchObjectException, NoSuchFieldException {
if(null == s || null == t){
throw new NullPointerException("源对象 或者 目标对象 不能为空.");
}
Field[] fields = s.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
// 获取源对象中, 属性上需要映射的类
AimObject field_AimObject = field.getAnnotation(AimObject.class);
if(null == field_AimObject){
continue;
}
t=copy(field.get(s),t);
}
return t;
}
/**
* 为目标类的属性 通过属性名赋值
* @param t 目标类
* @param fieldName 目标类的变量名
* @param target_Field_Type 变量类型
* @param value 源数据
* @param s_field_Type 源数据 类型
* @param 泛型
* @return
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws NoSuchFieldException
*/
public static <T> void setTargetFieldValueByNameAndValue(T t ,
String fieldName,
Class target_Field_Type,
Object value,
Class<?> s_field_Type) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException, ParseException {
Field field = t.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
// 如果与映射属性的类型不一致, 转换成目标属性的类型
if(!target_Field_Type.isAssignableFrom(s_field_Type) ){
// 时间转 String
if((DATE).equals (s_field_Type.getSimpleName())|| s_field_Type.getSimpleName().equals(LOCAL_DATE_TIME)){
value=covertDate2String(s_field_Type.getSimpleName(),value);
}else {
value= convertValueByType(target_Field_Type,value.toString());
}
}
field.set(t,value);
}
/**
* 将 值 进行类型转换
* @param target_Field_Type 目标类变量的类型
* @param val 值
* @return
* @throws ParseException
*/
public static Object convertValueByType(Class target_Field_Type ,String val) throws ParseException {
String typeName = target_Field_Type.getSimpleName();
Object o =null;
switch (typeName){
case "Integer":
o=Integer.parseInt(val);break;
case "Long":
o=Long.parseLong(val);break;
case "Double":
o=Double.parseDouble(val);break;
case "Short":
o= Short.parseShort(val); break;
case "Byte":
o= Byte.parseByte(val);break;
case "Date":
o=SIMPLE_DATE_FORMAT.parse(val);
case "LocalDateTime":
o= LocalDateTime.parse(val,DATE_TIME_FORMATTER);break;
default:
o=val;break;
}
return o;
}
public static Object covertDate2String(String typeName,Object value){
Object o =null;
switch (typeName){
case "Date":
Date date =(Date)value;
o=SIMPLE_DATE_FORMAT.format(date);
break;
case "LocalDateTime":
LocalDateTime parse=(LocalDateTime)value;
o= parse.format(DATE_TIME_FORMATTER);
break;
default:
o=value;break;
}
return o;
}
}
/**
* @program: springBootStudy
* @Date: 2020/7/10 21:30
* @Author: Inxu
* @Description:
*/
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
@AimObject(Student.class)
public class UserInfo {
@AimField(value = "name",type = String.class)
private String uname;
@AimField(value = "age",type = Integer.class)
private String uage;
@AimField(value = "dateTime",type = LocalDateTime.class)
private String udate;
@AimObject(Student.class)
private SubjectInfo subjectInfo;
}
/**
* @program: springBootStudy
* @Date: 2020/7/10 23:46
* @Author: Inxu
* @Description:
*/
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
@AimObject(Student.class)
public class SubjectInfo {
@AimField(value = "subName",type = String.class)
private String name;
@AimField(value = "score",type = Double.class)
private String score;
}
/**
* @program: springBootStudy
* @Date: 2020/7/11 13:17
* @Author: Inxu
* @Description:
*/
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
@AimObject(Student.class)
public class EmailInfo {
@AimField(value = "email",type = String.class)
private String addr;
@AimField(value = "emailIP",type = String.class)
private String ip;
private Integer times;
}
/**
* @program: springBootStudy
* @Date: 2020/7/10 21:28
* @Author: Inxu
* @Description:
*/
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
@AimObject(UserInfo.class)
public class Student {
@AimField(value = "uname",type = String.class)
private String name;
@AimField(value = "uage",type = String.class)
private Integer age;
@AimField(value = "udate",type = String.class)
private LocalDateTime dateTime;
@AimOther(value = "name",type = String.class,clazz = SubjectInfo.class)
private String subName;
@AimOther(value = "score",type = String.class,clazz = SubjectInfo.class)
private Double score;
@AimOther(value = "addr",type = String.class,clazz = EmailInfo.class)
private String email;
@AimOther(value = "ip",type = String.class,clazz = EmailInfo.class)
private String emailIP;
}
效果如下: 基本实现,把终端提交的原数据转换成自身数据库需要的数据格式,然后如果需要的话,在转换成终端需要的数据格式。
不支持 集合 ,仅支持对象间基本类型的转换。
可能有BUG。还请谅解, 修改后,望告知 [email protected]. 谢谢!!!