使用注解生成代码

   // creates the method descriptor with parameter descriptors

            // TODO parameterize parameter descriptors

            ParameterDescriptor parameterDescriptor1 = new ParameterDescriptor();

            parameterDescriptor1.setName("listener");

            parameterDescriptor1.setDisplayName("listener");

            ParameterDescriptor[] parameterDescriptors = {parameterDescriptor1};

            descriptor = new MethodDescriptor(method, parameterDescriptors);

 

        } catch (Throwable t) {

            // alternative: create a plain method descriptor

            descriptor = new MethodDescriptor(method);

        }

 

        // TODO parameterize descriptor properties

        descriptor.setDisplayName("${method.simpleName}(java.beans.PropertyChangeListener)");

        descriptor.setShortDescription("Adds a property change listener.");

        descriptor.setExpert(false);

        descriptor.setHidden(false);

        descriptor.setValue("preferred", false);

 

        return descriptor;

    }

#end

}

 

注意在这个模板运作之前,我们需要将以下信息传递给Velocity

 

packageName:生成类的完整包名。

className:生成类的类名。

fields:源类中包含的filed的集合。我们需要从每个field中获取以下信息:

simpleNamefiled的变量名。

typefiled的类型。

descriptionfiled的自我描述(在本例中没有使用)

……

methods:源类中包含的method的集合。我们需要从每个method中获取以下信息:

simpleNamemethod的方法名。

argumentsmethod的参数(在本例中没有使用)

returnTypemethod的返回类型(在本例中没有使用)

descriptionmethod的自我描述(在本例中没有使用)

……

所有的这些信息(也就是模型)都需要从源类里面匹配的注解中提取,并保存到JavaBean后传递给Velocity

 

步骤2:注解处理器读取Model

 

下面让我们创建一个注解处理器。正如本系列第二部分中所提到的,不要忘记给处理器添加注解,好让它能够处理BeanInfo注解类型:

 

@SupportedAnnotationTypes("example.annotations.beaninfo.BeanInfo")

@SupportedSourceVersion(SourceVersion.RELEASE_6)

public class BeanInfoProcessor

    extends AbstractProcessor {

      ...

}

 

注解处理器的方法需要从注解和源类本身中提取构建模型所需要的信息。你可以将全部需要的信息都保存到JavaBean里面,不过在这个示例中我们使用的是javax.lang.model.element类型,因为我们不打算传递太多细节给Velocity(当然,需要的数据还是会传递过去的,在这个例子中我们要创建的是一个完整的BeanInfo生成器):

 

String fqClassName = null;

String className = null;

String packageName = null;

Map<String, VariableElement> fields = new HashMap<String, VariableElement>();

Map<String, ExecutableElement> methods = new HashMap<String, ExecutableElement>();

 

for (Element e : roundEnv.getElementsAnnotatedWith(BeanInfo.class)) {

 

    if (e.getKind() == ElementKind.CLASS) {

 

        TypeElement classElement = (TypeElement) e;

        PackageElement packageElement = (PackageElement) classElement.getEnclosingElement();

 

        processingEnv.getMessager().printMessage(

            Diagnostic.Kind.NOTE,

            "annotated class: " + classElement.getQualifiedName(), e);

 

        fqClassName = classElement.getQualifiedName().toString();

        className = classElement.getSimpleName().toString();

        packageName = packageElement.getQualifiedName().toString();

 

    } else if (e.getKind() == ElementKind.FIELD) {

 

        VariableElement varElement = (VariableElement) e;

 

        processingEnv.getMessager().printMessage(

            Diagnostic.Kind.NOTE,

            "annotated field: " + varElement.getSimpleName(), e);

 

        fields.put(varElement.getSimpleName().toString(), varElement);

 

    } else if (e.getKind() == ElementKind.METHOD) {

 

        ExecutableElement exeElement = (ExecutableElement) e;

 

        processingEnv.getMessager().printMessage(

            Diagnostic.Kind.NOTE,

            "annotated method: " + exeElement.getSimpleName(), e);

 

        methods.put(exeElement.getSimpleName().toString(), exeElement);

    }

}

 

步骤3:初始化Velocity Context并加载模板

 

下面的代码片段展示了如何初始化Velocity Context并加载模板:

 

if (fqClassName != null) {

 

    Properties props = new Properties();

    URL url = this.getClass().getClassLoader().getResource("velocity.properties");

    props.load(url.openStream());

 

    VelocityEngine ve = new VelocityEngine(props);

    ve.init();

 

    VelocityContext vc = new VelocityContext();

 

    vc.put("className", className);

    vc.put("packageName", packageName);

    vc.put("fields", fields);

    vc.put("methods", methods);

 

    Template vt = ve.getTemplate("beaninfo.vm");

    ...

}

 

Velocity配置文件,在本示例中名为velocity.properties,它应该被放置到src/main/resources目录下。下面是它的内容示例:

 

runtime.log.logsystem.class = org.apache.velocity.runtime.log.SystemLogChute

 

resource.loader = classpath

classpath.resource.loader.class = org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader

 

这组属性配置了Velocity的日志,以及一个用于查找模板的基本资源加载路径。

 

步骤4:创建新的源文件并生成源代码

 

紧接着,让我们创建新的源文件,并将这个新文件作为模板的目标来运行模板。下面的代码片段展示了如何操作:

 

JavaFileObject jfo = processingEnv.getFiler().createSourceFile(

    fqClassName + "BeanInfo");

 

processingEnv.getMessager().printMessage(

    Diagnostic.Kind.NOTE,

    "creating source file: " + jfo.toUri());

 

Writer writer = jfo.openWriter();

 

processingEnv.getMessager().printMessage(

    Diagnostic.Kind.NOTE,

    "applying velocity template: " + vt.getName());

 

vt.merge(vc, writer);

 

writer.close();

 

步骤5:打包并运行

 

最后,注册注解处理器(记得添加本系列第二部分中提到过的service配置文件),然后打包。再通过终端命令行,Eclipse或者Maven工具在client(客户)项目中进行调用和编译。

 

假设client项目中的client类如下:

 

package example.velocity.client;

import example.annotations.beaninfo.BeanInfo;

@BeanInfo public class Article {

    @BeanInfo private String id;

    @BeanInfo private int department;

    @BeanInfo private String status;

    public Article() {

        super();

    }

    public String getId() {

        return id;

    }

    public void setId(String id) {

        this.id = id;

    }

    public int getDepartment() {

        return department;

    }

    public void setDepartment(int department) {

        this.department = department;

    }

    public String getStatus() {

        return status;

    }

    public void setStatus(String status) {

        this.status = status;

    }

    @BeanInfo public void activate() {

        setStatus("active");

    }

    @BeanInfo public void deactivate() {

        setStatus("inactive");

    }

}

 

当我们在终端上执行javac命令后,我们可以在控制台上看到找到的被注解元素,以及生成的BeanInfo类:

 

Article.java:6: Note: annotated class: example.annotations.velocity.client.Article

public class Article {

       ^

Article.java:9: Note: annotated field: id

    private String id;

                   ^

Article.java:12: Note: annotated field: department

    private int department;

                ^

Article.java:15: Note: annotated field: status

    private String status;

                   ^

Article.java:53: Note: annotated method: activate

    public void activate() {

                ^

Article.java:59: Note: annotated method: deactivate

    public void deactivate() {

                ^

Note: creating source file: file:/c:/projects/example.annotations.velocity.client/src/main/java/example/annotations/velocity/client/ArticleBeanInfo.java

Note: applying velocity template: beaninfo.vm

Note: example\annotations\velocity\client\ArticleBeanInfo.java uses unchecked or unsafe operations.

Note: Recompile with -Xlint:unchecked for details.

 

如果我们检查下源代码目录,我们将会找到我们生成的BeanInfo类。任务完成!

 

 

本教程由尚硅谷教育大数据研究院出品,如需转载请注明来源。

猜你喜欢

转载自blog.csdn.net/sggtgfs/article/details/85242951