java retentionpolicy_Java注解之如何利用RetentionPolicy.SOURCE生存周期

上一篇文章简单讲了下Java注解的学习之元注解说明,学习了Java注解是如何定义的,怎么使用的,但是并没有介绍Java的注解是怎么起作用的,像Spring Boot里面的那些注解,到底是怎么让程序这样子运行起来的?特别是讲到RetentionPolicy这一块,到底在SOURCE阶段,在CLASS阶段,在RUNTIME阶段有什么差别,注解是如何在这三个阶段起作用的呢?而且,在SOURCE阶段,在CLASS阶段,程序又不运行,那注解到底会用来做些什么呢?

带着这些疑问,我就去了解下了如何让注解起作用,发现RUNTIME阶段的介绍到处都是,但是SOURCE和CLASS阶段就很少文章讲解到了,真的得搜刮好几十篇文章才能成功的把程序跑起来,几乎每一篇文章都少讲了些东西。

本文优先讲的是SOURCE阶段注解如何发挥作用,发现这一块涉及的知识非常多且难,资料还少,另外还发现,Java服务器端编程的人用这个反而不如Android开发的人用得多。对我学习SOURCE阶段的注解帮助最大的是Pluggable Annotation Processing API,JSR269插件化注解API以及JVM进阶 -- 浅谈注解处理器。搜索这方面的资料用“插件化注解处理API”这个关键词能搜得更全。

这几篇文章基本上把SOURCE阶段的注解实现和使用讲了,但是具体细节,比如用javac直接编译运行代码,javac使用jar包,使用maven等三个方式如何运行注解处理器,倒是基本上蜻蜓点水,摸索了我好久才搞定了。关于注解处理器的知识,可以从如上三篇文章了解,本文主要讲注解的定义和运行。

我用的代码是摘抄至 JVM进阶 -- 浅谈注解处理器 ,它定义了一个CheckGetter的注解,用来检查一个类里面的字段,哪个没有Getter方法,没有的话编译就报错。不过我的和他的稍稍不同,他的代码定义没有放到package里面,我的放到package里面了,这样子的使用和执行又有了点不同。

首先,定义CheckGetter注解:

package com.shahuwang.processor;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.FIELD})

@Retention(RetentionPolicy.SOURCE)

public @interface CheckGetter {

}

注意上面的代码,是放到 package com.shahuwang.processor 里面的,因此,先创建如下结构的文件夹

Processor

—— com

—— shuhuwang

—— processor

—— CheckGetter.java

注解已经定义好了,现在先来用一下这个注解:

package com.shahuwang.processor;

@CheckGetter

public class TestGetter {

String name;

String first;

public String getName(){

return this.name;

}

}

这个类有两个字段,但是有一个字段没有设置getter。

下面才是真正重要的代码,就是让CheckGetter这个注解真正能运行起来,发挥作用:

package com.shahuwang.processor;

import javax.annotation.processing.AbstractProcessor;

import javax.annotation.processing.RoundEnvironment;

import javax.annotation.processing.SupportedAnnotationTypes;

import javax.annotation.processing.SupportedSourceVersion;

import javax.lang.model.SourceVersion;

import javax.lang.model.element.ExecutableElement;

import javax.lang.model.element.Modifier;

import javax.lang.model.element.TypeElement;

import javax.lang.model.element.VariableElement;

import javax.lang.model.util.ElementFilter;

import javax.tools.Diagnostic;

import javax.lang.model.element.Element;

import java.util.Set;

// 这个地方换了包名就需要改过来,否则processor就不会执行了, 这里是最需要注意的地方,千万注意!!!!!

@SupportedAnnotationTypes("com.shahuwang.processor.CheckGetter")

@SupportedSourceVersion(SourceVersion.RELEASE_11)

public class CheckGetterProcessor extends AbstractProcessor {

@Override

public boolean process(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {

for (TypeElement annotatedClass : ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(CheckGetter.class))) {

for (VariableElement field : ElementFilter.fieldsIn(annotatedClass.getEnclosedElements())) {

if(!containsGetter(annotatedClass, field.getSimpleName().toString())){

processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,

String.format("getter not found for '%s.%s'.", annotatedClass.getSimpleName(), field.getSimpleName()));

}

}

}

return false;

}

private static boolean containsGetter(TypeElement typeElement, String name){

String getter = "get" + name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase();

for(ExecutableElement executableElement: ElementFilter.methodsIn(typeElement.getEnclosedElements())){

if(!executableElement.getModifiers().contains(Modifier.STATIC) &&

executableElement.getSimpleName().toString().equals(getter) &&

executableElement.getParameters().isEmpty()){

return true;

}

}

return false;

}

}

上面这段代码要理解的概念有点儿多,实际上我现在也不是很懂,但是本文的目标是先让注解处理器跑起来,所以先不管。这里最重要也是折磨我最惨的地方,就是这一句@SupportedAnnotationTypes("com.shahuwang.processor.CheckGetter"),你定义的注解在哪个package下,这里就要写完整了,如果写错了,注解处理器就不起作用了。

现在在Processor目录下,打开命令行,先编译CheckGetterProcessor.java: javac com/shahuwang/processor/CheckGetterProcessor.java,编译好之后就可以使用了,再执行命令:javac -processor com.shahuwang.processor.CheckGetterProcessor com/shahuwang/processor/TestGetter.java,便可以看到这样的提示:

错误: getter not found for 'TestGetter.first'.

上面这种方式,需要每次执行编译的时候,指定一下processor才能做到检查作用,那如果在团队开发中,希望自动执行一些检查,那可以用SPI 服务提供者发现机制或者maven来实现。

SPI 服务提供者发现机制就是配置META-INF文件夹和里面的文件,告诉Java你要执行某个东西,这个东西的路径在哪里。再把编译好的processor和META-INF打包成jar包,就可以很方便使用了。文件夹和文件结构如下:

processor

-com

-shahuwang

- processor

- CheckGetterProcessor.class

-META-INF

-services

- javax.annotation.processing.Processor

编译方式和上述一样。

javax.annotation.processing.Processor是一个普通的文本,就是告知java一些关于注解处理器的配置,里面的内容如下:

com.shahuwang.processor.CheckGetterProcessor

就是告知这个注解处理器要用哪些个,如果有多个的话,可以一行一个。

然后在processor目录下,执行指令:jar -cvf processor.jar com META-INF, 形成了一个 processor.jar 的包,此时可以执行指令:

javac -cp processor.jar com/shahuwang/processor/TestGetter.java

就会自动执行注解处理器检查字段有没有getter方法了。

jar包的这个方法,其实是把注解和注解的实现单独放一块作为一个插件来使用了,maven也是如此的。

现实的开发中,还是用maven最多,先用指令创建一个maven项目:mvn archetype:generate -DgroupId=com.shahuwang -DartifactId=Processor -Dpackage=com.shahuwang.processor

然后在pom.xml的层级下添加如下配置:

UTF-8

UTF-8

1.8

1.8

1.8

org.apache.maven.plugins

maven-compiler-plugin

3.5.1

1.8

1.8

UTF-8

com.shahuwang.processor.CheckGetterProcessor

代码目录结构如下:

Processor

- src

- main

- java

-com

-shahuwang

-processor

-CheckGetter.java

-CheckGetterProcessor.java

- pom.xml

然后Processor目录下执行: mvn clean install, 这个项目就会被安装到本地的maven库里面。

再用maven新建一个TestProcessor项目,项目结构如下:

TestProcessor

- src

- main

- java

-com

-shahuwang

-TestGetter.java

- pom.xml

TestGetter.java 的代码上面有。

修改pom.xml, 先在 下添加:

UTF-8

UTF-8

1.8

1.8

1.8

org.apache.maven.plugins

maven-compiler-plugin

3.5.1

1.8

1.8

UTF-8

com.shahuwang.processor.CheckGetterProcessor

再在dependencies添加:

com.shahuwang

Processor

1.0-SNAPSHOT

也就是引入上面编译好的处理器的包。

现在,在TestProcessor目录下执行:

mvn compile

就会看到熟悉的提示:

错误: getter not found for 'TestGetter.first'.

三种主流的注解处理器使用方式现在都搞懂怎么使用了。下一篇文章将会关注注解处理器的使用方法,各个注解处理器API的使用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/529996.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在java程序中定义的类有两种成员_java试题 急需答案 谢谢!!!

三、填空(每小题2分,共10分)1.在Applet中,创建一个具有10行45列的多行文本区对象ta的语句为:2.创建一个标识有“关闭”字样的标签对象gb的语句为。3.方法是一种仅有方法头,没...三、填空(每小题…

java 同步 变量,在java中的对象上同步,然后更改同步的变量的值

I came across a code like thissynchronized(obj) {obj new Object();}Something does not feel right about this , I am unable to explain, Is this piece of code OK or there is something really wrong in it, please point it out.Thanks解决方案Its probably not wha…

java set泛型_Java 集合二 泛型、Set相关

泛型1、在定义一个类的方法时,因为不确定返回值类型,所以用一个符号代替,这个符号就是泛型eg:ArrayList list new ArrayList();2、泛型的好处:1、提高了数据的安全性,将运行时的问题提前暴露在编译阶段2、避免了强转的…

java annotation 实现_在Java中如何实现自己的annotation

1. 先定义annotation2. 使用annotation例子:import java.lang.annotation.*;import java.lang.reflect.Method;Target(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)interface Test {String info() default "";}class Annotated {Test(info &q…

登录界面拦截java_java拦截通过url访问页面,必须通过登录页面访问目标页面

在web.xml中配置过滤:LoginFiltercom.verification.action.LoginFilterLoginFiltery/form/dealParse.do/* 拦截所有请求/.do 拦截以“.do”结尾的请求/index.jsp 拦截指定的jsp/artery/form/* 拦截该目录下的所有请求等等拦截器,拦截请求类&#xf…

python textwrap_[Python标准库]textwrap——格式化文本段落

textwrap——格式化文本段落作用:通过调整换行符在段落中出现的位置来格式化文本。 Python 版本:2.5 及以后版本 需要美观打印时,可以用 textwrap 模块来格式化要输出的文本。这个模块允许通过编程提供类似段落自动换行或填充…

java 字符串 1_java 字符串操作大全1

1、length() 字符串的长度例:char chars[]{a,b.c};String snew String(chars);int lens.length();2、charAt() 截取一个字符例:char ch;ch"abc".charAt(1); 返回b3、getChars() 截取多个字符void getChars(int sourceStart,int sourceEnd,char…

java实现权限_Java实现权限管理的两种方式

编辑特别推荐:种方式:利用filter、xml文件和用户信息表配合使用来实现权限管理。1.过滤器filterpackage cn.com.aaa.bbb.filter;import java.io.IOException;import java.io.InputStream;import java.util.HashMap;import java.util.Iterator;import java.util.List…

java 输入16进制_尝试使用十六进制输入来使用小端和大端

我试图用这两个原型编写C函数:int extract_little (char* str, int ofset, int n);int extract_big(char* str, int ofset, int n);现在一般的想法是我需要从地址str ofset开始以两种格式返回一个n字节整数 . 附: Ofset还没有做任何事情,我计…

java gson_Java 中 Gson的使用

JSON 是一种文本形式的数据交换格式,它比XML更轻量、比二进制容易阅读和编写,调式也更加方便;解析和生成的方式很多,Java中最常用的类库有:JSON-Java、Gson、Jackson、FastJson等一、Gson的基本用法Gson提供了fromJson() 和toJson…

spring注入普通java类_普通java类如何取得注入spring Ioc容器的对象

[除了使用XML配置外,还可以选择使用基于注解(annotation)的配置方式,其依赖于字节码来织入组件。注解注入在XML注入之前完成,因此在XML配置中可以重载注解注入的属性。一、建一个SpringUtil类package com.ceopen.eoss.spring; import org.spr…

java web 集成dom4j_[JavaWeb基础] 031.dom4j写入xml的方法

上一篇我们讲述了dom4j读取xml的4种方法,甚是精彩,那么怎么样写入xml呢?我们直接看下源码实现。public static void main(String[] args) throws Exception {// 创建文档Document document DocumentHelper.createDocument();// 设置编码docu…

java servlet 调试日志 logger sae_java servlet 调试日志 lo

java servlet 调试日志 lo[2021-02-10 08:32:08] 简介:php去除nbsp的方法:首先创建一个PHP代码示例文件;然后通过“preg_replace("/(\s|\&nbsp\;| |\xc2\xa0)/", " ", strip_tags($val));”方法去除所有nbsp即可。推荐&#x…

java接口权限管理在哪里_java访问权限控制

为什么java要有访问权限的控制?访问权限的设置和代码的重构有关。在一个项目中,大多数的时间和金钱都投入到了代码的维护当中。维护中一定会修改已存在的不合理的代码。但是在重构的过程中,就出现了这样的问题:如何保证不影响那些使用了待修…

java8 stream index_Java8的stream用法整理

/***authorindex* date 2020/10/27**/public classTestcollectingAndThen {Testpublic voidtest(){final int NUM 14;List peopleList new ArrayList<>(NUM);String[] names {"小张", "小龙", "小牛", "小猪", "小黑&quo…

memo、 useMemo 和 useCallback语法讲解

memo、 useMemo 和 useCallback 缓存组件, 对组件浅比较 (只有组件的props, (对函数,引用要用useCallback包裹)发生变化 缓存值, 依赖项变化&#xff0c;会从新计算。 缓存函数, 依赖项变化,重新生成新函数 useMemo 语法 对返回的值缓存进行优化 const memoizedValue useMem…

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

今天遇到需求&#xff1a;导入Excel时候列头会发生变化&#xff0c;客户是大爷要求你改代码&#xff0c;导入Excel是用easypoi做的&#xff0c;识别表头是用注解Excel(name "xxx")通过这个name来匹配那你表头要动&#xff0c;我这个注解是硬编码所以就有动态设置这个…

求java简单计算器源代码_java简单计算器源代码

简单计算器代码package calcultorthree;import java.awt.BorderLayout;//导入边界布局管理器类import java.awt.GridLayout;//导入网格布局管理器类import java.awt.TextField;//导入文本区域类import java.awt.event.ActionEvent;//导入事件类import java.awt.event.ActionLis…

java中间语言汇编语言_中间语言(IL) | 学步园

一、IL与汇编语言IL是微软.NET平台上衍生出的一门中间语言&#xff0c;.NET平台上的各种高级语言(如C#&#xff0c;VB&#xff0c;F#)的编译器会将各自的代码转化为IL。&#xff0c;其中包含了.NET平台上的各种元素&#xff0c;如“范型”&#xff0c;“类”、、“接口”、“模…

java遍历斐波纳契数列_详解循环、迭代、递归、分治(Leet Code 509 斐波那契数列),实际运用...

Multiple solutions of Fibonacci (Python or Java)本章是用英文写的&#xff0c;作为或想成为一名优秀的攻城狮&#xff0c;习惯阅读英文文档将使你受益良多。例如更好的查看最新版的官方文档、与国外友人交流、等等 其实英文的生词也并不多,其中90&#xff05;的英文都在代码…