Java核心技术之注解处理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cwt8805/article/details/52350982

注解处理

运行时处理

定义一个注解ToString(注解本质上就是一种接口)

@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ToString {
    boolean includeName() default true;
}

任意需要格式化打印的类对象可以使用以上注解

@ToString(includeName=false)
public class Point {
    @ToString(includeName=false) private int x;
    @ToString(includeName=false) private int y;
    …
}

@ToString
public class Rectangle {
    @ToString(includeName=false) private Point topLeft;
    @ToString private int width;
    @ToString private int height;
    …
}

使用反射进行注解处理

public class ToStrings {
    public static String toString(Object obj) {
        if (obj == null) return "null";
        Class<?> cl = obj.getClass();
        ToString ts = cl.getAnnotation(ToString.class);
        if (ts == null) return obj.toString();
        StringBuilder result = new StringBuilder();
        if (ts.includeName()) result.append(cl.getName());
        result.append("[");
        boolean first = true;
        for (Field f : cl.getDeclaredFields()) {
            ts = f.getAnnotation(ToString.class);
            if (ts != null) {
                if (first) first = false; else result.append(",");
                f.setAccessible(true);
                if (ts.includeName()) {
                    result.append(f.getName());
                    result.append("=");
                }
                try {
                    result.append(ToStrings.toString(f.get(obj)));
                } catch (ReflectiveOperationException ex) {
                    ex.printStackTrace();
                }
            }
        }
        result.append("]");
        return result.toString();
    }
}

源码级的注解处理(代码生成)

首先定义一个注解处理器,如下继承AbstractProcessor

@SupportedAnnotationTypes("com.horstmann.annotations.ToString")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class ToStringAnnotationProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations,
            RoundEnvironment currentRound) {
        if (annotations.size() == 0) return true;
        try {
            JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile("com.horstmann.annotations.ToStrings");
            try (PrintWriter out = new PrintWriter(sourceFile.openWriter())) {
                out.println("// Automatically generated by com.horstmann.annotations.ToStringAnnotationProcessor");
                out.println("package com.horstmann.annotations;");
                out.println("public class ToStrings {");

                for (Element e : currentRound.getElementsAnnotatedWith(ToString.class)) {
                    if (e instanceof TypeElement) {
                        TypeElement te = (TypeElement) e;
                            writeToStringMethod(out, te);
                    }
                }   
                out.println("    public static String toString(Object obj) {");
                out.println("        return java.util.Objects.toString(obj);");
                out.println("    }");
                out.println("}");
            }
        } catch (IOException ex) {
            processingEnv.getMessager().printMessage(Kind.ERROR, ex.getMessage());
        }        
        return true;
    }

    private void writeToStringMethod(PrintWriter out, TypeElement te) {
        String className = te.getQualifiedName().toString();
        out.println("    public static String toString(" + className + " obj) {");
        ToString ann = te.getAnnotation(ToString.class);
        out.println("        StringBuilder result = new StringBuilder();");
        if (ann.includeName()) out.println("        result.append(\"" + className + "\");");        
        out.println("        result.append(\"[\");");
        boolean first = true;
        for (Element c : te.getEnclosedElements()) {
            String methodName = c.getSimpleName().toString();
            ann = c.getAnnotation(ToString.class);
            if (ann != null) {             
                if (first) first = false; else out.println("        result.append(\",\");");
                if (ann.includeName()) {
                    String fieldName = Introspector.decapitalize(methodName.replaceAll("^(get|is)", ""));
                        // Turn getWidth into width, isDone into done, getURL into URL 
                    out.println("        result.append(\"" + fieldName + "=" + "\");"); 
                }
                out.println("        result.append(toString(obj." + methodName + "()));");
            }
        }
        out.println("        result.append(\"]\");");
        out.println("        return result.toString();");
        out.println("    }");
    }    
}

要在编译时使用该Processor,首先使用javac对其进行编译

然后再使用编译好的Processor编译其他源文件。javac -processor xxxProcessor xxxSourceFiles
在这个过程中Processor会先生成java源文件,然后在将生成的源文件和指定的源文件一起编译。

猜你喜欢

转载自blog.csdn.net/cwt8805/article/details/52350982
今日推荐