动态的为实体字段添加注解/注解属性

动态注解操作与应用
这个博客介绍了如何使用Java动态地给实体类的字段添加、编辑和查询注解。通过Apache的javassist库,实现了在运行时动态修改类的注解信息,包括添加新的注解、修改已有注解的属性,以及遍历和获取注解的所有属性。示例代码展示了如何在实际项目中应用这些功能,例如在导出表格时根据条件决定是否显示字段。

可以动态的给实体添加注解,比如:导出表格的时候,根据条件决定是否导出该字段的列等使用

本例子将所有代码都放入工具类中,实际上有些不能实例化到内存中,只能作为一部分代码放在逻辑中,此种代码以再程序中标注;另一部分是可以持久化到内存,使用完工具类之后也可以继续保存注解或者属性;

使用搭配在文末指出

代码如下:

package com.springcloud.utils;

import org.apache.ibatis.javassist.ClassPool;
import org.apache.ibatis.javassist.CtClass;
import org.apache.ibatis.javassist.CtField;
import org.apache.ibatis.javassist.NotFoundException;
import org.apache.ibatis.javassist.bytecode.AnnotationsAttribute;
import org.apache.ibatis.javassist.bytecode.ConstPool;
import org.apache.ibatis.javassist.bytecode.FieldInfo;
import org.apache.ibatis.javassist.bytecode.annotation.Annotation;
import org.apache.ibatis.javassist.bytecode.annotation.MemberValue;
import org.apache.ibatis.javassist.bytecode.annotation.StringMemberValue;

import java.util.Arrays;
import java.util.Set;


public class AddAnnotion {

    /**
     * 功能:动态的给类属性添加注解
     *  用于本来没有注解,直接添加上一行整注解
     * (可以持久化到内存,可作为工具类使用)
     * @param className     类名
     * @param attributeName 类属性
     * @param typeName      注解类型
     */
    public static void addAnnotation(String className, String attributeName, String typeName) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ct = pool.get(className);
            CtField cf = ct.getField(attributeName);
            FieldInfo fieldInfo = cf.getFieldInfo();
            AnnotationsAttribute attribute = (AnnotationsAttribute) fieldInfo.getAttribute(AnnotationsAttribute.visibleTag);
            ConstPool cp = fieldInfo.getConstPool();
            Annotation annotation = new Annotation(typeName, cp);
            System.out.println("添加注解" + annotation);
            attribute.addAnnotation(annotation);
            System.out.println("添加后的所有注解" + Arrays.toString(attribute.getAnnotations()));
        } catch (NotFoundException e) {
            System.out.println("此类不存在" + e);
        }
    }

    /**
     * 遍历注解所有属性
     *
     * @param className     类名
     * @param attributeName 类属性
     */
    public static void queryAnnotation(String className, String attributeName) {
        System.out.println("====开始遍历注解所有属性=====");
        System.out.println("");
        try {
            ClassPool pool = ClassPool.getDefault();
            //获取实体类
            CtClass ct = pool.get(className);
            //获取属性
            CtField cf = ct.getField(attributeName);
            //获取属性字段信息
            FieldInfo fieldInfo = cf.getFieldInfo();
            //获取属性字段的运行时可见注释
            AnnotationsAttribute attribute = (AnnotationsAttribute) fieldInfo.getAttribute(AnnotationsAttribute.visibleTag);
            //获取所有注解
            Annotation[] annotations = attribute.getAnnotations();
            int sum = 0;
            //遍历注解
            for (Annotation annotation : annotations) {
                sum++;
                System.out.println("注解" + sum + ":" + annotation.toString());
                //如果没有属性名,就下一个循环
                if (annotation.getMemberNames() == null) {
                    System.out.println("!无属性名跟属性值!");
                    continue;
                }
                //获取注解的所有属性名,跟属性值
                for (String memberName : annotation.getMemberNames()) {
                    MemberValue memberValue = annotation.getMemberValue(memberName);
                    System.out.println("获取到的注解的属性名:" + memberName);
                    System.out.println("获取到的注解的属性值:" + memberValue);
                }
            }
        } catch (NotFoundException e) {
            System.out.println("此类不存在" + e);
        }
    }

    /**
     * 给字段注解添加属性,添加单一注解的属性
     * (不能持久化到内存,只能作为代码一部分使用)
     * @param className     类名
     * @param attributeName 类属性
     * @param name          指定注解名
     * @param key           给注解添加的属性名
     * @param value         给注解添加的属性的值
     */
    public static void editAnnotation(String className, String attributeName, String name, String key, String value) {
        try {
            ClassPool pool = ClassPool.getDefault();
            //获取实体类
            CtClass ct = pool.get(className);
            //获取属性
            CtField cf = ct.getField(attributeName);
            //获取属性字段信息
            FieldInfo fieldInfo = cf.getFieldInfo();
            //获取该字段的常量池
            ConstPool constPool = cf.getFieldInfo().getConstPool();
            //获取属性字段的运行时可见注释
            AnnotationsAttribute attribute = (AnnotationsAttribute) fieldInfo.getAttribute(AnnotationsAttribute.visibleTag);
            //获取所有注解
            Annotation[] annotations = attribute.getAnnotations();
            for (Annotation annotation : annotations) {
                //如果没有属性名,就下一个循环
                if (annotation.getMemberNames() == null) {
                    continue;
                }
                if (annotation.toString().contains(name)) {
                    System.out.println("添加属性");
                    //给指定的注解添加属性
                    annotation.addMemberValue(key, new StringMemberValue(value, constPool));
                }
            }

            //遍历检查是否添加上注解
            for (Annotation annotation : annotations) {
                Set<String> memberNames = annotation.getMemberNames();
                if (annotation.getMemberNames() == null) {
                    System.out.println("!无属性名跟属性值!");
                    continue;
                }
                for (String memberName : memberNames) {
                    System.out.println("名称:" + memberName + "值:" + annotation.getMemberValue(memberName));
                }
            }
        } catch (Exception e) {
            System.out.println("捕获异常" + e.getMessage());
        }
    }

    /**
     * 获取指定字段的指定注解
     *
     * @param className     类名
     * @param attributeName 类属性
     * @param annotionName  指定注解名
     */
    public static Annotation getAnnotation(String className, String attributeName, String annotionName) {
        Annotation tableField = null;
        try {
            ClassPool pool = ClassPool.getDefault();
            //获取实体类
            CtClass ct = pool.get(className);
            //获取属性
            CtField cf = ct.getField(attributeName);
            //获取属性字段信息
            FieldInfo fieldInfo = cf.getFieldInfo();
            //获取该字段的常量池
            ConstPool constPool = cf.getFieldInfo().getConstPool();
            //获取属性字段的运行时可见注释
            AnnotationsAttribute attribute = (AnnotationsAttribute) fieldInfo.getAttribute(AnnotationsAttribute.visibleTag);
            //获取该字段所有注解
            Annotation[] annotations = attribute.getAnnotations();
            for (Annotation annotation : annotations) {
                //注解名包含字段,就命中返回
                if (annotation.toString().contains(annotionName)) {
                    tableField = annotation;
                    return tableField;
                }
            }
        } catch (NotFoundException e) {
            System.out.println("捕获异常" + e.getMessage());
        }
        return tableField;
    }

    /**
     * 根据给定的注解体,给其添加属性
     *  (不能持久化到内存,只能作为代码一部分使用)
     * @param className     类名
     * @param attributeName 类属性
     * @param annotation    注解实体
     * @param key           给注解添加的属性
     * @param value         给注解添加的属性的值
     * @return
     */
    public static Annotation editAnnotationBy(String className, String attributeName, Annotation annotation, String key, String value) {
        try {
            ClassPool pool = ClassPool.getDefault();
            //获取实体类
            CtClass ct = pool.get(className);
            //获取属性
            CtField cf = ct.getField(attributeName);
            //获取该字段的常量池
            ConstPool constPool = cf.getFieldInfo().getConstPool();
            //给指定的注解添加属性
            annotation.addMemberValue(key, new StringMemberValue(value, constPool));
            return annotation;
        } catch (Exception e) {
            System.out.println("捕获异常" + e.getMessage());
        }
        return annotation;
    }

    /**
     * 功能:使用生成的注解体 ;动态的给类注解添加属性
     * (可以持久化到内存,可作为工具类使用)
     * @param className     类名
     * @param attributeName 类属性
     */
    public static void addAnnotationBy(String className, String attributeName, Annotation annotation) {
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ct = pool.get(className);
            CtField cf = ct.getField(attributeName);
            FieldInfo fieldInfo = cf.getFieldInfo();
            AnnotationsAttribute attribute = (AnnotationsAttribute) fieldInfo.getAttribute(AnnotationsAttribute.visibleTag);
            attribute.addAnnotation(annotation);
            System.out.println("添加后的所有注解" + Arrays.toString(attribute.getAnnotations()));
        } catch (NotFoundException e) {
            System.out.println("此类不存在" + e);
        }
    }
}

工具类使用举例:
实体

/**
 * @author byChen
 * @date 2021/10/20
 */
public class Animal {
    @TableField(exist = false)
    public String age;
}

工具类:

    @GetMapping("/annotion")
    public R annotion() {
        Annotation tableField = AddAnnotion.getAnnotation("com.springcloud.domain.Animal", "age","TableField");
        System.out.println("添加之前的:"+tableField);
        Annotation annotation = AddAnnotion.editAnnotationBy("com.springcloud.domain.Animal", "age", tableField, "value", "123");
        System.out.println("添加过后的:"+annotation);
        AddAnnotion.addAnnotationBy("com.springcloud.domain.Animal", "age",annotation);
        AddAnnotion.queryAnnotation("com.springcloud.domain.Animal","age");
        return R.ok();
    }
}

运行结果:
在这里插入图片描述

Java 中,实体注解字段对应数据库属性可使用多种注解来实现,下面介绍一些常见的注解及其用法: #### @TableName `@TableName` 是 MyBatis-Plus 框架中的注解,用于指定实体类对应的数据库表名。例如: ```java import com.baomidou.mybatisplus.annotation.TableName; @TableName("sl_carriage") public class Carriage { // 类的属性和方法 } ``` 这里的 `"sl_carriage"` 表示这个实体类映射到数据库中的 `sl_carriage` 表,通过该注解,MyBatis-Plus 可以将实体类与数据库表正确映射,以便执行 CRUD 操作 [^3]。 #### @TableField `@TableField` 用于指定实体属性与数据库表字段的映射关系。当实体属性名与数据库表字段名不一致时,可使用该注解进行显式映射。示例如下: ```java import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; @TableName("user") public class User { private Long id; @TableField("user_name") private String name; // getter 和 setter 方法 } ``` 在上述代码中,实体类 `User` 的 `name` 属性对应数据库表 `user` 中的 `user_name` 字段 [^1][^2]。 #### @Id `@Id` 注解用于标识实体类中的主键属性。在 MyBatis-Plus 中,结合 `@TableId` 注解使用,可指定主键的生成策略。示例: ```java import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.IdType; @TableName("user") public class User { @TableId(value = "id", type = IdType.AUTO) private Long id; private String name; // getter 和 setter 方法 } ``` 此代码中,`@TableId` 注解指定了主键字段为 `id`,并且使用 `IdType.AUTO` 表示自增主键 [^1][^2]。 #### @Transient 当实体类中存在不需要映射到数据库表字段属性时,可使用 `@Transient` 注解。示例: ```java import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import java.io.Serializable; import java.util.Date; @TableName("user") public class User implements Serializable { private Long id; private String name; @TableField(exist = false) private String extraInfo; // getter 和 setter 方法 } ``` 在这个例子中,`extraInfo` 属性不会被映射到数据库表的字段,因为 `@TableField` 的 `exist` 属性设置为 `false` [^5]。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值