天天看点

Think in Java -- Annotation

  在java SE5中,引入了Annotation的概念。引入Annotation,我们可以把一些metadata信息也放在源码文件里面,而不用放在另外一个文件。例如在Spring中,我们可以使用annotation来实现很多的功能。用起来也是非常的方便。特别是我们在写一些框架的时候,如果能自己定义一些Annotation,可以让我们的框架变得更加的好用。

  •   Annotation的简单语法
import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)

public @interface UseCase {
    public int id();
    public String description() default "no description";
}
           

这里我们可以看到,其他Annotation的定义和interface的定义十分的相似,只是多了一个@.在上面定义的过程中,我们发现我们使用了两个Annotation。一个是Target,一个是Retention。Target的作用是表明,我们这个定义的UseCase Annotation是用在哪里的。这里我们创建的UseCase是用来修改Method的。ElementType还有其他类型,可以参考 http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/annotation/Retention.html。Retention是用来表用,我们创建的Annotation是在哪里生效的。我们定义的Annotation是用来在运行时候用的,所以应该定义为RUNTIME。RetentionPolicy还有其他类型,可以参考 http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/annotation/Retention.html。

  • Annotation的使用
import java.util.*;

public class PasswordUtils {
    @UseCase(id = 47 , description = "Passwords must contain at least one numeric")
    public boolean validatePassword(String password) {
        return (password.matches("\\w*\\d\\w*"));
    }

    @UseCase(id = 48, description = null)
    public String encryptPassword(String password) {
        return new StringBuilder(password).reverse().toString();
    }

    @UseCase(id = 49 , description = "New passwords can't equal previously used ones")
    public boolean checkForNewPassword(List<String>previousPasswords , String password) {
        return !previousPasswords.contains(password);
    }
}
           

我们使用上面定义的Annotation,来修饰PasswordUtils中的类。在这里我们需要注意的是,UseCase中,有些值有有默认值的,我们可以不给他赋值,如果没有默认值的话,是一定需要赋值的。 还有另外一点需要注意的,非primitive类型的数据,不能赋值为null.*(其实primitive类型的本来就不能赋值为null)

  • 处理Annotation

在上面,我们在PasswordUtils中使用了我们自己定义的Annotation。但是我们仅仅把Annotation加进去还是远远不够的。Java中的一个默认的Annotation,如Override,Java中有专门的程序来处理这些Annotation。所以对于我们自己定义的Annotation,我们也需要自己定义程序来处理这些Annotation。

import java.lang.reflect.*;
import java.util.*;

public class UseCaseTracker {
    public static void trackUseCases(List<Integer>useCases , Class<?>cl) {
        for (Method m : cl.getDeclaredMethods()) {
            UseCase uc = m.getAnnotation(UseCase.class);
            if (uc != null) {
                System.out.println("Found Use Case:" + uc.id() + " " + uc.description());
                useCases.remove(new Integer(uc.id()));
            }
        }
        for (int i : useCases) {
            System.out.println("Warning: Missing use case-" + i);
        }
    }

    public static void main(String args[]) {
        List<Integer> useCases = new ArrayList<Integer>();
        Collections.addAll(useCases , 47 , 48 , 49 , 50);
        trackUseCases(useCases , PasswordUtils.class);
    }
}
           

上面的程序中,我们使用到了Java中的反射的一些内容。