*在编译期间注入“接口方法实现”

时间:2015-01-22 14:03:22

标签: java enums proxy

请考虑以下事项:

public interface MyFilter {

  @FilterAttribute
  String getAttribute();
}

@Retention(RUNTIME)
@Target(METHOD)
@Implementor(AutoEnumFilterAttribute.class)
public @interface FilterAttribute{
}

public enum MyEnumType2Filter implements MyFilter{
  TYPE0,
  TYPE1;
}

public enum MyEnumType2Filter implements MyFilter{
  TYPE20,
  TYPE21;
}

还有更多......

MyFilter.getAttribute()实现在所有情况下看起来都是这样的。

...
public String getAttribute() {
  return "attribute."+name().toLowerCase()+".filter";
}
...

我们可以看到,在实现此接口的每个枚举中都有不必要的重复实现。 当然,我可以有一个单独的助手类,我做这样的事情

public final class MyFilterHelp {

  public static String getAttribute(MyFilter filter) {
    //check that it is an enum then,
    return "attribute."+filter.name().toLowerCase()+".filter";
  }
}

or
public enum MyEnum implements MyFilter {
   TYPE20;

   private String attribute;
   private MyEnum () {
      this.attribute = "attribute."+name().toLowerCase()+".filter";
   }

   public  Strign getAttribute() {
     return this.attribute;
   }
}

但是这个第一个选项将属性与枚举分开,而section选项仍然需要为实现此接口的每个枚举实现。

我的愿景是。

public class AutoEnumFilterAttribute<MyFilter> {

      public String getAttribute(MyFilter filter) {
        //check that it is an enum then,
        return "attribute."+filter.name().toLowerCase()+".filter";
      }
}

并且通常使用我的枚举过滤器(AutoEnumFilterAttribute在某种程度上像代理一样):

MyFilter filter = ...
String attribute = filter.getAttribute();

我猜测我可以通过&#34;注射&#34;在编译期间实现此接口的每个枚举中实现MyFilter.getAttribute()。

关于如何解决这个问题的任何想法? 考虑jdk7或以下。

正如所回答的那样,可以使用java8 default method

来做到这一点

1 个答案:

答案 0 :(得分:1)

如果您正在使用 Java 8 ,则可以在界面中使用default method。如果你将它与指定枚举方法name()结合起来,那么你就会非常接近你想要的东西。

interface MyFilter {

    default String getAttribute() {
        return "attribute."+name().toLowerCase()+".filter";
    } // you no longer have to implement this in your enums

    String name(); // you need to specify this method here in order to use it in the default method
}

由于每个枚举都已经实现了name(),因此对现有类没有任何惩罚(即不进行重构),并且您将以简洁的方式获得所需的API方法。

如果您正在使用旧版本的Java ,那么您的解决方案将会相当复杂。您可以考虑撰写Annotation Preprocessor。我自己没有使用它们,但我曾经看过一个演示并且已经阅读了一些它。请记住,我可能没有把一切都弄好。

一个非常简短的总结是,您可以使用自定义注释标记类,并让Annotation预处理器选择这些类并为它们自动生成一些代码。最好的部分是编译器在编译时会知道这一点,因为您可以将预处理器配置为在编译器之前运行。因此,编译器不会忽视您在“预编译”时添加的任何方法。

所以我的想法是创造这样的东西:

interface MyFilter {

    String getAttribute();
}

@AddGetAttribute
enum MyEnumType2Filter implements MyFilter {
    TYPE20, TYPE21
}

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.CLASS)
@interface AddGetAttribute {}

@SupportedAnnotationTypes("com.blagae.AddGetAttribute")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class AttributeProcessor extends AbstractProcessor {

    public AttributeProcessor() {
        super();
    }

    public boolean process(Set<? extends TypeElement> annotations,
                                   RoundEnvironment roundEnv) {
        /* this method should let you add the source code for your enums
           see links below for some basic examples
           you will need to try and add a method to your existing class,
           instead of creating a new class file as these links do.
         */
        return false;
    }
}

我承诺的链接:

using Velocity