java注解之运行时修改字段的注解值操作

今天遇到需求:导入Excel时候列头会发生变化,客户是大爷要求你改代码,

导入Excel是用easypoi做的,识别表头是用注解@Excel(name = "xxx")通过这个name来匹配

那你表头要动,我这个注解是硬编码

所以就有动态设置这个表头

public class JavaVo{
@Excel(name = "xxx")
private String userName;
//省略getset方法
}

ExcelImportUtil.importExcel(file.getInputStream(), configClass(JavaVo.class), params);

代码如下

 private Class configClass(Class c , String val) {

   Field[] fields = c.getDeclaredFields();
   try {
  for(int i = 0;i < fields.length;i++){
  Field f = fields[i];
  Excel excelAn = f.getAnnotation(Excel.class);//Excel是注解类型
  if(excelAn == null){
   continue;
  }
  InvocationHandler h = Proxy.getInvocationHandler(excelAn);
  Field hField = h.getClass().getDeclaredField("memberValues");
    // 因为这个字段事 private final 修饰,所以要打开权限
    hField.setAccessible(true);
    // 获取 memberValues
    Map memberValues = (Map) hField.get(h);
    // 修改 value 属性值 这里修改的是@Excel(name = "姓名")
        //name是key
    memberValues.put("name", val);
  }
 } catch (Exception e) {
  e.printStackTrace();
 }
 return c;
 }

补充知识:java动态修改 注解的值,控制对象转化为json字符串的字段是否序列化

定义一个对象使用@JSONField控制该对象属性是否需要序列化

import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;

@Data
public class A {
  @JSONField(serialize = false)
  private String extendParams;

  @JSONField(serialize = true)
  private String sad;
}

编写工具类

import com.alibaba.fastjson.annotation.JSONField;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Map;
import lombok.val;

/**
 * 动态操作注解属性
 * @since 2020年8月13日20:49:26
 */
public class AnnotationUtils<T> {
  /**
   * 查看注解属性
   * @param t
   * @param name
   * @return
   * @throws NoSuchFieldException
   */
  public Object getJSONFieldProp(T t, String name) throws NoSuchFieldException {
    Field field = t.getClass().getDeclaredField(name);
    JSONField annotation = field.getAnnotation(JSONField.class);
    val serialize = annotation.serialize();
    return serialize;
  }

  /**
   * 修改注解属性
   * @param t
   * @param value
   * @return
   * @throws NoSuchFieldException
   * @throws IllegalAccessException
   */
  public Object setJSONFieldProp(T t,String name, Object value) throws NoSuchFieldException, IllegalAccessException {
    Field field = t.getClass().getDeclaredField(name);
    JSONField annotation = field.getAnnotation(JSONField.class);
    InvocationHandler invocationHandler = Proxy.getInvocationHandler(annotation);
    Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
    memberValues.setAccessible(true);
    Map map = (Map) memberValues.get(invocationHandler);
    map.put("serialize",value);
    val serialize = annotation.serialize();
    return serialize;
  }
}

测试

import com.alibaba.fastjson.JSON;

public class TT {

  public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    AnnotationUtils<A> aAnnotationUtils = new AnnotationUtils<>();
    A a = new A();
    a.setExtendParams("exex");
    a.setSad("sadsad");

    Object extendParams = aAnnotationUtils.getJSONFieldProp(a, "extendParams");//查询注解的值
    System.out.println(extendParams.toString());
//    System.out.println(JSON.toJSONString(a));

    Object extendParams1 = aAnnotationUtils.setJSONFieldProp(a, "extendParams", true);//修改注解的值
    System.out.println(extendParams1.toString());
    System.out.println(JSON.toJSONString(a));
  }
}

去掉main里面的注解看看效果,这个好像是发生了jvm优化导致的问题。。。

注释第一个print 打印结果如下:

false
true
{"extendParams":"exex","sad":"sadsad"}

不注释第一个print 打印结果如下:

false
{"sad":"sadsad"}
true
{"sad":"sadsad"}

接下来我们在做一个测试

  public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
    List<A> aList = new ArrayList<>();
    for(int i=0; i<10; i++){
      AnnotationUtils<A> aAnnotationUtils = new AnnotationUtils<>();
      A a = new A();
      a.setExtendParams("exex");
      a.setSad("sadsad");
      if(i%2 == 0) {
        aAnnotationUtils.setJSONFieldProp(a, "extendParams", true);//修改注解的值
      }
      aList.add(a);
    }
    System.out.println(JSON.toJSONString(aList));
  }

打印结果

[{"extendParams":"exex","sad":"sadsad"},{"extendParams":"exex","sad":"sadsad"},{"extendParams":"exex","sad":"sadsad"},{"extendParams":"exex","sad":"sadsad"},{"extendParams":"exex","sad":"sadsad"},{"extendParams":"exex","sad":"sadsad"},{"extendParams":"exex","sad":"sadsad"},{"extendParams":"exex","sad":"sadsad"},{"extendParams":"exex","sad":"sadsad"},{"extendParams":"exex","sad":"sadsad"}]

我本想用修改注解的方式来修改某个字段的序列化与不序列化,但是我发现注解是在class层面的并不是在对象层面。所以我的设想失败了。。

以上这篇java注解之运行时修改字段的注解值操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java 注解的使用实例详解

    Java 注解的使用 注解的使用非常简单,只需在需要注解的地方标明某个注解即可,例如在方法上注解: public class Test { @Override public String tostring() { return "override it"; } } 例如在类上注解: @Deprecated public class Test { } 所以Java内置的注解直接使用即可,但很多时候我们需要自己定义一些注解,例如常见的spring就用了大量的注解来管理对象之间的依赖关系.下

  • java教程之java注解annotation使用方法

    1.概述 注解可以定义到方法上,类上,一个注解相当与一个类,就相当于实例了一个对象,加上了注解,就相当于加了一个标志. 常用的注解:@Override:表示重新父类的方法,这个也可以判断是否覆盖的父类方法,在方法前面加上此语句,如果提示的错误,那么你不是覆盖的父类的方法,要是提示的没有错误,那么就是覆盖的父类的方法.@SuppressWarnings("deprecation"):取消编译器的警告(例如你使用的方法过时了)@Deprecated:在方法的最上边也上此语句,表示此方法过时

  • java SpringBoot自定义注解,及自定义解析器实现对象自动注入操作

    # java-SpringBoot自定义参数解析器实现对象自动注入 解析器逻辑流程图表 后台解析注解的解析器 首先,我在java后台编写了一个解析器,代码如下 import com.ruoyi.framework.interceptor.annotation.LoginUser; import com.ruoyi.project.WebMoudle.WebUser.domain.WebUser; import com.ruoyi.project.WebMoudle.WebUser.service

  • Java自定义注解的详解

    Java自定义注解 Java注解提供了关于代码的一些信息,但并不直接作用于它所注解的代码内容.在这个教程当中,我们将学习Java的注解,如何定制注解,注解的使用以及如何通过反射解析注解. Java1.5引入了注解,当前许多java框架中大量使用注解,如hibernate.Jersey.spring.注解作为程序的元数据嵌入到程序当中.注解可以被一些解析工具或者是编译工具进行解析.我们也可以声明注解在编译过程或执行时产生作用. 在使用注解之前,程序源数据只是通过java注释和javadoc,但是注

  • java注解之运行时修改字段的注解值操作

    今天遇到需求:导入Excel时候列头会发生变化,客户是大爷要求你改代码, 导入Excel是用easypoi做的,识别表头是用注解@Excel(name = "xxx")通过这个name来匹配 那你表头要动,我这个注解是硬编码 所以就有动态设置这个表头 public class JavaVo{ @Excel(name = "xxx") private String userName; //省略getset方法 } ExcelImportUtil.importExcel

  • Java实现创建运行时类的对象操作示例

    本文实例讲述了Java实现创建运行时类的对象操作.分享给大家供大家参考,具体如下: 获取运行时类的方法: public void test() throws ClassNotFoundException { /* * Class类是反射的源头 * 创建一个类,通过编译(javac.exe),生成对应的.class文件,之后使用java.exe加载(JVM的类加载器完成的)此.class文件. * 此.class文件加载到内存后,就是一个运行时类,存放在缓存区. * 那么这个运行时类本身就是一个C

  • Python运行时修改业务SQL代码

    目录 前记 1.缘起 2.侵入库 3.获取商户ID 4.修改SQL 前记 在项目的演变过程中,有时可能会诞生一些需要奇怪的临时需求,这些需求会涉及到所有的SQL,但开发时间上却不允许整个项目的所有SQL进行重写,比如控制不同的人访问表的权限,或者是我面对的SASS化需求,这时就需要在运行时根据对应的条件来修改SQL语句. 1.缘起 最近项目在准备搞SASS化,SASS化有一个特点就是多租户,且每个租户之间的数据都要隔离,对于数据库的隔离方案常见的有数据库隔离,表隔离,字段隔离,目前我只用到表隔离

  • java编译时与运行时概念与实例详解

    Java编译时与运行时很重要的概念,但是一直没有明晰,这次专门博客写明白概念. 基础概念 编译时 编译时顾名思义就是正在编译的时候.那啥叫编译呢?就是编译器帮你把源代码翻译成机器能识别的代码.(当然只是一般意义上这么说,实际上可能只是翻译成某个中间状态的语言.比如Java只有JVM识别的字节码,.另外还有啥链接器.汇编器.为了了便于理解我们可以统称为编译器) 那编译时就是简单的作一些翻译工作,比如检查老兄你有没有粗心写错啥关键字了啊.有啥词法分析,语法分析之类的过程.就像个老师检查学生的作文中有

  • java显示当前运行时的参数(java运行参数)

    显示当前运行java代码的运行时的各种参数. 不带显String操作. 复制代码 代码如下: package systeminfo; import java.util.Iterator;import java.util.Map.Entry;import java.util.Properties; public class sysinfo { public static void main(String[] args) {  Properties p = System.getProperties(

  • mysql数据库表增添字段,删除字段,修改字段的排列等操作

    目录 一.mysql修改表名 二.mysql修改数据的字段类型 三.mysql修改字段名 四.mysql添加字段 1.添加没有约束性的字段 2.添加一个有约束性的字段 3.在表的第一列添加一个字段 4.在数据表中指定列之后添加一个字段 五.mysql删除字段 六.mysql修改字段的排列位置 1.修改字段为表的第一个字段 2.修改字段为指定列后面 七.mysql更改表的存储引擎 修改表指的是修改数据库之后中已经存在的数据表的结构.​​mysql​​​使用​​alter table​​语句修改表.

  • MySQL如何修改字段的默认值和空值

    目录 MySQL修改字段的默认值和空值 修改字段默认值 修改字段值是否为空 MySQL默认值NULL.空值.Empty String的区别 如何选择? 先说结论 区别 MySQL修改字段的默认值和空值 修改字段默认值 修改: ALTER TABLE 表名 ALTER COLUMN 字段名 SET DEFAULT 默认值 删除: ALTER TABLE 表名 ALTER COLUMN 字段名 DROP DEFAULT 修改字段值是否为空 设为空: ALTER TABLE 表名 MODIFY 字段名

  • mysql查询的时候给字段赋默认值操作

    需求 查询某个字段的时候需要给一个字段同样的值. 这个值你可以写死,也可以从数据库获取 1.写死值 SELECT mfr_id AS mfrId, mfr_name AS mfrName, IFNULL(NULL, 587694978080178176) AS suppId FROM mater_prod materProd 查询结果 2.从数据库获取值 SELECT mfr_id AS mfrId, mfr_name AS mfrName, IFNULL(NULL, mfr_id) AS su

  • Java内存划分:运行时数据区域

    目录 1. 程序计数器(线程私有) 2. Java虚拟机栈(线程私有) (1) 概念 (2) 下面我们来分析一段代码 3. 本地方法栈(线程私有) 4. Java堆(线程共享) 5. 方法区(线程共享) 6. 运行时常量池(方法区的一部分) (1) 概念 (2) 补充: 其他常量池 总结 1. 程序计数器(线程私有) 程序计数器是一块比较小的内存空间,可以看做是当前线程所执行的字节码的行号指示器(切换线程后,能恢复到正确的执行位置). 2. Java虚拟机栈(线程私有) (1) 概念 虚拟机栈描

  • 举例讲解Java的RTTI运行时类型识别机制

    1.RTTI: 运行时类型信息可以让你在程序运行时发现和使用类型信息. 在Java中运行时识别对象和类的信息有两种方式:传统的RTTI,以及反射.下面就来说下RTTI. RTTI:在运行时,识别一个对象的类型.但是这个类型在编译时必须已知. 下面通过一个例子来看下RTTI的使用.这里涉及到了多态的概念:让代码只操作基类的引用,而实际上调用具体的子类的方法,通常会创建一个具体的对象(Circle,Square,或者Triangle,见下例),把它向上转型为Shape(忽略了对象的具体类型),并在后

随机推荐