Skip to content
This repository was archived by the owner on Aug 31, 2019. It is now read-only.

Commit 37da660

Browse files
committed
Support for provisioning command classes through Providers
1 parent 8f006f3 commit 37da660

6 files changed

Lines changed: 74 additions & 26 deletions

File tree

bukkit/src/main/java/com/sk89q/bukkit/util/CommandsManagerRegistration.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.ArrayList;
3131
import java.util.List;
3232
import javax.annotation.Nullable;
33+
import javax.inject.Provider;
3334

3435
/**
3536
* @author zml2008
@@ -53,7 +54,11 @@ public CommandsManagerRegistration(Plugin plugin, CommandExecutor executor, @Nul
5354
}
5455

5556
public boolean register(Class<?> clazz) {
56-
return registerAll(commands.registerAndReturn(clazz));
57+
return register(clazz, null);
58+
}
59+
60+
public <T> boolean register(Class<T> clazz, @Nullable Provider<? extends T> provider) {
61+
return registerAll(commands.registerMethods(clazz, null, provider));
5762
}
5863

5964
public boolean registerAll(List<Command> registered) {

bungee/src/main/java/com/sk89q/bungee/util/CommandRegistration.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.sk89q.bungee.util;
22

33
import java.util.List;
4+
import javax.annotation.Nullable;
5+
import javax.inject.Provider;
46

57
import net.md_5.bungee.api.CommandSender;
68
import net.md_5.bungee.api.plugin.Plugin;
@@ -18,7 +20,11 @@ public CommandRegistration(Plugin plugin, PluginManager pluginManager, CommandsM
1820
}
1921

2022
public boolean register(Class<?> clazz) {
21-
return this.registerAll(this.commands.registerAndReturn(clazz));
23+
return register(clazz, null);
24+
}
25+
26+
public <T> boolean register(Class<T> clazz, @Nullable Provider<? extends T> provider) {
27+
return this.registerAll(this.commands.registerMethods(clazz, null, provider));
2228
}
2329

2430
public boolean registerAll(List<Command> registered) {

core/pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,17 @@
1717
<dependency>
1818
<groupId>com.google.guava</groupId>
1919
<artifactId>guava</artifactId>
20-
<version>14.0.1</version>
20+
<version>17.0</version>
2121
</dependency>
2222
<dependency>
2323
<groupId>com.google.code.findbugs</groupId>
2424
<artifactId>annotations</artifactId>
2525
<version>3.0.0</version>
2626
</dependency>
27+
<dependency>
28+
<groupId>javax.inject</groupId>
29+
<artifactId>javax.inject</artifactId>
30+
<version>1</version>
31+
</dependency>
2732
</dependencies>
2833
</project>

core/src/main/java/com/sk89q/minecraft/util/commands/CommandsManager.java

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.logging.Level;
3535
import java.util.logging.Logger;
3636
import javax.annotation.Nullable;
37+
import javax.inject.Provider;
3738

3839
/**
3940
* Manager for handling commands. This allows you to easily process commands,
@@ -77,9 +78,10 @@ public abstract class CommandsManager<T> {
7778
protected Map<Method, Map<String, Method>> commands = new HashMap<Method, Map<String, Method>>();
7879

7980
/**
80-
* Used to store the instances associated with a method.
81+
* Used to store the providers associated with a method.
8182
*/
82-
protected Map<Method, Object> instances = new HashMap<Method, Object>();
83+
protected Map<Class, Object> instances = new HashMap<>();
84+
protected Map<Method, Provider> providers = new HashMap<>();
8385

8486
/**
8587
* Mapping of commands (not including aliases) with a description. This
@@ -136,8 +138,12 @@ public List<Command> registerAndReturn(Class<?> cls) {
136138
* @return Commands Registered
137139
*/
138140
public List<Command> registerMethods(Class<?> cls, Method parent) {
141+
return registerMethods(cls, parent, null);
142+
}
143+
144+
public <C> List<Command> registerMethods(Class<C> cls, @Nullable Method parent, @Nullable Provider<? extends C> provider) {
139145
try {
140-
return registerMethods(cls, parent, null);
146+
return registerMethods0(cls, parent, provider);
141147
} catch (InvocationTargetException | IllegalAccessException | InstantiationException e) {
142148
throw new CommandRegistrationException("Failed to register commands in class " + cls.getName(), e);
143149
}
@@ -148,10 +154,10 @@ public List<Command> registerMethods(Class<?> cls, Method parent) {
148154
*
149155
* @param cls the class to register
150156
* @param parent the parent method
151-
* @param obj the object whose methods will become commands if they are annotated
157+
* @param provider provides instances of the command method, or null to use the {@link Injector}
152158
* @return a list of commands
153159
*/
154-
private List<Command> registerMethods(Class<?> cls, Method parent, Object obj) throws IllegalAccessException, InstantiationException, InvocationTargetException {
160+
private <C> List<Command> registerMethods0(Class<C> cls, Method parent, @Nullable Provider<? extends C> provider) throws IllegalAccessException, InstantiationException, InvocationTargetException {
155161
Map<String, Method> map;
156162
List<Command> registered = new ArrayList<Command>();
157163

@@ -186,24 +192,35 @@ private List<Command> registerMethods(Class<?> cls, Method parent, Object obj) t
186192

187193
// We want to be able invoke with an instance
188194
if (!isStatic) {
189-
if(obj == null) {
190-
if(injector != null) {
191-
obj = injector.getInstance(cls);
192-
}
193-
194-
if(obj == null) {
195-
String text = "Failed to get an instance of " + cls.getName() +
196-
" for command method " + method.getDeclaringClass().getName() + "#" + method.getName();
197-
if(injector == null) {
198-
text += " (no Injector is available to create it)";
199-
} else {
200-
text += " (the Injector returned null when asked for one)";
195+
if(provider == null && injector != null) {
196+
// If we weren't given a Provider, try to get one from the Injector
197+
provider = injector.getProviderOrNull(cls);
198+
if(provider == null) {
199+
// If we can't get a provider, check if we have already instantiated the class
200+
C instance = (C) instances.get(cls);
201+
if(instance == null) {
202+
// If we haven't, do that now and save it
203+
instance = (C) injector.getInstance(cls);
204+
instances.put(cls, instance);
201205
}
202-
throw new CommandRegistrationException(text);
206+
// Generate a provider that just returns the saved instance
207+
final C finalInstance = instance;
208+
provider = () -> finalInstance;
203209
}
204210
}
205211

206-
instances.put(method, obj);
212+
if(provider != null) {
213+
providers.put(method, provider);
214+
} else {
215+
String text = "Failed to get an instance/provider of " + cls.getName() +
216+
" for command method " + method.getDeclaringClass().getName() + "#" + method.getName();
217+
if(injector == null) {
218+
text += " (no Injector is available to create it)";
219+
} else {
220+
text += " (the Injector returned null when asked for one)";
221+
}
222+
throw new CommandRegistrationException(text);
223+
}
207224
}
208225

209226
// Build a list of commands and their usage details, at least for
@@ -253,7 +270,7 @@ private List<Command> registerMethods(Class<?> cls, Method parent, Object obj) t
253270
}
254271

255272
if (cls.getSuperclass() != null) {
256-
registerMethods(cls.getSuperclass(), parent, obj);
273+
registerMethods0(cls.getSuperclass(), parent, provider);
257274
}
258275

259276
return registered;
@@ -551,7 +568,8 @@ private List<String> executeMethod(Method parent, boolean completing, String[] a
551568

552569
methodArgs[0] = context;
553570

554-
Object instance = instances.get(method);
571+
Provider provider = providers.get(method);
572+
Object instance = provider == null ? null : provider.get();
555573

556574
// If we get here while completing, it means the method's return type is a List<String>,
557575
// and we never want to use the default completion. So if it returns null, convert it to

core/src/main/java/com/sk89q/minecraft/util/commands/Injector.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,26 @@
2020
package com.sk89q.minecraft.util.commands;
2121

2222
import java.lang.reflect.InvocationTargetException;
23+
import javax.annotation.Nullable;
24+
import javax.inject.Provider;
2325

2426
/**
2527
* Constructs new instances.
2628
*/
2729
public interface Injector {
2830

31+
/**
32+
* Return a {@link Provider} for the given command class. The framework will
33+
* call this at registration time, and use the provider to get a {@link T}
34+
* instance every time a command is executed.
35+
*
36+
* If null is returned, then {@link #getInstance(Class)} will be called at
37+
* registration time to get the instance, and it will be reused forever.
38+
*/
39+
default @Nullable <T> Provider<? extends T> getProviderOrNull(Class<T> cls) {
40+
return null;
41+
}
42+
2943
/**
3044
* Constructs a new instance of the given class.
3145
*

pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@
4141
<artifactId>maven-compiler-plugin</artifactId>
4242
<version>3.1</version>
4343
<configuration>
44-
<source>1.7</source>
45-
<target>1.7</target>
44+
<source>1.8</source>
45+
<target>1.8</target>
4646
</configuration>
4747
</plugin>
4848

0 commit comments

Comments
 (0)