我已经建立了一个系统,用于通过将特定类传递给getter方法来检索侦听器类。例如,你可以像这样调用它:
GlobalListener lis = /*Manager instance*/.getListener(GlobalListener.class);
/*Manager instance*/
是我的ListenerManager
类的实例,其中包含以下缩写内容:
public class ListenerManager {
private final Project project;
private final Map<String, SubListener> listeners = new HashMap<>();
/**
* {@link ListenerManager} constructor
*
* @since 1.0.0
* @version 1.0.0
*
* @param plugin The main {@link Project} instance
*/
public ListenerManager(Project project) {
this.project = project;
this.registerDefaults();
}
private void registerDefaults() {
SubListener[] list = new SubListener[] {
new GlobalListener(this.project),
new ItemListener(this.project)
};
for (SubListener lis : list) {
this.registerListener(lis);
}
}
/**
* Gets a listener by its string name. Returns null if the listener is
* disabled or not registered.
*
* @since 1.0.0
* @version 1.0.0
*
* @param <T> The SubListener class
* @param listener An instance of the class type extending
* {@link SubListener} to retrieve
* @return The listener class, null if disabled or not registered
*/
public <T extends SubListener> T getListener(Class<T> listener) {
return listener.cast(this.listeners.get(this.getListenerName(listener)));
}
/**
* Retrieves a listener's name
*/
protected String getListenerName(Class<? extends SubListener> listener) {
try {
Method m = listener.getDeclaredMethod("getName");
return (String) m.invoke(null);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
this.project.getLogger().log(Level.SEVERE, "Error reflecting listener field for name!", ex);
}
return null;
}
/**
* Registers a listener through the plugin manager and {@link ListenerManager}
*
* @since 1.0.0
* @version 1.0.0
*
* @param <T> The {@link SubListener} to register
* @param listener The listener to register
* @throws ListenerReregisterException Attempted to register a Listener under a similar key
*/
public <T extends SubListener> void registerListener(T listener) throws ListenerReregisterException {
String name = listener.getName();
if (!this.listeners.containsKey(name)) {
this.listeners.put(name, listener);
this.project.getServer().getPluginManager().registerEvents(listener, this.plugin);
} else {
throw new ListenerReregisterException("Listener Map already contains key: " + name);
}
}
}
如图所示,它通过SubListener
反映方法getName
的{{1}}类,这是Method#invoke(null)
类的最终内容:
SubListener
然而,在我最近的测试中,这个系统似乎不再适用了,过去它的工作完全正常。现在,行public class SubListener implements Listener {
private final Project project;
public SubListener(Project project) {
this.project = project;
}
public final String getName() {
return this.getClass().getName() + "@" + this.getClass().getPackage().getName();
}
}
会抛出m.invoke(null)
。我认为这是因为我将NoSuchMethodException
传递给了null
参数,但是它如何在事先完美地运行,但现在正在破坏?
请注意,我无法选择将#invoke
方法设为静态,因为它可以通过获取当前的类来实现。通过getName
答案 0 :(得分:1)
您正在调用Method#invoke(Object, Object...)
方法,该方法接受访问者实例作为其第一个参数。
如果方法标记为null
,那么将static
作为第一个arg传递将非常正确,但您的方法是一个实例方法,正如您所提到的那样,并且您已发布的代码已经证明了这一点。 (我假设你没有在每个监听器上使用静态方法getName()
)
我无法完全回答为什么它之前有效 - 我唯一的猜测是你可能没有调用方法,因为我看不到任何方式可以在没有实例的情况下调用实例方法。< / p>
问题的一个可能解决方案是使用getClass().getName()
作为侦听器的键,因为在保存实例时以及在获取实例时都有类。此外,您的getName()
方法没有提供比我的方法更独特的密钥 - 它只是以另一种格式返回它。
旁注:Class#getName()
已经返回了类的完全限定名称,无需返回包名称 - 您的方法会产生my.package.Class@my.package
之类的内容。
答案 1 :(得分:1)
之前应该没有用,因为Method#invoke(null)
调用方法就好像它是静态的,这意味着没有对实例的引用。除非您有静态getName()
,否则这不应该有效。
你要么必须
A)让一个Listener实例代替null(Method#invoke(instance)
)
B)getName()
是一个静态方法,取决于项目是什么,可能不起作用