`

(四) 源码级注解处理

阅读更多

注解的用处之一就是自动生成包含程序额外信息的"附文件"。Java EE 5使用注解极大地简化了编程模型。

源码级注解是将注解处理器添加到Java编译器中。

    javac -processor ProcessorClassName1,ProcessorClassName2,... sourceFiles

 

有编译器定位源代码中的注解,然后选择恰当的注解处理器。每个注解处理器会依次执行。如果某哥哥注解处理器创建了一个新的源文件,那么将重复执行这个处理过程。如果某次处理循环没有再产生任何新的源文件,那么就编译所有的源文件。

关于处理器需要指示注释处理器支持哪些注释类型的注释和注释处理器所支持的最新源版本的注释。

    @SupportedAnnotationTypes("annotation.Property")
    @SupportedSourceVersion(SourceVersion.RELEASE_6)
 

通过一个简单示例来演示这项技术,一个DEMO,可以自动产生bean信息类。可以使用一个注解来标记bean的属性,然后运行某个工具对这个源文件进行解析、分析其注解,最后输出bean信息类的源文件。

 

package com.shaogq.annotation.source;

import java.beans.Introspector;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

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.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.JavaFileObject;
@SupportedAnnotationTypes("com.shaogq.annotation.Property")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class BeanInfoAnnotationFactory extends AbstractProcessor{

    @Override
    public boolean process(Set<? extends TypeElement> annotations,
            RoundEnvironment roundEnv) {
        for(TypeElement t : annotations){
            Map<String, Property> props = new LinkedHashMap<String, Property>();
            String beanClassName = null;
            for(Element e:roundEnv.getElementsAnnotatedWith(t)){
                String mname = e.getSimpleName().toString();
                String[] prefixes = {"get", "set" , "is"};
                boolean found = false;
                for(int i=0;!found && i<prefixes.length;i++){
                    if(mname.startsWith(prefixes[i])){
                        found = true;
                        int start = prefixes[i].length();
                        String name = Introspector.decapitalize(mname.substring(start));
                        props.put(name, e.getAnnotation(Property.class));
                    }
                }
                if(!found){
                    processingEnv.getMessager().printMessage(Kind.ERROR, 
                        "&Property must be applied to getXxx, setXxx, or isXxx method", e);
                }else if(beanClassName==null){
                    beanClassName = ((TypeElement)e.getEnclosingElement()).getQualifiedName().toString();
                }
            }
            try{
                if(beanClassName != null){
                    writeBeanInfoFile(beanClassName, props);
                }
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        return true;
    }

    private void writeBeanInfoFile(String beanClassName,
            Map<String, Property> props) throws IOException{
        JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(
                beanClassName + "BeanInfo");
        PrintWriter out = new PrintWriter(sourceFile.openWriter());
        int i = beanClassName.lastIndexOf(".");
        if(i>0){
            out.print("package ");
            out.print(beanClassName.substring(0, i));
            out.print(";");
        }
        out.print("public class ");
        out.print(beanClassName.substring(i + 1));
        out.println("BeanInfo extends java.beans.SimpleBeanInfo");
        out.print("{");
        out.print("    public java.beans.PropertyDescriptor[] getPropertyDescriptors(){");
        out.println("        try{");
        for(Map.Entry<String, Property> e :props.entrySet()){
            out.print("            java.beans.PropertyDescriptor");
            out.print(e.getKey());
            out.println("Descriptor");
            out.print("                = new java.beans.PropertyDescriptory(\"");
            out.print(e.getKey());
            out.print("\", ");
            out.print(beanClassName);
            out.println(".class);");
            String ed = e.getValue().editor().toString();
            if(!ed.equals("")){
                out.print("            ");
                out.print(e.getKey());
                out.print("Descriptor.setPropertyEditorClass(");
                out.print(ed);
                out.println(".class);");
            }
        }
        out.println("           return new java.beans.PropertyDescriptor[]{");
        boolean first = true;
        for(String p : props.keySet()){
            if(first){
                first = false;
            }else{
                out.print(",");
            }
            out.println();
            out.print("        ");
            out.print(p);
            out.print("Descriptor");
        }
        out.println();
        out.println("            };");
        out.println("        }");
        out.println("        catch(java.beans.IntrospectionException e){");
        out.println("            e.printStackTrace();");
        out.println("        return null;");
        out.println("        }");
        out.println("    }");
        out.println("}");
        out.close();
    }
    
}
 

 

 

分享到:
评论

相关推荐

    spring-hibernate注解配置源码

    本实例"spring-hibernate注解配置源码"旨在展示如何在不使用XML配置的情况下,通过注解的方式整合Struts2、Spring和Hibernate,创建一个完整的MVC(模型-视图-控制器)架构的应用。下面将详细介绍这个过程中的关键...

    Android高级应用源码-AndroidInject增加sqlite3数据库映射注解(ORM).zip

    这个压缩包"Android高级应用源码-AndroidInject增加sqlite3数据库映射注解(ORM).zip"提供了一个示例,展示了如何在Android项目中使用SQLite3数据库,并通过ORM(对象关系映射)技术来简化数据库操作。ORM允许开发者...

    入门级java 注解学习示例代码

    1. **源码级注解(Source-level Annotations)**:这些注解在编译期间由编译器处理,例如`@Override`用于标记重写父类方法,`@Deprecated`用于标记已废弃的方法。 2. **编译器注解(Compiler annotations)**:这些...

    注解+自定义注解+元注解+理解

    源码级注解仅在编译期间起作用,编译器级注解影响编译过程,而运行时注解可以在程序运行时被访问和处理。 二、自定义注解 2.1 创建自定义注解 在Java中,我们可以通过定义一个@interface关键字来创建自定义注解。...

    Python-asyncio源码注解

    **Python-asyncio源码注解** `asyncio` 是 Python 的一个标准库,用于编写异步并发代码,尤其在处理I/O密集型任务时表现出色。它基于协程(coroutines)和事件循环(event loop)的概念,使得开发者能够以同步编程...

    Android高级应用源码-AndroidInject增加sqlite3数据库映射注解(ORM).rar

    这个压缩包"Android高级应用源码-AndroidInject增加sqlite3数据库映射注解(ORM).rar"提供了一个示例,展示了如何在Android项目中使用SQLite3数据库,并结合ORM(对象关系映射)技术,通过注解的方式简化数据库操作。...

    Spring高级源码学习笔记.zip

    本笔记旨在深入解析Spring的高级源码,帮助程序员从应用层面过渡到源码级的理解。 Spring的核心组件包括Bean容器、AOP代理、数据访问/集成、MVC、Web服务等。首先,我们来探讨Bean容器,它是Spring的基础,负责管理...

    python 开发商品竞价demo源码+注解清晰一看就懂.zip

    11. **注解**:源码中的注解是理解代码功能和逻辑的重要辅助,它解释了代码的目的、工作方式以及特定部分的功能。 通过分析这个商品竞价DEMO,你可以学习到Python开发的实际应用,同时加深对Python语言特性和编程...

    hibernate二级缓存示例源码

    综上所述,通过学习`hibernate二级缓存示例源码`,我们可以了解到如何在实际项目中配置和使用Hibernate二级缓存,从而提升系统的性能。在实际应用中,应结合具体场景选择合适的缓存策略,以达到最佳的性能优化效果。

    java注解深入理解

    3. **源码级注解**:这类注解只在源代码级别有效,编译后的字节码中不会保留。通常用于代码生成工具,例如,JSR 269的`@Generated`注解。 创建自定义注解是通过定义一个接口来实现的,接口上使用`@interface`关键字...

    spring源码注释中文

    5. **AS(Application Server)**:Spring 提供了与常见应用服务器的集成,如 JMX 支持和 EJB(企业级JavaBean)的轻量级替代方案。 6. **Test**:测试模块支持在开发过程中对 Spring 应用进行单元测试和集成测试,...

    spring源码(注释+测试版)

    Spring框架是Java开发中最广泛应用的轻量级框架之一,它以IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)为核心,提供了全面的解决方案,包括数据访问、事务管理、Web...

    400多种Javascript应用实例的源码,源码有中文注解

    这个压缩包包含了400多种JavaScript应用实例的源码,并且每个源码都有中文注解,这对于初学者和进阶开发者来说,都是一个极其宝贵的资源。 1. **基础语法与数据类型**:JavaScript支持多种数据类型,包括基本类型...

    Java EE企业级应用开发教程(SSM)源码.zip

    Java EE企业级应用开发教程(SSM)源码是一个涵盖了使用Java开发企业级应用程序的实践示例。SSM是Spring、Spring MVC和MyBatis这三大框架的简称,它们是Java EE开发中常用的技术栈。这个教程源码将帮助开发者深入...

    Linux0.11源码及内核注解文档

    总的来说,通过学习“Linux0.11源码及内核注解文档”,可以深入了解操作系统内核的运作方式,提升编程和系统级问题解决能力。这对于想要从事系统开发、嵌入式开发或者服务器维护的人来说,是不可多得的学习资料。...

    SpringBoot 、Shiro、 自定义注解权限控制源码下载

    7. **日志和异常处理**:了解如何配置日志框架(如Logback、Log4j等)和全局异常处理。 通过这个项目,开发者不仅可以熟悉SpringBoot、Shiro和MyBatis Plus的基本用法,还能深入学习到权限控制和数据库操作的最佳...

    尚硅谷 4月份MyBatis视频教程(国内首套:源码级讲授的MyBatis视频)最新更新

    尚硅谷发布的这套MyBatis视频教程,是国内首套源码级讲授的MyBatis教程,非常适合希望深入了解MyBatis内部原理及实现机制的学习者。通过本篇总结,我们不仅了解了MyBatis的基本概念、核心功能,还探讨了一些实战中的...

    基于java的开发源码-UIMA注解类 uimaFIT.zip

    3. **uimaFIT**:uimaFIT是Apache UIMA的一个轻量级库,它通过Java注解简化了UIMA组件的配置和实现。uimaFIT允许开发者通过简单的注解来声明分析引擎的组件和参数,减少了XML配置文件的需求,提高了开发效率。 4. *...

    ssh框架源码 零配置 带注解

    这个压缩包“ssh框架源码 零配置 带注解”提供了这三大框架的源代码,并且强调了零配置和注解的使用,意味着开发者可以避免繁琐的XML配置,更专注于业务逻辑的实现。 Spring框架是SSH中的核心,它提供了一个全面的...

    python 开发虚拟跑步机自动计算消耗能量demo源码+注解清晰一看就懂.zip

    通过分析这个虚拟跑步机的Python源码,开发者不仅可以学习到如何使用Python进行数据处理和计算,还能了解到如何设计和实现一个简单的健身应用。对于想要提升自己Python技能的人来说,这是一个非常实用的学习资源。

Global site tag (gtag.js) - Google Analytics