java 反射自定义注解_Java学习路线(十)——反射和自定义注解

注解

在接触spring之后,我们经常会使用@xx这种形式的语法,我们把它们称为注解,通过注解,我们发现可以少写很多代码,既可以节省代码量,同时也有一定程度的注解作用,使代码语义明确,可谓一石二鸟。

注解的定义

public @interface MyAnnotation {

}

通过@interface关键字可以定义一个注解,我们发现它和interface关键字非常相似,可以理解为每个注解都是一个接口,同时也是Annotation的一个子类。

public interface MyAnnotation extends Annotation{

}

元注解

先看一个常用的注解:

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.SOURCE)

public @interface Override {

}

这是我们@Override注解的定义,你可以看到其中的@Target,@Retention两个注解就是我们所谓的元注解,元注解一般用于指定某个注解生命周期以及作用目标等信息。

元注解

作用

@Target

注解的作用目标

@Retention

注解的生命周期

@Documented

注解是否应当被包含在JavaDoc文档中

@Inherited

是否允许子类继承该注解

@Target

ElementType.ANNOTATION_TYPE 可以给一个注解进行注解

ElementType.CONSTRUCTOR 可以给构造方法进行注解

ElementType.FIELD 可以给属性进行注解

ElementType.LOCAL_VARIABLE 可以给局部变量进行注解

ElementType.METHOD 可以给方法进行注解

ElementType.PACKAGE 可以给一个包进行注解

ElementType.PARAMETER 可以给一个方法内的参数进行注解

ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

Retention

RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。

RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。

RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

注解的属性

注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface MyAnnotation {

int id();

String msg();

}

@TestAnnotation(id=1,msg="hello annotation")

public class Test {

}

反射

注解的作用可以理解为是注释,具体如何获取注解里面的信息以及如何使用里面的信息,还需要依靠反射。

首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解。

public boolean isAnnotationPresent(Class extends Annotation> annotationClass) {}

然后通过 getAnnotation() 方法来获取 Annotation 对象。

public A getAnnotation(Class annotationClass) {}

具体代码请参照项目代码。

自定义注解

我们现在假设一个运用场景,有一个实体类,他的金钱字段是BigDecimal,我希望金钱的BigDecimal字段返回前端的时候保留两位小数,其他BigDecimal字段不变,对于这种场景,就可以使用自定义注解。

首先自定义一个注解类:

@Target(ElementType.FIELD)

public @interface BigToStr {

//小数保留位数,默认2位

int length() default 2;

}

这里我们使用fastjson格式化,所以引入fastjson的maven配置。

com.alibaba

fastjson

1.2.54

写一个fastjson的过滤器,处理@BigToStr的字段

@Component

public class BigToStrFilter implements ValueFilter {

/**

* 需要处理的类

*/

private Map map = null;

/**

* 当前实体类

*/

private Object currentObject = null;

private void getNames(Object object) {

if (currentObject == object) {

return;

}

currentObject = object;

map = new HashMap<>();

Class clazz = object.getClass();

Field[] fields = clazz.getDeclaredFields();

//扫描每个字段,找出需要转化的字段

for (Field field : fields) {

BigToStr bigToStr = field.getAnnotation(BigToStr.class);

if (bigToStr != null) {

map.put(field.getName(),bigToStr.length());

}

}

}

/**

* @param object 对象

* @param name 对象的字段的名称

* @param value 对象的字段的值

*/

@Override

public Object process(Object object, String name, Object value) {

getNames(object);

//如果是需要转化的字段,对值进行转化

if (map.containsKey(name) && value instanceof BigDecimal) {

return bigDecimal2String((BigDecimal) value,map.get(name));

}

return value;

}

private static String bigDecimal2String(BigDecimal var,Integer length){

if(null==var) {

StringBuilder value = new StringBuilder("0.0");

while (length > 1) {

value.append("0");

length--;

}

return value.toString();

}

//BigDecimal格式化

return var.setScale(length,BigDecimal.ROUND_HALF_UP).toPlainString();

}

}

将过滤器放入fastjson的过滤配置中:

@Override

public void configureMessageConverters(List> converters) {

FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();

//序列化配置

FastJsonConfig config = new FastJsonConfig();

config.setSerializerFeatures(

// 输出key时是否使用双引号

QuoteFieldNames,

//禁止循环引用

DisableCircularReferenceDetect

);

config.setSerializeFilters(bigToStrFilter);

converter.setFastJsonConfig(config);

//优先使用FastJson进行序列化

converters.set(1,converter);

}

测试

我们定义一个类:

@Data

public class AccountVo {

@BigToStr

private BigDecimal money;

@BigToStr(length = 3)

private BigDecimal money1;

private BigDecimal money2;

}

看看他的三个字段在实体化后会有什么区别,访问http://127.0.0.1:8080/annotation/test,得到如下结果:

{

"code": "000",

"data": {

"money": "1.25",

"money1": "1.245",

"money2": 1.245454000000000061021410147077403962612152099609375

},

"msg": "成功"

}

很明显,通过注解,我们让BigDecimal的字段实现了自动格式化。当然,这只是自定义注解的一个小示例,想要实现其他功能,大体上的逻辑是差不多的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值