简体   繁体   English

使用注释创建可调用对象

[英]Creating Callables using Annotation

I'm attempting to make a system similar to https://github.com/ElgarL/TownyChat/blob/master/src/com/palmergames/bukkit/TownyChat/TownyChatFormatter.java 我正在尝试制作类似于https://github.com/ElgarL/TownyChat/blob/master/src/com/palmergames/bukkit/TownyChat/TownyChatFormatter.java的系统

replacer.registerFormatReplacement(Pattern.quote("{worldname}"), new TownyChatReplacerCallable() {
        @Override
        public String call(String match, LocalTownyChatEvent event) throws Exception {
            return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName());
        }
    });
    replacer.registerFormatReplacement(Pattern.quote("{town}"), new TownyChatReplacerCallable() {
        @Override
        public String call(String match, LocalTownyChatEvent event) throws Exception {
            return event.getResident().hasTown() ? event.getResident().getTown().getName() : "";
        }
    });

and more. 和更多。

Is there a way to use annotations to cut down on the amount of repeated code, avoiding reflection to call the call method, and only using it during registration, if at all? 有没有一种方法可以使用注释来减少重复代码的数量,避免反射调用调用方法,并且仅在注册期间使用它(如果有的话)?

I'm not adverse to the idea of creating an annotation pre processor as I was already planning on doing this to enable automatically generating documentation. 我并不反对创建注释预处理器的想法,因为我已经在计划这样做以启用自动生成文档。

Let's assume you write a small Annotation 假设您编写了一个小的注释

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface PatternHandler {
    String value();
}

And create a class like 并创建一个像

class Callables {

    @PatternHandler("foo")
    public static final TownyChatReplacerCallable FOO = new TownyChatReplacerCallable() {
        @Override
        public String call(String match, String event) {
            return "This is foo handler called with " + match + "," + event;
        }
    };

    @PatternHandler("bar")
    public static final TownyChatReplacerCallable BAR = new TownyChatReplacerCallable() {
        @Override
        public String call(String match, String event) {
            return "This is foo handler called with " + match + "," + event;
        }
    };
}

Now you can take the whole class or even multiple classes that contain those static fields and pass it to some registry method that iterates reflectively over each field in that class and if it's an annotated callable registers that. 现在,您可以采用包含这些静态字段的整个类,甚至多个类,并将其传递给某个注册表方法,该方法对该类中的每个字段进行反射性迭代,如果它是带注释的可调用寄存器。

class AnnotationRegistry {
    public static void register(String pattern, TownyChatReplacerCallable handler) {}

    public static void register(Class<?> clazz) {
        // only fields declared by this class, not inherited ones (static fields can't be inherited)
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            // must have that annotation
            PatternHandler annotation = field.getAnnotation(PatternHandler.class);
            if (annotation != null) {
                // must be static
                if (!Modifier.isStatic(field.getModifiers())) {
                    System.out.println("Field must be static:" + field.getName());
                    continue;
                }
                // get content of that field
                try {
                    Object object = field.get(null);
                    // must be != null and a callable
                    if (object instanceof TownyChatReplacerCallable) {
                        register(annotation.value(), (TownyChatReplacerCallable) object);
                    } else {
                        System.out.println("Field must be instanceof TownyChatReplacerCallable:"  + field.getName());
                    }
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

That would save you a bit code and would have no speed disadvantage at runtime since there is no need to use reflection to call those callables. 这将节省您一些代码,并且在运行时不会对速度造成不利影响,因为不需要使用反射来调用那些可调用对象。

Full example here: http://ideone.com/m3PPcY 此处的完整示例: http : //ideone.com/m3PPcY

Besides using static fields, you can also use non static ones if you pass an instance of a class to the registry which would then be used like Object object = field.get(instance); 除了使用静态字段外,如果将类的实例传递给注册表,则也可以使用非静态字段,然后将其用作Object object = field.get(instance); instead of the null . 而不是null

Furthermore, instead of fields the same approach would work with methods which would be less code to write: 此外,代替字段的是相同的方法,它可以与编写更少代码的方法一起使用:

@PatternHandler("foo")
public static String fooMethod(String match, String event) {
    return "This is foo handler called with " + match + "," + event;
}

Registry would then look for all Method s. 然后,注册表将查找所有Method Then for example wrap them in 然后例如将它们包起来

class MethodAdapter implements TownyChatReplacerCallable {
    private final Method method;
    public MethodAdapter(Method m) {
        method = m;
    }
    @Override
    public String call(String match, String event) {
        try {
            return (String) method.invoke(null, match, event);
        } catch (Exception e) {
            e.printStackTrace();
            return "OMGZ";
        }
    }
}

and continue as usual. 并照常继续。 But beware: invoking a method reflectively is potentially slower than calling it directly via code - few percent only, nothing to worry about 但要注意:与通过代码直接调用相比,以反射方式调用方法可能会更慢-仅占百分之几,无需担心

Full example for methods: http://ideone.com/lMJsrl 方法的完整示例: http : //ideone.com/lMJsrl

You can try new Java 8 Lambda Expressions instead ( http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html ). 您可以改用新的Java 8 Lambda表达式( http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html )。

replacer.registerFormatReplacement(Pattern.quote("{worldname}"), new TownyChatReplacerCallable() {
        @Override
        public String call(String match, LocalTownyChatEvent event) throws Exception {
            return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName());
        }
    });

Can be written as : 可以写成:

replacer.registerFormatReplacement(
  Pattern.quote("{worldname}"), 
  (match, event) -> { return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName()); } 
});

You can also push it further with another interface, method, ... that wrap it 您还可以通过包装它的另一个接口,方法...来进一步推动它

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在 java 中创建和使用注释 - Creating and using annotation in java Java ThreadPoolExexecutor使用流和可调用对象 - Java ThreadPoolExexecutor using streams and Callables 创建自定义注释并在Java中使用它? - creating custom annotation and using it in java? 使用休眠注释时未创建数据库表 - Database table not creating while using hibernate annotation 使用ExecutorService和Callables无法捕获特定异常? - Can't catch specific exception using ExecutorService and Callables? 如何使用ExecutorService管理未知数量的Callables的返回值? - How to manage return values of an unknown amount of Callables using ExecutorService? 在Spring中创建新实例和使用范围原型注释之间的区别 - Difference between creating new instance and using scope prototype annotation in Spring 使用基于注释的配置创建延迟初始化的Spring bean - Creating lazily initialized Spring beans using annotation based configuration 使用内置注释创建自定义验证注释 - Creating custom validation annotation using built-in annotations 使用 @Bean Spring 注释创建 bean 时出现异常 - Getting Exception while creating beans using @Bean Spring annotation
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM