(四) 源码级注解处理

注解的用处之一就是自动生成包含程序额外信息的"附文件"。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();
    }
    
}
 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值