Calculate the total number of certain fields using custom annotations and reflection

Achieved results

Insert image description here

Organize ideas

the whole idea

  1. Annotations can identify which fields are used for calculations
  2. Use reflection to take out the values ​​of the fields that need to be calculated and add them up.

The knowledge points you need to know here include annotations and java reflection. Use reflection to instantiate objects, get values, and assign values.

code design

  1. Create an annotation that identifies the fields that need to be calculated.
  2. Get fields of a certain type (javabeans that need to be calculated in total), loop over the fields and get the annotated fields.
  3. Use the function of calculating the total in java8, pass in the fields that need to be calculated, and calculate the total.
  4. Use reflection instantiation to create a new object, assign the total calculated above, and return this object.

Code

core code

// 获取字段列表
Class c;
List<Field> fields = Arrays.stream(c.getDeclaredFields()).collect(Collectors.toList());
// 根据类型实例化队形
Constructor constructor = c.getConstructor();
obj = constructor.newInstance();
// 获取字段的注解
FieldTotalAnnotation annotation = field.getAnnotation(FieldTotalAnnotation.class);
// 根据方法名获取属性值
String getMethodName = "get"
        + propertyName.substring(0, 1).toUpperCase()
        + propertyName.substring(1);
Method method = data.getMethod(getMethodName);
Object value = method.invoke(v);
// 根据方法名为属性赋值
String setMethodName = "set"
                + propertyName.substring(0, 1).toUpperCase()
                + propertyName.substring(1);
Class<?> resType = c.getDeclaredField(propertyName).getType();
            Method method = c.getMethod(setMethodName, resType);
  method.invoke(obj, (String) value);

Complete code

@Slf4j
public class StatisticTotalUtil {
    
    
    /**
     * @param statisticsTotalList 需要计算的列表
     * @param c                   需要创建新对象的类型
     * @return 返回一个新的对象 里面是各个字段的总数
     */
    public static <T> T getTotalCount(List<T> statisticsTotalList, Class c) {
    
    
        statisticsTotalList.stream().mapToInt(v -> {
    
    
            return (int) new Object();
        });
        // 获取字段列表
        List<Field> fields = Arrays.stream(c.getDeclaredFields()).collect(Collectors.toList());
        // 创建总计对象
        Object res = new Object();
        try {
    
    
            Constructor constructor = c.getConstructor();
            res = constructor.newInstance();
        } catch (NoSuchMethodException e) {
    
    
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
    
    
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
    
    
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
    
    
            throw new RuntimeException(e);
        }
        Object finalRes = res;
        fields.stream().forEach(field -> {
    
    
            FieldTotalAnnotation annotation = field.getAnnotation(FieldTotalAnnotation.class);
            if (ObjectUtil.isEmpty(annotation)) {
    
    
                return;
            }
            Class<?> type = field.getType();
            String propertyName = field.getName();
            if (ObjectUtil.isNotEmpty(annotation) && annotation.value() && !annotation.isTotalName()) {
    
    
                if (type != Integer.class) {
    
    
                    log.info("不是[Integer]类型不予累加");
                    return;
                }
                Object sum = statisticsTotalList.stream().mapToInt(v -> {
    
    
                    Class data = v.getClass();
                    try {
    
    
                        // 根据属性名称就可以获取其get方法
                        String getMethodName = "get"
                                + propertyName.substring(0, 1).toUpperCase()
                                + propertyName.substring(1);
                        Method method = data.getMethod(getMethodName);
                        Object value = method.invoke(v);
                        return (int) Optional.ofNullable(value).orElse(0);
                    } catch (NoSuchMethodException e) {
    
    
                        throw new RuntimeException(e);
                    } catch (InvocationTargetException e) {
    
    
                        throw new RuntimeException(e);
                    } catch (IllegalAccessException e) {
    
    
                        throw new RuntimeException(e);
                    }
                }).sum();
                setPropertyValue(propertyName, finalRes, c, type, sum);
            } else {
    
    
                log.info("没有统计注解标识或者不是integer类型");
            }
            if (ObjectUtil.isNotEmpty(annotation) && annotation.isTotalName()) {
    
    
                if (type != String.class) {
    
    
                    log.info("不是[String]类型不予累加");
                    return;
                }
                setPropertyValue(propertyName, finalRes, c, type, "总计");
            } else {
    
    
                log.info("没有统计注解标识或者不是String类型");
            }

        });
        return (T) res;
    }

    /**
     * @param propertyName 某字段的属性名称
     * @param finalRes     用传过来的对象类型创建的对象
     * @param c            需要创建新对象的类型
     * @param type         需要赋值的字段类型
     * @param value        计算过后的值
     */
    private static void setPropertyValue(String propertyName, Object finalRes, Class c, Class type, Object value) {
    
    
        String setMethodName = "set"
                + propertyName.substring(0, 1).toUpperCase()
                + propertyName.substring(1);
        try {
    
    
            Class<?> resType = c.getDeclaredField(propertyName).getType();
            Method method = c.getMethod(setMethodName, resType);
            if (type == Integer.class) {
    
    
                method.invoke(finalRes, (int) value);
            }
            if (type == String.class) {
    
    
                method.invoke(finalRes, (String) value);
            }
        } catch (NoSuchMethodException e) {
    
    
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
    
    
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
    
    
            throw new RuntimeException(e);
        } catch (NoSuchFieldException e) {
    
    
            throw new RuntimeException(e);
        }
    }

}
@Documented
@Target(ElementType.FIELD)// 作用在字段上
@Retention(RetentionPolicy.RUNTIME)// 运行时有效
public @interface FieldTotalAnnotation {
    
    
    @ApiModelProperty("是否需要统计")
    boolean value() default true;
    @ApiModelProperty("是否需要加上”合计“两个字")
    boolean isTotalName() default false;
}
@Test
public void statisticTotal() {
    
    
    List<TMessageTemplateStatistic> resList = new ArrayList<>();
    TMessageTemplateStatistic s1 = new TMessageTemplateStatistic();
    s1.setTotalCount(4);
    s1.setMailCount(5);
    TMessageTemplateStatistic s2 = new TMessageTemplateStatistic();
    s2.setTotalCount(7);
    s2.setMailCount(8);
    resList.add(s1);
    resList.add(s2);
    TMessageTemplateStatistic total = StatisticTotalUtil.getTotalCount(resList, TMessageTemplateStatistic.class);
    resList.add(total);
    System.out.println(resList);
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TMessageTemplateStatistic implements Serializable {
    
    

    @FieldTotalAnnotation(isTotalName = true)
    @ApiModelProperty("区域名称")
    private String areaName;

    @FieldTotalAnnotation
    @ApiModelProperty("总数量")
    private Integer totalCount;

    @FieldTotalAnnotation
    @ApiModelProperty("发送邮政企业数量")
    private Integer mailCount;

}
[{
    
    "areaName":"杭州","mailCount":5,"totalCount":4},{
    
    "areaName":"台州","mailCount":8,"totalCount":7},{
    
    "areaName":"总计","mailCount":13,"totalCount":11}]

Insert image description here

According to the above tool class, any list can be passed and the total number can be calculated. That's the total in the last row.
In this way, there is no need to deal with a business with a statistical list separately.

Guess you like

Origin blog.csdn.net/weixin_40741732/article/details/128849984