目录
创建注解文件
添加注解
@Target(ElementType.FIELD)//只能定义在字段上
// @Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//在运行时有效
public @interface DynamicAnnotation {
}
添加想要的业务属性
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DynamicAnnotation {
String description();
String field();
//值是否需要再次处理
boolean isValue();
int sort();
}
具体使用
@DynamicAnnotation(description = "车辆所在省份", field = "carProvinceName", isValue = false, sort = 6)
public String carProvinceName;
获取属性信息
/**
* 获取某类实体的DynamicAnnotation注解信息
* 返回map
*
* @param object
* @param headerMap
* @return
*/
private <T> void getAnnotationMsg(T object, Map<String, String> headerMap) {
Map<Integer, String> map = new HashMap();
for (Field field : object.getClass().getFields()) {
//getDeclaredFields只能取到子类属性,不包含父类属性
//判断该字段是否存在DynamicAnnotation注解
if (field.isAnnotationPresent(DynamicAnnotation.class)) {
DynamicAnnotation myAnnotation = field.getAnnotation(DynamicAnnotation.class);
System.out.println("注解属性1:["+myAnnotation.field()+"],注解属性1:["+myAnnotation.description()+"]");
}
}
}
获取属性和字段值
data.stream().forEach(a -> {
Map<String, Object> dataMap = new LinkedHashMap<>();
for (Field field : a.getClass().getDeclaredFields()) {
//判断该字段是否存在MyAnnotation注解
if (field.isAnnotationPresent(DynamicAnnotation.class)) {
field.setAccessible(true);
DynamicAnnotation myAnnotation = field.getAnnotation(DynamicAnnotation.class);
// ((AnnotationInvocationHandler) ((Proxy) myAnnotation).h).memberValues
System.out.println("字段:["+myAnnotation.field()+"],字段值:["+field.get(a)+"]");
}
}
注意事项
1.注意public和private的区别:getDeclaredFields()和getFields()的区别。
后者能取到继承的父类属性
2.如果,需要反射的类中有继承关系,顺序会按照先子类后父类的关系进行反射;
如果要指定顺序,需要新加一个排序的属性
优化方案
以上为我的初步方案,代码审核时候,领导给了建议,针对isValue字段可以进一步处理,搞一个
数据转换器,比如:时间类型转年月日,布尔转是否等,给了我灵感,于是进行了一下更改。
首先,isValue中自定义属性之前规定的是布尔类型,改为枚举类
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DynamicAnnotation {
String description();
String field();
/**
* 处理值
*
* @return
*/
DynamicValueEnum isValue() default DynamicValueEnum.NULL;
int sort();
}
枚举类
@AllArgsConstructor
@Getter
public enum DynamicValueEnum {
NULL,
BOOL_HANDLE,
OUTSIDE_HANDLE;
}
在处理非必要填写的属性时候,可以用default关键字给一个默认值,这样在使用自定义注解时
候,可以忽略对此属性的赋值,使用如下:
@DynamicAnnotation(description = "定位是否与经销商所在地一致", field = "isSame", isValue = DynamicValueEnum.BOOL_HANDLE, sort = 8)
public boolean isSame;
@DynamicAnnotation(description = "报终端时间", field = "alarmPermanent", sort = 9)
public String alarmPermanent;
具体的类型值处理,在反射里进行了
/**
* 获取某字段值
*
* @param object
* @param dataMap
* @param <T>
*/
private <T> void getObjectFiledValue(T object, Map<String, Object> dataMap) {
try {
for (Field field : object.getClass().getFields()) {
if (field.isAnnotationPresent(DynamicAnnotation.class)) {
field.setAccessible(true);
DynamicAnnotation myAnnotation = field.getAnnotation(DynamicAnnotation.class);
//字段与value放入map中
if (myAnnotation.isValue() == DynamicValueEnum.NULL) {
dataMap.put(myAnnotation.field(), field.get(object));
} else if (myAnnotation.isValue() == DynamicValueEnum.BOOL_HANDLE) {
dataMap.put(myAnnotation.field(), (boolean) field.get(object) ? "是" : "否");
}
}
}
} catch (IllegalAccessException e) {
return;
}
}