1

I'm attempting to make a system similar to 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.

4

2 回答 2

1

假设你写了一个小注解

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

并创建一个类

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;
        }
    };
}

现在,您可以获取包含这些静态字段的整个类甚至多个类,并将其传递给某个注册表方法,该方法在该类中的每个字段上进行反射式迭代,并且如果它是带注释的可调用寄存器,则该方法会注册。

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();
                }
            }
        }
    }
}

这将为您节省一些代码,并且在运行时不会有速度劣势,因为不需要使用反射来调用这些可调用对象。

完整示例:http: //ideone.com/m3PPcY

除了使用静态字段外,如果您将类的实例传递给注册表,您还可以使用非静态字段,然后像Object object = field.get(instance);使用null.

此外,与字段相同的方法将适用于编写更少代码的方法:

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

然后注册表会查找所有Methods。然后例如将它们包装在

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";
        }
    }
}

并像往常一样继续。但请注意:反射调用方法可能比直接通过代码调用要慢 - 仅百分之几,无需担心

方法的完整示例:http: //ideone.com/lMJsrl

于 2013-07-25T22:23:06.063 回答
0

您可以尝试新的 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());
        }
    });

可以写成:

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

您还可以使用另一个接口、方法等来进一步推动它

于 2013-07-25T13:24:38.187 回答