Java核心技术之注解处理

注解处理

运行时处理

定义一个注解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源文件,然后在将生成的源文件和指定的源文件一起编译。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值