写点什么

Java 通过反射注解赋值

作者:Jeremy Lai
  • 2022-12-01
    广东
  • 本文字数:3104 字

    阅读完需:约 10 分钟

前段时间,领导分配一个统计销售区域汇总的数据,解决方案使用到了反射获取注解,通过注解获取属性或者设置字段属性。

问题描述

查询公司列表,分别是公司 id、区域 id、区域名称:



创建公司类Company


public class Company {
public Company(Integer id, Integer areaId, String areaName) { this.id = id; this.areaId = areaId; this.areaName = areaName; }
/** * 公司id */ private Integer id;
/** * 区域id */ private Integer areaId;
/** * 区域名称 */ private String areaName; // 省略get/set方法
}
复制代码

最终解决

要求汇总各个区域公司数量,得到如下汇总:



最终区域实体AreaStatistic:


public class AreaStatistic {
@ColumnProperty("华东大区") private Integer eastChina = 0;
@ColumnProperty("华东id") private Integer eastChinaId;
@ColumnProperty("华南大区") private Integer southChina = 0;
@ColumnProperty("华南id") private Integer southChinaId;
@ColumnProperty("华北大区") private Integer northChina = 0;
@ColumnProperty("华北id") private Integer northChinaId;
@Override public String toString() { return "AreaStatistic{\n" + "华东Id=" + eastChinaId + ",华东=" + eastChina + ", \n华南Id=" + southChinaId + ", 华南=" + southChina + ", \n华北Id=" + northChinaId + ", 华北=" + northChina + '}'; } // 省略get/set方法}
复制代码

if/else 普通解法

AreaStatistic areaStatistic = new AreaStatistic();for (Company company:companyList) {    String areaName = company.getAreaName();    if ("华南".equals(areaName)) {        areaStatistic.setSouthChina(areaStatistic.getSouthChina()+1);        areaStatistic.setSouthChinaId(company.getAreaId());    } else if ("华北".equals(areaName)) {        areaStatistic.setNorthChina(areaStatistic.getNorthChina()+1);        areaStatistic.setNorthChinaId(company.getAreaId());    } else if ("华东".equals(areaName)) {        areaStatistic.setEastChina(areaStatistic.getEastChina()+1);        areaStatistic.setEastChinaId(company.getAreaId());    }}
复制代码


输出:


华东Id=3,华东=2, 华南Id=1, 华南=1, 华北Id=2, 华北=2
复制代码


这种做法的缺点:


  • 要写大量的条件判断语句,非常的繁琐。

  • 增加和减少统计区域,都要修改代码。


针对上面的缺点,使用反射获取注解,通过注解获取属性赋值。

通过反射注解赋值属性

解题思路

  1. 遍历公司列表,获取到区域 id 和区域名称。

  2. 创建自定义注解@ColumnProperty:


@Target({ElementType.METHOD, ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)public @interface ColumnProperty {
String value() default "";
}
复制代码


  1. 通过反射获取属性,然后遍历字段属性获取注解。


AreaStatistic字段属性上添加注解:


@ColumnProperty("华东大区")private Integer eastChina = 0;
@ColumnProperty("华东id")private Integer eastChinaId;
@ColumnProperty("华南大区")private Integer southChina = 0;
@ColumnProperty("华南id")private Integer southChinaId;
@ColumnProperty("华北大区")private Integer northChina = 0;
@ColumnProperty("华北id")private Integer northChinaId;
复制代码


  1. 通过反射获取属性,然后遍历字段属性获取注解。


Class staticClass = areaStatistic.getClass();Field[] fields = staticClass.getDeclaredFields();for (Field field : fields) {    ColumnProperty property = field.getAnnotation(ColumnProperty.class);    String value = property.value();}
复制代码


  1. 匹配区域名称和字段属性,比如遍历公司区域是华东,就遍历到华东大区注解对应的字段,并赋值或者获取字段值。


if (value != null) {    int indexOf = value.indexOf("大区");    if (indexOf != -1 && value.length() == 4) {        if (areaName.equals(value.substring(0,2))) {            field.setAccessible(true);            field.set(areaStatistic,(Integer) field.get(areaStatistic) + 1);          }     }}
复制代码


  1. 区域 id 赋值也是相同的解题思路。


根据上面的思路,有如下代码汇总


// 遍历公司for (Company company:companyList) {  setAreaProperty(areaStatistic2,company.getAreaName(),company.getAreaId());}
private void setAreaProperty(AreaStatistic areaStatistic,String areaName,Integer areaId) throws IllegalAccessException { // 反射获取注解 Class staticClass = areaStatistic.getClass(); Field[] fields = staticClass.getDeclaredFields(); for (Field field : fields) { ColumnProperty property = field.getAnnotation(ColumnProperty.class); String value = property.value(); if (value != null) { int indexOf = value.indexOf("大区"); if (indexOf != -1 && value.length() == 4) { // 匹配到注解属性并赋值 if (areaName.equals(value.substring(0,2))) { field.setAccessible(true); field.set(areaStatistic,(Integer) field.get(areaStatistic) + 1); for (Field idField : fields) { ColumnProperty idProperty = idField.getAnnotation(ColumnProperty.class); String idValue = idProperty.value(); if (idValue.equals(areaName+"id")) { idField.setAccessible(true); idField.set(areaStatistic,areaId); break; } } break; } } } }}
复制代码


输出:


华东Id=3,华东=2, 华南Id=1, 华南=1, 华北Id=2, 华北=2
复制代码

汇总某些字段的和

上面算出各个区域的汇总之后,还要算出全部区域的总和,这里还是使用到注解,把属性字段包含大区都累加起来:


AreaStatistic statistic = new AreaStatistic();statistic.setEastChina(2);statistic.setNorthChina(3);statistic.setSouthChina(1);int sum = 0;Class staticClass = statistic.getClass();Field[] fields = staticClass.getDeclaredFields();for (Field field : fields) {    ColumnProperty property = field.getAnnotation(ColumnProperty.class);    String value = property.value();    if (value.indexOf("大区") != -1) {        field.setAccessible(true);        sum += field.get(statistic) == null ? 0 : (Integer) field.get(statistic);    }}System.out.println(sum);
复制代码


输出结果:


6
复制代码

总结

  • 自定义注解,通过反射获取注解

  • 通过匹配注解值,获取或者复制对应的字段属性。


赋值主要代码为:


field.setAccessible(true);field.set(Model,value);
复制代码

源码地址

https://github.com/jeremylai7/java-codes/blob/master/basis/src/main/java/reflect/SetValueByAnnotation.java

用户头像

Jeremy Lai

关注

还未添加个人签名 2018-02-12 加入

还未添加个人简介

评论

发布
暂无评论
Java通过反射注解赋值_解决问题_Jeremy Lai_InfoQ写作社区