最近做一个项目需要将map 键值对为中文的数据映射到正常一点的java对象中,鄙人觉得直接用中文名写在javaBean属性中有点low,感觉对不起自己几年的工作做经验,于是想到了利用注解和反射的特性将map信息映射为对象属性
实现过程如下
- 1 定义注解
import java.lang.annotation.*;
/**
* 通过注解名称将数据映射到对象中
* @author ccbobe
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface RowField{
String name();
}
- 2 核心解析工具方法
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author ccbobe
* 对象属性与注解映射及其设置映射value
*/
public class RowFieldUtils {
/**
* 缓存Class字段信息
*/
private static Map<Class<?>, Map<String, String>> CACHE_CLASS_INFO = new ConcurrentHashMap(32);
/**
* 获取指定类的映射信息
* @param clazz
* @param <T>
* @return 返回映射信息
*/
public static <T> Map<String,String> getBeanMetaByRowField(Class<T> clazz){
Map<String, String> map = CACHE_CLASS_INFO.get(clazz);
if (map!=null && !map.isEmpty()){
return CACHE_CLASS_INFO.get(clazz);
}
Map<String, String> headerData = new HashMap<>();
Class<?> cls = clazz;
//遍历所有父类字节码对象
while (cls != Object.class) {
Field[] fields = cls.getDeclaredFields();
List<Field> list = new ArrayList<>();
list.addAll(Arrays.asList(fields));
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
RowField fieldAnnotation = field.getDeclaredAnnotation(RowField.class);
if (fieldAnnotation != null) {
field.setAccessible(true);
String name = field.getName();
headerData.put(fieldAnnotation.name(),name);
} else {
String name = field.getName();
headerData.put(name,name);
}
}
// 遍历所有父类字节码对象
cls = cls.getSuperclass();
}
CACHE_CLASS_INFO.put(clazz,headerData);
return headerData;
}
/**
* 将map数据映射到指定对象中
* @param mapData
* @param clazz
* @param <T>
* @return
*/
public static <T> T mapToBean(Map<String,Object> mapData,Class<T> clazz){
T instance = null;
try {
instance = clazz.newInstance();
Map<String, String> meta = getBeanMetaByRowField(clazz);
for(Map.Entry<String, Object> entry : mapData.entrySet()){
String fieldName = entry.getKey();
Object dataValue = entry.getValue();
//存在属性则设置
if (meta.containsKey(fieldName)){
setValue(instance,meta.get(fieldName),dataValue);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
/**
* @param obj
* @param fieldName
* @param value
* @return
* @throws
* @Description 设置 属性值
*/
private static void setValue(Object obj, String fieldName, Object value){
try {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 3 测试用例
(1)需要映射的java对象信息
import lombok.Data;
@Data
public class SystemData {
/**
* 地区名称
*/
@RowField(name = "地区")
private String address;
/**
* 系统名称
*/
@RowField(name = "系统")
private String systemName;
/**
* 可读时间
*/
@RowField(name = "可读时间")
private String readTime;
}
(2)需要映射的map对象信息
Map maps = new HashMap();
maps.put("地区","图书馆管理系统");
maps.put("系统","图书馆管理系统");
maps.put("可读时间","图书馆管理系统");
maps.put("code","12345688");
(3)测试并显示
SystemData systemData = RowFieldUtils.mapToBean(maps, SystemData.class);
System.out.println(systemData.toString());
(4) 最终输出测试信息
SystemData(address=图书馆管理系统, systemName=图书馆管理系统, readTime=图书馆管理系统)
总结: 本java类主要说明利用了反射和注解相关java知识来支撑解析java文件使用,如果需要想支持多种类型,希望读者自行完善。