代码之家  ›  专栏  ›  技术社区  ›  Timo Westkämper

实现注释的用例

  •  36
  • Timo Westkämper  · 技术社区  · 14 年前

    实现注释的有效用例是什么?

    另一种方法是将注释中包含的数据镜像到dto中,这似乎是一种开销。

    举个例子:

    public enum IDType {
        LOCAL,
        URI,
        RESOURCE;
    }
    
    @Documented
    @Target( { METHOD, FIELD })
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    public @interface Id {
        /**
         * @return
         */
        IDType value() default IDType.LOCAL;
    }
    

    随着实施

    public class IdImpl implements Id{
    
        private final IDType idType;
    
        public IdImpl(IDType idType){
            this.idType = idType;
        }
    
        @Override
        public IDType value() {
            return idType;
        }
    
        @Override
        public Class<? extends Annotation> annotationType() {
            return Id.class;
        }
    
    }
    

    我得到了编译器的警告,但它似乎是许多用例的有效工具。

    用作IdImpl的超级接口

    编辑时间:

    我刚从 Guice :

    bind(CreditCardProcessor.class)
        .annotatedWith(Names.named("Checkout"))
        .to(CheckoutCreditCardProcessor.class);
    

    看到这个了吗 Javadoc from Names

    有没有人知道为什么会有这个限制,或者有其他的用例在想?

    4 回复  |  直到 14 年前
        1
  •  23
  •   gobernador    12 年前

    我从未在实践中使用过它,但您得到的是,您可以使用类来替换注释。

    让我们创建一个人工示例。假设我们有一个文档生成器。上面写着 @Docu 注释并打印 description 属性。这样地:

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.util.ArrayList;
    import java.util.List;
    
    public class DokuGenerator {
    
        public static void main(String[] args) throws Exception {
            new DokuGenerator(StaticClass.class, StaticClass2.class);
        }
    
        public DokuGenerator(Class<?>... classesToDokument) throws Exception {
            List<Docu> documentAnnotations = getDocumentAnnotations(classesToDokument);
            printDocumentation(documentAnnotations);
        }
    
        private List<Docu> getDocumentAnnotations(Class<?>... classesToDokument)
                throws Exception {
            List<Docu> result = new ArrayList<Docu>();
            for (Class<?> c : classesToDokument)
                if (c.isAnnotationPresent(Docu.class))
                    result.add(c.getAnnotation(Docu.class));
            return result;
        }
    
        private void printDocumentation(List<Docu> toDocument) {
            for (Docu m : toDocument)
                System.out.println(m.description());
        }
    
    }
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Docu {
        String description();
    }
    
    @Docu(description = "This is a static class!")
    class StaticClass {
    }
    
    @Docu(description = "This is another static class!")
    class StaticClass2 {
    }
    

    印刷品:

    This is a static class!  
    This is another static class!
    

    @文件 大多数时候都是注释,但有些特殊情况我们需要特殊的文档。我们可能需要为某些方法添加性能文档。我们可以通过让类实现注释来实现这一点。生成器首先检查注释,如果不存在,则检查类是否实现了注释。如果有,它会将类添加到注释列表中。

    这样(生成器中只有两行额外的代码):

    import java.lang.annotation.Annotation;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    public class DokuGenerator {
    
        public static void main(String[] args) throws Exception {
            new DokuGenerator(StaticClass.class, StaticClass2.class,
                    DynamicClass.class);
        }
    
        public DokuGenerator(Class<?>... classesToDokument) throws Exception {
            List<Docu> documentAnnotations = getDocumentAnnotations(classesToDokument);
            printDocumentation(documentAnnotations);
        }
    
        private List<Docu> getDocumentAnnotations(Class<?>... classesToDokument)
                throws Exception {
            List<Docu> result = new ArrayList<Docu>();
            for (Class<?> c : classesToDokument)
                if (c.isAnnotationPresent(Docu.class))
                    result.add(c.getAnnotation(Docu.class));
                else if (Arrays.asList(c.getInterfaces()).contains(Docu.class))
                    result.add((Docu) c.newInstance());
            return result;
        }
    
        private void printDocumentation(List<Docu> toDocument) {
            for (Docu m : toDocument)
                System.out.println(m.description());
        }
    
    }
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Docu {
        String description();
    }
    
    @Docu(description = "This is a static class!")
    class StaticClass {
    }
    
    @Docu(description = "This is another static class!")
    class StaticClass2 {
    }
    
    class DynamicClass implements Docu {
    
        public DynamicClass() {
            try {
                Thread.sleep((long) (Math.random() * 100));
            } catch (InterruptedException e) {
                // ignore exception to make debugging a little harder
            }
        }
    
        @Override
        public String description() {
            long millis = System.currentTimeMillis();
            new DynamicClass();
            millis = System.currentTimeMillis() - millis;
            return "This is a dynamic class. I run on "
                    + System.getProperty("os.name")
                    + ". The construction of an instance of this class run for "
                    + millis + " milliseconds.";
        }
    
        @Override
        public Class<? extends Annotation> annotationType() {
            return Docu.class;
        }
    
    }
    

    This is a static class!  
    This is another static class!  
    This is a dynamic class. I run on Windows XP. The construction of an instance of this class run for 47 milliseconds.
    

    您不必对代码生成器进行太多更改,因为您可以使用类替换注释。

    另一个例子是使用注释或XML作为配置的框架。您可能有一个处理注释的处理器。如果您使用XML作为配置,那么您可以生成实现注释的类的实例,并且您的处理器可以在不做任何更改的情况下对它们进行处理(当然还有其他方法可以达到同样的效果,但这是一种方法)

        2
  •  4
  •   sfussenegger    13 年前

    JAXBIntroductions 这是一个很好的例子:它允许使用XML文件配置JAXB注释。我们想到了两个主要用例:配置没有源代码访问权限的类,或者对一个类进行不同的配置。

    一般来说,我认为动态实例化注释以将它们传递给框架通常是一个很好的用例。但是,如果您是这个框架的设计者,我当然会三思而后行。

        3
  •  0
  •   Foumpie    7 年前

    我在创建注释时使用它,并希望在省略注释时提供默认值,从而使其使用成为可选的。当您的库引入了一个新的注释并且希望库保持向后兼容时,可能会发生这种情况。

    @Id
    class BeanA {}
    
    // No annotation
    class BeanB {}
    

    默认实现;

    private static final Id DEFAULT_ID = new Id() {
    
        @Override
        public IDType value() {
            return IDType.LOCAL;
        }
    
        @Override
        public Class<? extends Annotation> annotationType() {
            return Id.class;
        }
    };
    

    处理;

    Id beanId = (bean.getClass().isAnnotationPresent(Id.class))
        ? bean.getClass().getAnnotation(Id.class)
        : DEFAULT_ID;
    
        4
  •  -2
  •   Community CDub    8 年前

    没有有效的用户案例-编译器只是容忍它,因为禁止它会非常混乱,编写编译器的人可能在非常罕见的情况下需要该工具。如果您需要对注释进行分类,请参阅本文以了解如何进行分类: Why is not possible to extend annotations in Java?

    一个可怜的灵魂在你后面来维护和调试代码,或者另一个需要编写代码生成工具并假设注释类型是直接的,或者另一个仅仅使用这种注释的人,甚至没有梦想会发生什么以及如何处理它。当他发现黑客攻击并找到消除它的方法时,他将死于疝气或类似的疾病:-)注释被认为是纯粹的声明性语句,由codegen工具单独解释,该工具与注释代码分开运行并将其视为数据。

     public Class<? extends Annotation> annotationType() { 
         return Id.class; 
     } 
    

    与人们可以输入代码相比,这仍然是一件小事。

    注释不是练习黑客的地方-这是编译器试图传达的。你知道注解“实现”中的代码什么时候运行,怎样运行吗?包括CTOR?什么是可用的,什么是不可用的?什么是安全呼叫?编译器没有-编译器需要相当繁重的静态分析来检查这种黑客行为的实际安全性。因此,它只是发出一个警告,这样当出现问题时,人们就不能责怪compile、VM和其他任何东西。