一:编写目的
1.解决问题:
map的key值与实体类的字段名对应,map的value值与实体类的字段值对应,实现map与实体类互转
2.使用场景
接口传过来的是json字符串,我们现在需要转换为实体类对象。
公共类给我们的是实体类,需要转化为json格式网络传输
3.使用技术:
java 反射,java 注解
不需要使用jar包
jdk版本:个人使用的jdk1.8,但是这段代码没有使用jdk1.8的新特性,语法糖应该支持
二、呈现的效果(测试代码)
实体类
首先定义一个实体类:
这个实体类中有两个字段,name,key
同时,实体类中,重写toString方法,输出两个字段
public class Student {
@Mkey
private String name;
@Mkey
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Student [name=" + name + ", id=" + id + "]";
}
}
main测试类
测试类尝试了,将map转为实体类,然后再转为map,然后控制台打印:
import java.util.HashMap;
import java.util.Map;
public class Client {
public static void main(String[] args) {
//定义一个map
Map<String,Object> map=new HashMap();
map.put("id", 1);
map.put("name", "zhangsan");
//将map转换为实体类
Student stu=MapConvert.toObject(map, Student.class);
//输出实体类
System.out.println(stu);
//将实体类转换为map,输出
System.out.println(MapConvert.toMap(stu));
}
}
控制台打印结果:
第一行是实体类的值,第二行是map的值(测试成功)
Student [name=zhangsan, id=1]
{name=zhangsan, id=1}
三、设计思路与实现代码
1定义注解
定义注解的目的是为了在转换时,知道要转换哪些字段,比如在实体类中定义了LOG、序列化字段等一般是不需要放到map中,所以在实体类中,需要标明哪些字段是需要塞到map中。有时会发现,实体类中的字段名可能与map中的key值不同,那这样就需要自定义key值,如果没有自定义,那么默认为字段名与map中的key一致。
import java.lang.annotation.*;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Mkey {
//map中的key值,如果value()为空,那么默认实体类的字段名为map中的key值
String value() default "";
}
2.转换类(最重要的类)
说明见代码注解
为了方便使用者使用或者阅读这段代码,尽量每行加上注解(代码命名或许不太规范)
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class MapConvert {
/**
* map转为实体类
* @param map
* @param cla 需要被转的实体类的类型
* @return 实体类
*/
public static <T> T toObject(Map map, Class<T> cla) {
T obj = null;
try {
//反射实例化实体类
obj = cla.newInstance();
} catch (ReflectiveOperationException e) {
// 打印异常日志
}
//如果实例化失败,直接返回null
//如果map是空的,直接返回空的实体类
if (obj != null && map != null && !map.isEmpty()) {
//获得实体类的所有字段
Field[] fields = cla.getDeclaredFields();
//遍历这些字段
for (Field field : fields) {
//判断字段是否被加上了注解,如果没有,就直接跳过
if (field.isAnnotationPresent(Mkey.class)) {
try {
//获得注解
Mkey anno = field.getAnnotation(Mkey.class);
//获得注解的value值
String key = anno.value();
//如果注解的value值为空,那么默认实体类的字段名为map中的key值
if (key == null || "".equals(key)) {
key = field.getName();
}
//获得map的value值
Object v = map.get(key);
//如果map中没有这个值,跳过
if (v != null) {
//获得实体类字段类型
Class<?> type = field.getType();
field.setAccessible(true);
//判断map获得的value的类型是否和字段的类型一致或父子类关系
if (v.getClass().isAssignableFrom(type)) {
field.set(obj, v);
}
//加上一些需要强转的基本数据类型,后面还有float、double等等需要加上
else if (type == Integer.class || type == int.class) {
int value = 0;
try {
value = Integer.parseInt(String.valueOf(map.get(key)));
} catch (Exception e) {
;
}
field.set(obj, value);
}
}
} catch (IllegalAccessException e) {
}
}
}
}
return obj;
}
/**
* 实体类转为map
* @param obj
* @return
*/
public static Map<String, Object> toMap(Object obj) {
//直接使用HashMap
Map<String, Object> result = new HashMap<String, Object>();
if (obj != null) {
//获得所有字段
Field[] fields = obj.getClass().getDeclaredFields();
//遍历字段
for (Field field : fields) {
//判断有没有加上注解
if (field.isAnnotationPresent(Mkey.class)) {
try {
//获得注解
Mkey anno = field.getAnnotation(Mkey.class);
//根据注解获得map的key值
String key = anno.value();
if (key == null || "".equals(key)) {
key = field.getName();
}
field.setAccessible(true);
//赛值
result.put(key, field.get(obj));
} catch (IllegalAccessException e) {
// 打日志
}
}
}
}
return result;
}
}