-
Notifications
You must be signed in to change notification settings - Fork 1
Dependency Injection
DEVIN has it's own flexible dependency injection system for the commands, events and pretty much anything you could possibly need. This was made to save more time and make the code more maintainable by eliminating constructors that would just contain the plugin and a few other things across multiple objects with the same values. We could make the variables static, but if you injected them we could keep everything private and out of reach of other plugins. Before we get into injecting our managers, plugins, and other stuff into our command classes and events, lets talk about the basics.
Everything that goes into commands, events, and other objects comes from the injector. Each plugin is assigned it's own global injector which can be obtained like so:
public class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
Injector injector = Devin.getInjector(this); // Global Injector
Injector localInjector = new Injector(); // Local Injector.
}
}Injections are the objects that are going to be injected into your objects. You can either add one with a name or without one. If the injection has a name, the name of the field in every object must match that name. This is useful for when you need multiple objects of the same type, since each injection needs a unique name and type pair. If you do not include a name, then the fields can be named whatever you want them to be.
public class MyPlugin extends JavaPlugin {
private SomeManager manager;
private ThingManager thingManager;
@Override
public void onEnable() {
manager = new SomeManager();
thingManager = new ThingManager();
Injector injector = Devin.getInjector(this); // Global Injector
injector.add(manager); // Injections without a name
injector.add(thingManager, "thingManager"); // Named injection
}
}Lets get to the part where we can finally see some results, injecting our object. To have a field accept our injection, we must annotate it with @Inject. The field must match at least one of the injections that we gave it or it will through an error while debugging. This will not break the code, the variable will just be the default. Lets make a simple class that can accept our injections.
public class MyObject {
@Inject
private SomeManager manager;
@Inject
private ThingManager thingManager;
public SomeManager getManager() { return manager; }
public ThingManager getThingManager() { return thingManager; }
}Now we have a class that can accept our injections, so lets inject it!
public class MyPlugin extends JavaPlugin {
private SomeManager manager;
@Override
public void onEnable() {
manager = new SomeManager();
Injector injector = Devin.getInjector(this); // Global Injector
injector.add(manager); // Injections without a name
MyObject obj = new MyObject();
injector.inject(obj);
System.out.println(obj.getManager());
}
}The injector also allows you to pass in local injections so that one object specifically gets additional or different injections. Any local injections that have equivalent name and type pair in the global injections would override the global injections entirely. To do this, you need to pass in InjectedObject's into the inject method. An InjectedObject is a object which contains the name and type information, as well as the real value. These are automatically created behind the scenes when using the add methods.
public class MyPlugin extends JavaPlugin {
private SomeManager manager;
@Override
public void onEnable() {
manager = new SomeManager();
Injector injector = Devin.getInjector(this); // Global Injector
injector.add(manager); // Injections without a name
MyObject obj = new MyObject();
injector.inject(obj, new InjectedObject(new SomeManager("different")));
System.out.println(obj.getManager());
}
}Now we get to the fun stuff, injecting our commands. If you haven't read through Command 101, then I suggest you do so because this will contain information that was gone over on that page. Injecting into commands is very similar to how we injected objects.
public class MyPlugin extends JavaPlugin {
private SomeManager manager;
@Override
public void onEnable() {
manager = new SomeManager();
Injector injector = Devin.getInjector(this); // Global Injector
injector.add(manager); // Injections without a name
CommandRegistrar cr = new CommandRegistrar(this, new MessageSender());
cr.registerCommands(new MyCommands()); // Registers and injects command.
}
}When injecting into a command, there is no need to call the inject method. Just add your injections as you would above and register your command. The one exception is that the MessageSender is injected as well without having to add it.
DEVIN has a short cut way of injecting your event listeners without having to inject the object then register the listener.
public class MyPlugin extends JavaPlugin {
private SomeManager manager;
@Override
public void onEnable() {
manager = new SomeManager();
Injector injector = Devin.getInjector(this); // Global Injector
injector.add(manager); // Injections without a name
Devin.registerEvents(new MyListener(), this);
}
}This method will now inject your events and register your event listener at the same time. This also shortens the code a few characters from Bukkit.getPluginManager().registerEvents.