@@ -28,6 +30,7 @@ public class NewAPI {
*
* @param plugin The AuthMe plugin instance
*/
+ @Inject
public NewAPI(AuthMe plugin) {
this.plugin = plugin;
}
diff --git a/src/main/java/fr/xephi/authme/command/CommandHandler.java b/src/main/java/fr/xephi/authme/command/CommandHandler.java
index 37c1a2a1..5f7b32af 100644
--- a/src/main/java/fr/xephi/authme/command/CommandHandler.java
+++ b/src/main/java/fr/xephi/authme/command/CommandHandler.java
@@ -1,14 +1,14 @@
package fr.xephi.authme.command;
-import java.util.ArrayList;
-import java.util.List;
-
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.help.HelpProvider;
+import fr.xephi.authme.util.StringUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
-import fr.xephi.authme.util.StringUtils;
+import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.List;
/**
* The AuthMe command handler, responsible for mapping incoming commands to the correct {@link CommandDescription}
@@ -29,6 +29,7 @@ public class CommandHandler {
*
* @param commandService The CommandService instance
*/
+ @Inject
public CommandHandler(CommandService commandService) {
this.commandService = commandService;
}
diff --git a/src/main/java/fr/xephi/authme/command/CommandMapper.java b/src/main/java/fr/xephi/authme/command/CommandMapper.java
index e43ee4bb..18473b28 100644
--- a/src/main/java/fr/xephi/authme/command/CommandMapper.java
+++ b/src/main/java/fr/xephi/authme/command/CommandMapper.java
@@ -1,11 +1,13 @@
package fr.xephi.authme.command;
import fr.xephi.authme.command.executable.HelpCommand;
+import fr.xephi.authme.initialization.BaseCommands;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.command.CommandSender;
+import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -28,7 +30,8 @@ public class CommandMapper {
private final Set baseCommands;
private final PermissionsManager permissionsManager;
- public CommandMapper(Set baseCommands, PermissionsManager permissionsManager) {
+ @Inject
+ public CommandMapper(@BaseCommands Set baseCommands, PermissionsManager permissionsManager) {
this.baseCommands = baseCommands;
this.permissionsManager = permissionsManager;
}
diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java
index 5c5abfcc..d4262944 100644
--- a/src/main/java/fr/xephi/authme/command/CommandService.java
+++ b/src/main/java/fr/xephi/authme/command/CommandService.java
@@ -19,6 +19,7 @@ import fr.xephi.authme.util.ValidationService;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import javax.inject.Inject;
import java.util.Collection;
import java.util.List;
@@ -28,39 +29,30 @@ import java.util.List;
*/
public class CommandService {
- private final AuthMe authMe;
- private final Messages messages;
- private final HelpProvider helpProvider;
- private final CommandMapper commandMapper;
- private final PasswordSecurity passwordSecurity;
- private final PermissionsManager permissionsManager;
- private final NewSetting settings;
- private final PluginHooks pluginHooks;
- private final SpawnLoader spawnLoader;
- private final AntiBot antiBot;
- private final ValidationService validationService;
- private final BukkitService bukkitService;
-
- /*
- * Constructor.
- */
- public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages,
- PasswordSecurity passwordSecurity, PermissionsManager permissionsManager, NewSetting settings,
- PluginHooks pluginHooks, SpawnLoader spawnLoader, AntiBot antiBot,
- ValidationService validationService, BukkitService bukkitService) {
- this.authMe = authMe;
- this.messages = messages;
- this.helpProvider = helpProvider;
- this.commandMapper = commandMapper;
- this.passwordSecurity = passwordSecurity;
- this.permissionsManager = permissionsManager;
- this.settings = settings;
- this.pluginHooks = pluginHooks;
- this.spawnLoader = spawnLoader;
- this.antiBot = antiBot;
- this.validationService = validationService;
- this.bukkitService = bukkitService;
- }
+ @Inject
+ private AuthMe authMe;
+ @Inject
+ private Messages messages;
+ @Inject
+ private HelpProvider helpProvider;
+ @Inject
+ private CommandMapper commandMapper;
+ @Inject
+ private PasswordSecurity passwordSecurity;
+ @Inject
+ private PermissionsManager permissionsManager;
+ @Inject
+ private NewSetting settings;
+ @Inject
+ private PluginHooks pluginHooks;
+ @Inject
+ private SpawnLoader spawnLoader;
+ @Inject
+ private AntiBot antiBot;
+ @Inject
+ private ValidationService validationService;
+ @Inject
+ private BukkitService bukkitService;
/**
* Send a message to a player.
diff --git a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java
index 7bc06f03..c5a3ec5f 100644
--- a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java
+++ b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java
@@ -10,10 +10,13 @@ import fr.xephi.authme.command.FoundCommandResult;
import fr.xephi.authme.permission.DefaultPermission;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsManager;
+import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.util.CollectionUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
+import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
@@ -45,9 +48,10 @@ public class HelpProvider {
private final PermissionsManager permissionsManager;
private final String helpHeader;
- public HelpProvider(PermissionsManager permissionsManager, String helpHeader) {
+ @Inject
+ public HelpProvider(PermissionsManager permissionsManager, NewSetting settings) {
this.permissionsManager = permissionsManager;
- this.helpHeader = helpHeader;
+ this.helpHeader = settings.getProperty(PluginSettings.HELP_HEADER);
}
public List printHelp(CommandSender sender, FoundCommandResult result, int options) {
diff --git a/src/main/java/fr/xephi/authme/hooks/PluginHooks.java b/src/main/java/fr/xephi/authme/hooks/PluginHooks.java
index 3a54709a..76f8e034 100644
--- a/src/main/java/fr/xephi/authme/hooks/PluginHooks.java
+++ b/src/main/java/fr/xephi/authme/hooks/PluginHooks.java
@@ -11,6 +11,7 @@ import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
+import javax.inject.Inject;
import java.io.File;
/**
@@ -28,6 +29,7 @@ public class PluginHooks {
*
* @param pluginManager The server's plugin manager
*/
+ @Inject
public PluginHooks(PluginManager pluginManager) {
this.pluginManager = pluginManager;
tryHookToCombatPlus();
@@ -75,13 +77,23 @@ public class PluginHooks {
return null;
}
+ /**
+ * Checks whether the player is an NPC.
+ *
+ * @param player The player to process
+ * @return True if player is NPC, false otherwise
+ */
+ public boolean isNpc(Player player) {
+ return player.hasMetadata("NPC") || isNpcInCombatTagPlus(player);
+ }
+
/**
* Query the CombatTagPlus plugin whether the given player is an NPC.
*
* @param player The player to verify
* @return True if the player is an NPC according to CombatTagPlus, false if not or if the plugin is unavailable
*/
- public boolean isNpcInCombatTagPlus(Player player) {
+ private boolean isNpcInCombatTagPlus(Player player) {
return combatTagPlus != null && combatTagPlus.getNpcPlayerHelper().isNpc(player);
}
diff --git a/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java b/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java
new file mode 100644
index 00000000..b751b32e
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/AuthMeServiceInitializer.java
@@ -0,0 +1,286 @@
+package fr.xephi.authme.initialization;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Provider;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Dependency injector of AuthMe: initializes and injects services and tasks.
+ *
+ * Only constructor and field injection are supported, indicated with the JSR330
+ * {@link javax.inject.Inject @Inject} annotation.
+ *
+ * {@link PostConstruct @PostConstruct} methods are recognized and invoked upon
+ * instantiation. Note that the parent classes are not scanned for such methods.
+ */
+public class AuthMeServiceInitializer {
+
+ private final Set ALLOWED_PACKAGES;
+ private final Map, Object> objects;
+
+ /**
+ * Constructor.
+ *
+ * @param allowedPackages list of allowed packages. Only classes whose package
+ * starts with any of the given entries will be instantiated
+ */
+ public AuthMeServiceInitializer(String... allowedPackages) {
+ ALLOWED_PACKAGES = ImmutableSet.copyOf(allowedPackages);
+ objects = new HashMap<>();
+ }
+
+ /**
+ * Retrieves or instantiates an object of the given type.
+ *
+ * @param clazz the class to retrieve the value for
+ * @param the class' type
+ * @return object of the class' type
+ */
+ public T get(Class clazz) {
+ return get(clazz, new HashSet>());
+ }
+
+ /**
+ * Registers an instantiation by its type.
+ *
+ * @param object the object to register
+ * @throws IllegalStateException if an object of the same type has already been registered
+ */
+ public void register(Object object) {
+ if (object instanceof Type) {
+ throw new IllegalStateException("You tried to register a Type object: '" + object
+ + "'. This likely indicates an error. Please use register(Class, T) if really desired.");
+ }
+ storeObject(object);
+ }
+
+ /**
+ * Register an object with a custom class (supertype). Use this for example to specify a
+ * concrete implementation of an interface or an abstract class.
+ *
+ * @param clazz the class to register the object for
+ * @param object the object
+ * @param the class' type
+ */
+ public void register(Class super T> clazz, T object) {
+ if (objects.containsKey(clazz)) {
+ throw new IllegalStateException("There is already an object present for " + clazz);
+ }
+ Preconditions.checkNotNull(object);
+ objects.put(clazz, object);
+ }
+
+ /**
+ * Associate an annotation with a value.
+ *
+ * @param annotation the annotation
+ * @param value the value
+ */
+ public void provide(Class extends Annotation> annotation, Object value) {
+ if (objects.containsKey(annotation)) {
+ throw new IllegalStateException("Annotation @" + annotation.getClass().getSimpleName()
+ + " already registered");
+ }
+ Preconditions.checkNotNull(value);
+ objects.put(annotation, value);
+ }
+
+ /**
+ * Returns an instance of the given class or the value associated with an annotation,
+ * by retrieving it or by instantiating it if not yet present.
+ *
+ * @param clazz the class to retrieve a value for
+ * @param traversedClasses the list of traversed classes
+ * @param the class' type
+ * @return instance or associated value (for annotations)
+ */
+ private T get(Class clazz, Set> traversedClasses) {
+ if (Annotation.class.isAssignableFrom(clazz)) {
+ throw new UnsupportedOperationException("Cannot retrieve annotated elements in this way!");
+ } else if (objects.containsKey(clazz)) {
+ return getObject(clazz);
+ }
+
+ // First time we come across clazz, need to instantiate it. Add the clazz to the list of traversed
+ // classes in a new list, so each path we need to take has its own Set.
+ validatePackage(clazz);
+ validateInstantiable(clazz);
+
+ traversedClasses = new HashSet<>(traversedClasses);
+ traversedClasses.add(clazz);
+ System.out.println(Strings.repeat(" ", traversedClasses.size() * 2) + "- Instantiating " + clazz);
+ return instantiate(clazz, traversedClasses);
+ }
+
+ /**
+ * Instantiates the given class by locating an @Inject constructor and retrieving
+ * or instantiating its parameters.
+ *
+ * @param clazz the class to instantiate
+ * @param traversedClasses collection of classes already traversed
+ * @param the class' type
+ * @return the instantiated object
+ */
+ private T instantiate(Class clazz, Set> traversedClasses) {
+ Injection injection = firstNotNull(ConstructorInjection.provide(clazz), FieldInjection.provide(clazz));
+ if (injection == null) {
+ throw new IllegalStateException("Did not find injection method for " + clazz + ". Make sure you have "
+ + "a constructor with @Inject or fields with @Inject. Fields with @Inject require "
+ + "the default constructor");
+ }
+
+ validateInjectionHasNoCircularDependencies(injection.getDependencies(), traversedClasses);
+ Object[] dependencies = resolveDependencies(injection, traversedClasses);
+ T object = injection.instantiateWith(dependencies);
+ storeObject(object);
+ executePostConstructMethods(object);
+ return object;
+ }
+
+ /**
+ * Resolves the dependencies for the given constructor, i.e. returns a collection that satisfy
+ * the constructor's parameter types by retrieving elements or instantiating them where necessary.
+ *
+ * @param injection the injection parameters
+ * @param traversedClasses collection of traversed classes
+ * @return array with the parameters to use in the constructor
+ */
+ private Object[] resolveDependencies(Injection> injection, Set> traversedClasses) {
+ Class>[] dependencies = injection.getDependencies();
+ Class>[] annotations = injection.getDependencyAnnotations();
+ Object[] values = new Object[dependencies.length];
+ for (int i = 0; i < dependencies.length; ++i) {
+ if (annotations[i] != null) {
+ Object value = objects.get(annotations[i]);
+ if (value == null) {
+ throw new IllegalStateException("Value for field with @" + annotations[i].getSimpleName()
+ + " must be registered beforehand");
+ }
+ values[i] = value;
+ } else {
+ values[i] = get(dependencies[i], traversedClasses);
+ }
+ }
+ return values;
+ }
+
+
+ /**
+ * Internal method to retrieve an object from the objects map for non-annotation classes.
+ * In such cases, the type of the entry always corresponds to the key, i.e. the entry of key
+ * {@code Class} is guaranteed to be of type {@code T}.
+ *
+ * To retrieve values identified with an annotation, use {@code objects.get(clazz)} directly.
+ * We do not know or control the type of the value of keys of annotation classes.
+ *
+ * @param clazz the class to retrieve the implementation of
+ * @param the type
+ * @return the implementation
+ */
+ private T getObject(Class clazz) {
+ Object o = objects.get(clazz);
+ if (o == null) {
+ throw new NullPointerException("No instance of " + clazz + " available");
+ }
+ return clazz.cast(o);
+ }
+
+ /**
+ * Stores the given object with its class as key. Throws an exception if the key already has
+ * a value associated to it.
+ *
+ * @param object the object to store
+ */
+ private void storeObject(Object object) {
+ if (objects.containsKey(object.getClass())) {
+ throw new IllegalStateException("There is already an object present for " + object.getClass());
+ }
+ Preconditions.checkNotNull(object);
+ objects.put(object.getClass(), object);
+ }
+
+ /**
+ * Validates that none of the dependencies' types are present in the given collection
+ * of traversed classes. This prevents circular dependencies.
+ *
+ * @param dependencies the dependencies of the class
+ * @param traversedClasses the collection of traversed classes
+ */
+ private static void validateInjectionHasNoCircularDependencies(Class>[] dependencies,
+ Set> traversedClasses) {
+ for (Class> clazz : dependencies) {
+ if (traversedClasses.contains(clazz)) {
+ throw new IllegalStateException("Found cyclic dependency - already traversed '" + clazz
+ + "' (full traversal list: " + traversedClasses + ")");
+ }
+ }
+ }
+
+ /**
+ * Validates the package of a parameter type to ensure that it is part of the allowed packages.
+ * This ensures that we don't try to instantiate things that are beyond our reach in case some
+ * external parameter type has not been registered.
+ *
+ * @param clazz the class to validate
+ */
+ private void validatePackage(Class> clazz) {
+ if (clazz.getPackage() == null) {
+ throw new IllegalStateException("Primitive types must be provided explicitly (or use an annotation).");
+ }
+ String packageName = clazz.getPackage().getName();
+ for (String allowedPackage : ALLOWED_PACKAGES) {
+ if (packageName.startsWith(allowedPackage)) {
+ return;
+ }
+ }
+ throw new IllegalStateException("Class " + clazz + " with package " + packageName + " is outside of the "
+ + "allowed packages. It must be provided explicitly or the package must be passed to the constructor.");
+ }
+
+ private static void executePostConstructMethods(Object object) {
+ for (Method method : object.getClass().getDeclaredMethods()) {
+ if (method.isAnnotationPresent(PostConstruct.class)) {
+ if (method.getParameterCount() == 0) {
+ try {
+ method.setAccessible(true);
+ method.invoke(object);
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new UnsupportedOperationException(e);
+ }
+ } else {
+ throw new IllegalStateException("@PostConstruct methods must have an empty parameter list. " +
+ "Found parameters in " + method + " belonging to " + object.getClass());
+ }
+ }
+ }
+ }
+
+ private static void validateInstantiable(Class> clazz) {
+ if (clazz.isEnum() || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers())) {
+ throw new IllegalStateException("Class " + clazz.getSimpleName() + " cannot be instantiated");
+ }
+ }
+
+ @SafeVarargs
+ private static Injection firstNotNull(Provider extends Injection>... providers) {
+ for (Provider extends Injection> provider : providers) {
+ Injection object = provider.get();
+ if (object != null) {
+ return object;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/initialization/BaseCommands.java b/src/main/java/fr/xephi/authme/initialization/BaseCommands.java
new file mode 100644
index 00000000..156cb947
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/BaseCommands.java
@@ -0,0 +1,14 @@
+package fr.xephi.authme.initialization;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to denote the collection of AuthMe commands.
+ */
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface BaseCommands {
+}
diff --git a/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java b/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java
new file mode 100644
index 00000000..f77ae58c
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/ConstructorInjection.java
@@ -0,0 +1,77 @@
+package fr.xephi.authme.initialization;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Functionality for constructor injection.
+ */
+class ConstructorInjection implements Injection {
+
+ private final Constructor constructor;
+
+ private ConstructorInjection(Constructor constructor) {
+ this.constructor = constructor;
+ }
+
+ @Override
+ public Class>[] getDependencies() {
+ return constructor.getParameterTypes();
+ }
+
+ @Override
+ public Class>[] getDependencyAnnotations() {
+ Annotation[][] parameterAnnotations = constructor.getParameterAnnotations();
+ Class>[] annotations = new Class>[parameterAnnotations.length];
+ for (int i = 0; i < parameterAnnotations.length; ++i) {
+ annotations[i] = parameterAnnotations[i].length > 0
+ ? parameterAnnotations[i][0].annotationType()
+ : null;
+ }
+ return annotations;
+ }
+
+ @Override
+ public T instantiateWith(Object... values) {
+ try {
+ return constructor.newInstance(values);
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ throw new UnsupportedOperationException(e);
+ }
+ }
+
+ public static Provider> provide(final Class clazz) {
+ return new Provider>() {
+ @Override
+ public ConstructorInjection get() {
+ Constructor constructor = getInjectionConstructor(clazz);
+ return constructor == null ? null : new ConstructorInjection<>(constructor);
+ }
+ };
+ }
+
+
+ /**
+ * Gets the first found constructor annotated with {@link Inject} of the given class
+ * and marks it as accessible.
+ *
+ * @param clazz the class to process
+ * @param the class' type
+ * @return injection constructor for the class
+ */
+ @SuppressWarnings("unchecked")
+ private static Constructor getInjectionConstructor(Class clazz) {
+ Constructor>[] constructors = clazz.getDeclaredConstructors();
+ for (Constructor> constructor : constructors) {
+ if (constructor.isAnnotationPresent(Inject.class)) {
+ constructor.setAccessible(true);
+ return (Constructor) constructor;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/fr/xephi/authme/initialization/DataFolder.java b/src/main/java/fr/xephi/authme/initialization/DataFolder.java
new file mode 100644
index 00000000..33b87997
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/DataFolder.java
@@ -0,0 +1,14 @@
+package fr.xephi.authme.initialization;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for specifying the plugin's data folder.
+ */
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DataFolder {
+}
diff --git a/src/main/java/fr/xephi/authme/initialization/FieldInjection.java b/src/main/java/fr/xephi/authme/initialization/FieldInjection.java
new file mode 100644
index 00000000..aafb0bde
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/FieldInjection.java
@@ -0,0 +1,112 @@
+package fr.xephi.authme.initialization;
+
+import com.google.common.base.Preconditions;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Functionality for field injection.
+ */
+class FieldInjection implements Injection {
+
+ private final Field[] fields;
+ private final Constructor defaultConstructor;
+
+ private FieldInjection(Constructor defaultConstructor, Collection fields) {
+ this.fields = fields.toArray(new Field[fields.size()]);
+ this.defaultConstructor = defaultConstructor;
+ }
+
+ @Override
+ public Class>[] getDependencies() {
+ Class>[] types = new Class>[fields.length];
+ for (int i = 0; i < fields.length; ++i) {
+ types[i] = fields[i].getType();
+ }
+ return types;
+ }
+
+ @Override
+ public Class>[] getDependencyAnnotations() {
+ Class>[] annotations = new Class>[fields.length];
+ for (int i = 0; i < fields.length; ++i) {
+ annotations[i] = getFirstNonInjectAnnotation(fields[i]);
+ }
+ return annotations;
+ }
+
+ @Override
+ public T instantiateWith(Object... values) {
+ Preconditions.checkArgument(values.length == fields.length,
+ "The number of values must be equal to the number of fields");
+
+ T instance;
+ try {
+ instance = defaultConstructor.newInstance();
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ throw new UnsupportedOperationException(e);
+ }
+
+ for (int i = 0; i < fields.length; ++i) {
+ try {
+ fields[i].set(instance, values[i]);
+ } catch (IllegalAccessException e) {
+ throw new UnsupportedOperationException(e);
+ }
+ }
+ return instance;
+ }
+
+ private static Class> getFirstNonInjectAnnotation(Field field) {
+ for (Annotation annotation : field.getAnnotations()) {
+ if (annotation.annotationType() != Inject.class) {
+ return annotation.annotationType();
+ }
+ }
+ return null;
+ }
+
+ public static Provider> provide(final Class clazz) {
+ return new Provider>() {
+ @Override
+ public FieldInjection get() {
+ Constructor constructor = getDefaultConstructor(clazz);
+ if (constructor == null) {
+ return null;
+ }
+ List fields = getInjectionFields(clazz);
+ return fields == null ? null : new FieldInjection<>(constructor, fields);
+ }
+ };
+ }
+
+ private static List getInjectionFields(Class> clazz) {
+ List fields = new ArrayList<>();
+ for (Field field : clazz.getDeclaredFields()) {
+ if (field.isAnnotationPresent(Inject.class)) {
+ field.setAccessible(true);
+ fields.add(field);
+ }
+ }
+ return fields;
+ }
+
+ private static Constructor getDefaultConstructor(Class clazz) {
+ try {
+ Constructor> defaultConstructor = clazz.getDeclaredConstructor();
+ defaultConstructor.setAccessible(true);
+ return (Constructor) defaultConstructor;
+ } catch (NoSuchMethodException ignore) {
+ // no default constructor available
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/initialization/Injection.java b/src/main/java/fr/xephi/authme/initialization/Injection.java
new file mode 100644
index 00000000..6e85b4ce
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/initialization/Injection.java
@@ -0,0 +1,36 @@
+package fr.xephi.authme.initialization;
+
+/**
+ * Common interface for all injection methods.
+ *
+ * @param the type of the concerned object
+ */
+interface Injection {
+
+ /**
+ * Returns the dependencies that must be provided to instantiate the given item.
+ *
+ * @return list of dependencies
+ * @see #instantiateWith
+ */
+ Class>[] getDependencies();
+
+ /**
+ * Returns the annotation on each dependency if available. The indices of this
+ * array correspond to the ones of {@link #getDependencies()}. If no annotation
+ * is available, {@code null} is stored. If multiple annotations are present, only
+ * one is stored (no guarantee on which one).
+ *
+ * @return annotation for each dependency
+ */
+ Class>[] getDependencyAnnotations();
+
+ /**
+ * Creates a new instance with the given values as dependencies. The given values
+ * must correspond to {@link #getDependencies()} in size, order and type.
+ *
+ * @param values the values to set for the dependencies
+ * @return resulting object
+ */
+ T instantiateWith(Object... values);
+}
diff --git a/src/main/java/fr/xephi/authme/MetricsStarter.java b/src/main/java/fr/xephi/authme/initialization/MetricsStarter.java
similarity index 93%
rename from src/main/java/fr/xephi/authme/MetricsStarter.java
rename to src/main/java/fr/xephi/authme/initialization/MetricsStarter.java
index eac9ebaf..4a163f98 100644
--- a/src/main/java/fr/xephi/authme/MetricsStarter.java
+++ b/src/main/java/fr/xephi/authme/initialization/MetricsStarter.java
@@ -1,5 +1,7 @@
-package fr.xephi.authme;
+package fr.xephi.authme.initialization;
+import fr.xephi.authme.AuthMe;
+import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java
index a17eacd5..97383c53 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java
+++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java
@@ -18,6 +18,7 @@ import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
@@ -53,6 +54,7 @@ import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.event.player.PlayerShearEntityEvent;
+import javax.inject.Inject;
import java.util.concurrent.ConcurrentHashMap;
import static fr.xephi.authme.listener.ListenerService.shouldCancelEvent;
@@ -67,24 +69,22 @@ public class AuthMePlayerListener implements Listener {
public static final ConcurrentHashMap joinMessage = new ConcurrentHashMap<>();
public static final ConcurrentHashMap causeByAuthMe = new ConcurrentHashMap<>();
- private final AuthMe plugin;
- private final NewSetting settings;
- private final Messages m;
- private final DataSource dataSource;
- private final AntiBot antiBot;
- private final Management management;
- private final BukkitService bukkitService;
-
- public AuthMePlayerListener(AuthMe plugin, NewSetting settings, Messages messages, DataSource dataSource,
- AntiBot antiBot, Management management, BukkitService bukkitService) {
- this.plugin = plugin;
- this.settings = settings;
- this.m = messages;
- this.dataSource = dataSource;
- this.antiBot = antiBot;
- this.management = management;
- this.bukkitService = bukkitService;
- }
+ @Inject
+ private AuthMe plugin;
+ @Inject
+ private NewSetting settings;
+ @Inject
+ private Messages m;
+ @Inject
+ private DataSource dataSource;
+ @Inject
+ private AntiBot antiBot;
+ @Inject
+ private Management management;
+ @Inject
+ private BukkitService bukkitService;
+ @Inject
+ private SpawnLoader spawnLoader;
private void handleChat(AsyncPlayerChatEvent event) {
if (settings.getProperty(RestrictionSettings.ALLOW_CHAT)) {
@@ -201,7 +201,7 @@ public class AuthMePlayerListener implements Listener {
return;
}
- Location spawn = plugin.getSpawnLocation(player);
+ Location spawn = spawnLoader.getSpawnLocation(player);
if (spawn != null && spawn.getWorld() != null) {
if (!player.getWorld().equals(spawn.getWorld())) {
player.teleport(spawn);
@@ -517,7 +517,7 @@ public class AuthMePlayerListener implements Listener {
Player player = event.getPlayer();
String name = player.getName().toLowerCase();
- Location spawn = plugin.getSpawnLocation(player);
+ Location spawn = spawnLoader.getSpawnLocation(player);
if (Settings.isSaveQuitLocationEnabled && dataSource.isAuthAvailable(name)) {
PlayerAuth auth = PlayerAuth.builder()
.name(name)
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java
index ec8326b5..54df067e 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java
+++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java
@@ -15,21 +15,20 @@ import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.event.server.ServerListPingEvent;
+import javax.inject.Inject;
+
/**
*/
public class AuthMeServerListener implements Listener {
- private final AuthMe plugin;
- private final Messages messages;
- private final PluginHooks pluginHooks;
- private final SpawnLoader spawnLoader;
-
- public AuthMeServerListener(AuthMe plugin, Messages messages, PluginHooks pluginHooks, SpawnLoader spawnLoader) {
- this.plugin = plugin;
- this.messages = messages;
- this.pluginHooks = pluginHooks;
- this.spawnLoader = spawnLoader;
- }
+ @Inject
+ private AuthMe plugin;
+ @Inject
+ private Messages messages;
+ @Inject
+ private PluginHooks pluginHooks;
+ @Inject
+ private SpawnLoader spawnLoader;
@EventHandler(priority = EventPriority.HIGHEST)
public void onServerPing(ServerListPingEvent event) {
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java
index d8266985..ae6c47bc 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java
+++ b/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java
@@ -11,8 +11,11 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerCache;
+import javax.inject.Inject;
+
public class AuthMeTabCompletePacketAdapter extends PacketAdapter {
+ @Inject
public AuthMeTabCompletePacketAdapter(AuthMe plugin) {
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE);
}
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java
index a23ce5c1..d13668d5 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java
+++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java
@@ -19,6 +19,7 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.util.BukkitService;
import org.bukkit.entity.Player;
+import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.logging.Level;
@@ -27,6 +28,7 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter {
private final BukkitService bukkitService;
+ @Inject
public AuthMeTablistPacketAdapter(AuthMe plugin, BukkitService bukkitService) {
super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO);
this.bukkitService = bukkitService;
diff --git a/src/main/java/fr/xephi/authme/ImageGenerator.java b/src/main/java/fr/xephi/authme/mail/ImageGenerator.java
similarity index 88%
rename from src/main/java/fr/xephi/authme/ImageGenerator.java
rename to src/main/java/fr/xephi/authme/mail/ImageGenerator.java
index e529efab..77d98901 100644
--- a/src/main/java/fr/xephi/authme/ImageGenerator.java
+++ b/src/main/java/fr/xephi/authme/mail/ImageGenerator.java
@@ -1,6 +1,9 @@
-package fr.xephi.authme;
+package fr.xephi.authme.mail;
-import java.awt.*;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
/**
diff --git a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java
index c80001c3..d8332602 100644
--- a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java
+++ b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java
@@ -2,7 +2,6 @@ package fr.xephi.authme.mail;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.ImageGenerator;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.EmailSettings;
diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java
index ee27f82c..7dfcd40c 100644
--- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java
+++ b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java
@@ -2,6 +2,7 @@ package fr.xephi.authme.permission;
import de.bananaco.bpermissions.api.ApiLayer;
import de.bananaco.bpermissions.api.CalculableType;
+import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.CommandDescription;
import fr.xephi.authme.util.CollectionUtils;
import net.milkbowl.vault.permission.Permission;
@@ -20,11 +21,12 @@ import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService;
import ru.tehkode.permissions.PermissionUser;
import ru.tehkode.permissions.bukkit.PermissionsEx;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import java.util.logging.Logger;
/**
*
@@ -48,10 +50,7 @@ public class PermissionsManager implements PermissionsService {
* Server instance.
*/
private final Server server;
- /**
- * Logger instance.
- */
- private Logger log;
+ private final PluginManager pluginManager;
/**
* Type of permissions system that is currently used.
* Null if no permissions system is hooked and/or used.
@@ -70,11 +69,11 @@ public class PermissionsManager implements PermissionsService {
* Constructor.
*
* @param server Server instance
- * @param log Logger
*/
- public PermissionsManager(Server server, Logger log) {
+ @Inject
+ public PermissionsManager(Server server, PluginManager pluginManager) {
this.server = server;
- this.log = log;
+ this.pluginManager = pluginManager;
}
/**
@@ -100,39 +99,37 @@ public class PermissionsManager implements PermissionsService {
*
* @return The detected permissions system.
*/
+ @PostConstruct
public PermissionsSystemType setup() {
// Force-unhook from current hooked permissions systems
unhook();
- // Define the plugin manager
- final PluginManager pluginManager = this.server.getPluginManager();
-
// Reset used permissions system type flag
permsType = null;
// Loop through all the available permissions system types
- for(PermissionsSystemType type : PermissionsSystemType.values()) {
+ for (PermissionsSystemType type : PermissionsSystemType.values()) {
// Try to find and hook the current plugin if available, print an error if failed
try {
// Try to find the plugin for the current permissions system
Plugin plugin = pluginManager.getPlugin(type.getPluginName());
// Make sure a plugin with this name was found
- if(plugin == null)
+ if (plugin == null)
continue;
// Make sure the plugin is enabled before hooking
- if(!plugin.isEnabled()) {
- this.log.info("Not hooking into " + type.getName() + " because it's disabled!");
+ if (!plugin.isEnabled()) {
+ ConsoleLogger.info("Not hooking into " + type.getName() + " because it's disabled!");
continue;
}
// Use the proper method to hook this plugin
- switch(type) {
+ switch (type) {
case PERMISSIONS_EX:
// Get the permissions manager for PermissionsEx and make sure it isn't null
- if(PermissionsEx.getPermissionManager() == null) {
- this.log.info("Failed to hook into " + type.getName() + "!");
+ if (PermissionsEx.getPermissionManager() == null) {
+ ConsoleLogger.info("Failed to hook into " + type.getName() + "!");
continue;
}
@@ -146,8 +143,8 @@ public class PermissionsManager implements PermissionsService {
case Z_PERMISSIONS:
// Set the zPermissions service and make sure it's valid
zPermissionsService = Bukkit.getServicesManager().load(ZPermissionsService.class);
- if(zPermissionsService == null) {
- this.log.info("Failed to hook into " + type.getName() + "!");
+ if (zPermissionsService == null) {
+ ConsoleLogger.info("Failed to hook into " + type.getName() + "!");
continue;
}
@@ -157,14 +154,14 @@ public class PermissionsManager implements PermissionsService {
// Get the permissions provider service
RegisteredServiceProvider permissionProvider = this.server.getServicesManager().getRegistration(Permission.class);
if (permissionProvider == null) {
- this.log.info("Failed to hook into " + type.getName() + "!");
+ ConsoleLogger.info("Failed to hook into " + type.getName() + "!");
continue;
}
// Get the Vault provider and make sure it's valid
vaultPerms = permissionProvider.getProvider();
- if(vaultPerms == null) {
- this.log.info("Not using " + type.getName() + " because it's disabled!");
+ if (vaultPerms == null) {
+ ConsoleLogger.info("Not using " + type.getName() + " because it's disabled!");
continue;
}
@@ -177,19 +174,19 @@ public class PermissionsManager implements PermissionsService {
this.permsType = type;
// Show a success message
- this.log.info("Hooked into " + type.getName() + "!");
+ ConsoleLogger.info("Hooked into " + type.getName() + "!");
// Return the used permissions system type
return type;
} catch (Exception ex) {
// An error occurred, show a warning message
- this.log.info("Error while hooking into " + type.getName() + "!");
+ ConsoleLogger.logException("Error while hooking into " + type.getName(), ex);
}
}
// No recognized permissions system found, show a message and return
- this.log.info("No supported permissions system found! Permissions are disabled!");
+ ConsoleLogger.info("No supported permissions system found! Permissions are disabled!");
return null;
}
@@ -201,7 +198,7 @@ public class PermissionsManager implements PermissionsService {
this.permsType = null;
// Print a status message to the console
- this.log.info("Unhooked from Permissions!");
+ ConsoleLogger.info("Unhooked from Permissions!");
}
/**
@@ -232,7 +229,7 @@ public class PermissionsManager implements PermissionsService {
if (pluginName.equals("PermissionsEx") || pluginName.equals("PermissionsBukkit") ||
pluginName.equals("bPermissions") || pluginName.equals("GroupManager") ||
pluginName.equals("zPermissions") || pluginName.equals("Vault")) {
- this.log.info(pluginName + " plugin enabled, dynamically updating permissions hooks!");
+ ConsoleLogger.info(pluginName + " plugin enabled, dynamically updating permissions hooks!");
setup();
}
}
@@ -251,7 +248,7 @@ public class PermissionsManager implements PermissionsService {
if (pluginName.equals("PermissionsEx") || pluginName.equals("PermissionsBukkit") ||
pluginName.equals("bPermissions") || pluginName.equals("GroupManager") ||
pluginName.equals("zPermissions") || pluginName.equals("Vault")) {
- this.log.info(pluginName + " plugin disabled, updating hooks!");
+ ConsoleLogger.info(pluginName + " plugin disabled, updating hooks!");
setup();
}
}
diff --git a/src/main/java/fr/xephi/authme/process/Management.java b/src/main/java/fr/xephi/authme/process/Management.java
index 4b279c9a..04a0f414 100644
--- a/src/main/java/fr/xephi/authme/process/Management.java
+++ b/src/main/java/fr/xephi/authme/process/Management.java
@@ -3,6 +3,7 @@ package fr.xephi.authme.process;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
+import fr.xephi.authme.hooks.PluginHooks;
import fr.xephi.authme.process.email.AsyncAddEmail;
import fr.xephi.authme.process.email.AsyncChangeEmail;
import fr.xephi.authme.process.join.AsynchronousJoin;
@@ -14,23 +15,26 @@ import fr.xephi.authme.process.unregister.AsynchronousUnregister;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitScheduler;
+import javax.inject.Inject;
+
/**
*/
public class Management {
- private final AuthMe plugin;
- private final BukkitScheduler sched;
- private final ProcessService processService;
- private final DataSource dataSource;
- private final PlayerCache playerCache;
+ @Inject
+ private AuthMe plugin;
+ @Inject
+ private BukkitScheduler sched;
+ @Inject
+ private ProcessService processService;
+ @Inject
+ private DataSource dataSource;
+ @Inject
+ private PlayerCache playerCache;
+ @Inject
+ private PluginHooks pluginHooks;
- public Management(AuthMe plugin, ProcessService processService, DataSource dataSource, PlayerCache playerCache) {
- this.plugin = plugin;
- this.sched = this.plugin.getServer().getScheduler();
- this.processService = processService;
- this.dataSource = dataSource;
- this.playerCache = playerCache;
- }
+ Management() { }
public void performLogin(final Player player, final String password, final boolean forceLogin) {
runTask(new AsynchronousLogin(player, password, forceLogin, plugin, dataSource, processService));
@@ -49,7 +53,7 @@ public class Management {
}
public void performJoin(final Player player) {
- runTask(new AsynchronousJoin(player, plugin, dataSource, playerCache, processService));
+ runTask(new AsynchronousJoin(player, plugin, dataSource, playerCache, pluginHooks, processService));
}
public void performQuit(final Player player, final boolean isKick) {
diff --git a/src/main/java/fr/xephi/authme/process/ProcessService.java b/src/main/java/fr/xephi/authme/process/ProcessService.java
index 653be156..a338cad4 100644
--- a/src/main/java/fr/xephi/authme/process/ProcessService.java
+++ b/src/main/java/fr/xephi/authme/process/ProcessService.java
@@ -17,6 +17,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.scheduler.BukkitTask;
+import javax.inject.Inject;
import java.util.Collection;
/**
@@ -24,29 +25,24 @@ import java.util.Collection;
*/
public class ProcessService {
- private final NewSetting settings;
- private final Messages messages;
- private final AuthMe authMe;
- private final DataSource dataSource;
- private final PasswordSecurity passwordSecurity;
- private final PluginHooks pluginHooks;
- private final SpawnLoader spawnLoader;
- private final ValidationService validationService;
- private final BukkitService bukkitService;
-
- public ProcessService(NewSetting settings, Messages messages, AuthMe authMe, DataSource dataSource,
- PasswordSecurity passwordSecurity, PluginHooks pluginHooks, SpawnLoader spawnLoader,
- ValidationService validationService, BukkitService bukkitService) {
- this.settings = settings;
- this.messages = messages;
- this.authMe = authMe;
- this.dataSource = dataSource;
- this.passwordSecurity = passwordSecurity;
- this.pluginHooks = pluginHooks;
- this.spawnLoader = spawnLoader;
- this.validationService = validationService;
- this.bukkitService = bukkitService;
- }
+ @Inject
+ private NewSetting settings;
+ @Inject
+ private Messages messages;
+ @Inject
+ private AuthMe authMe;
+ @Inject
+ private DataSource dataSource;
+ @Inject
+ private PasswordSecurity passwordSecurity;
+ @Inject
+ private PluginHooks pluginHooks;
+ @Inject
+ private SpawnLoader spawnLoader;
+ @Inject
+ private ValidationService validationService;
+ @Inject
+ private BukkitService bukkitService;
/**
* Retrieve a property's value.
diff --git a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
index 37b0dfbd..c9ab7159 100644
--- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
+++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
@@ -9,6 +9,7 @@ import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.FirstSpawnTeleportEvent;
import fr.xephi.authme.events.ProtectInventoryEvent;
import fr.xephi.authme.events.SpawnTeleportEvent;
+import fr.xephi.authme.hooks.PluginHooks;
import fr.xephi.authme.listener.AuthMePlayerListener;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.permission.PlayerStatePermission;
@@ -45,18 +46,20 @@ public class AsynchronousJoin implements Process {
private final String name;
private final ProcessService service;
private final PlayerCache playerCache;
+ private final PluginHooks pluginHooks;
private final boolean disableCollisions = MethodUtils
.getAccessibleMethod(LivingEntity.class, "setCollidable", new Class[]{}) != null;
public AsynchronousJoin(Player player, AuthMe plugin, DataSource database, PlayerCache playerCache,
- ProcessService service) {
+ PluginHooks pluginHooks, ProcessService service) {
this.player = player;
this.plugin = plugin;
this.database = database;
this.name = player.getName().toLowerCase();
this.service = service;
this.playerCache = playerCache;
+ this.pluginHooks = pluginHooks;
}
@Override
@@ -190,7 +193,7 @@ public class AsynchronousJoin implements Process {
player.setWalkSpeed(0.0f);
}
player.setNoDamageTicks(registrationTimeout);
- if (plugin.getPluginHooks().isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) {
+ if (pluginHooks.isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) {
player.performCommand("motd");
}
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
diff --git a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java
index 94a8abeb..458c9969 100644
--- a/src/main/java/fr/xephi/authme/security/PasswordSecurity.java
+++ b/src/main/java/fr/xephi/authme/security/PasswordSecurity.java
@@ -8,6 +8,7 @@ import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.plugin.PluginManager;
+import javax.inject.Inject;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -22,6 +23,7 @@ public class PasswordSecurity {
private final DataSource dataSource;
private final PluginManager pluginManager;
+ @Inject
public PasswordSecurity(DataSource dataSource, NewSetting settings, PluginManager pluginManager) {
this.settings = settings;
this.algorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH);
diff --git a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java
index 59693a98..a046d813 100644
--- a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java
+++ b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java
@@ -4,6 +4,7 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.hooks.PluginHooks;
+import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.FileUtils;
import fr.xephi.authme.util.StringUtils;
@@ -14,6 +15,7 @@ import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
+import javax.inject.Inject;
import java.io.File;
import java.io.IOException;
@@ -40,7 +42,8 @@ public class SpawnLoader {
* @param settings The setting instance
* @param pluginHooks The plugin hooks instance
*/
- public SpawnLoader(File pluginFolder, NewSetting settings, PluginHooks pluginHooks) {
+ @Inject
+ public SpawnLoader(@DataFolder File pluginFolder, NewSetting settings, PluginHooks pluginHooks) {
File spawnFile = new File(pluginFolder, "spawn.yml");
// TODO ljacqu 20160312: Check if resource could be copied and handle the case if not
FileUtils.copyFileFromResource(spawnFile, "spawn.yml");
diff --git a/src/main/java/fr/xephi/authme/util/BukkitService.java b/src/main/java/fr/xephi/authme/util/BukkitService.java
index ea405d80..592caa22 100644
--- a/src/main/java/fr/xephi/authme/util/BukkitService.java
+++ b/src/main/java/fr/xephi/authme/util/BukkitService.java
@@ -7,6 +7,7 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
+import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
@@ -28,6 +29,7 @@ public class BukkitService {
private final boolean getOnlinePlayersIsCollection;
private Method getOnlinePlayers;
+ @Inject
public BukkitService(AuthMe authMe) {
this.authMe = authMe;
getOnlinePlayersIsCollection = initializeOnlinePlayersIsCollectionField();
diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java
index 5850645b..5d8c08ee 100644
--- a/src/main/java/fr/xephi/authme/util/Utils.java
+++ b/src/main/java/fr/xephi/authme/util/Utils.java
@@ -165,8 +165,9 @@ public final class Utils {
});
}
+ @Deprecated
public static boolean isNPC(Player player) {
- return player.hasMetadata("NPC") || plugin.getPluginHooks().isNpcInCombatTagPlus(player);
+ return plugin.getPluginHooks().isNpc(player);
}
public static void teleportToSpawn(Player player) {
diff --git a/src/main/java/fr/xephi/authme/util/ValidationService.java b/src/main/java/fr/xephi/authme/util/ValidationService.java
index 7f8b78b7..815f493f 100644
--- a/src/main/java/fr/xephi/authme/util/ValidationService.java
+++ b/src/main/java/fr/xephi/authme/util/ValidationService.java
@@ -10,6 +10,7 @@ import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.command.CommandSender;
+import javax.inject.Inject;
import java.util.Collection;
import java.util.List;
@@ -22,6 +23,7 @@ public class ValidationService {
private final DataSource dataSource;
private final PermissionsManager permissionsManager;
+ @Inject
public ValidationService(NewSetting settings, DataSource dataSource, PermissionsManager permissionsManager) {
this.settings = settings;
this.dataSource = dataSource;
diff --git a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java
index 89a35571..a1ff5e22 100644
--- a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java
+++ b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java
@@ -18,10 +18,10 @@ import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.ValidationService;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@@ -41,6 +41,7 @@ import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class CommandServiceTest {
+ @InjectMocks
private CommandService commandService;
@Mock
private AuthMe authMe;
@@ -67,12 +68,6 @@ public class CommandServiceTest {
@Mock
private BukkitService bukkitService;
- @Before
- public void setUpService() {
- commandService = new CommandService(authMe, commandMapper, helpProvider, messages, passwordSecurity,
- permissionsManager, settings, pluginHooks, spawnLoader, antiBot, validationService, bukkitService);
- }
-
@Test
public void shouldSendMessage() {
// given
diff --git a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java
index 3ec47a4f..e7d85f14 100644
--- a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java
+++ b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java
@@ -6,6 +6,8 @@ import fr.xephi.authme.command.FoundResultStatus;
import fr.xephi.authme.command.TestCommandsUtil;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerPermission;
+import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.properties.PluginSettings;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.junit.Before;
@@ -52,7 +54,9 @@ public class HelpProviderTest {
@Before
public void setUpHelpProvider() {
permissionsManager = mock(PermissionsManager.class);
- helpProvider = new HelpProvider(permissionsManager, HELP_HEADER);
+ NewSetting settings = mock(NewSetting.class);
+ given(settings.getProperty(PluginSettings.HELP_HEADER)).willReturn(HELP_HEADER);
+ helpProvider = new HelpProvider(permissionsManager, settings);
sender = mock(CommandSender.class);
}
diff --git a/src/test/java/fr/xephi/authme/initialization/AuthMeServiceInitializerTest.java b/src/test/java/fr/xephi/authme/initialization/AuthMeServiceInitializerTest.java
new file mode 100644
index 00000000..61322291
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/AuthMeServiceInitializerTest.java
@@ -0,0 +1,194 @@
+package fr.xephi.authme.initialization;
+
+import fr.xephi.authme.initialization.samples.BadFieldInjection;
+import fr.xephi.authme.initialization.samples.BetaManager;
+import fr.xephi.authme.initialization.samples.CircularClasses;
+import fr.xephi.authme.initialization.samples.ClassWithAbstractDependency;
+import fr.xephi.authme.initialization.samples.ClassWithAnnotations;
+import fr.xephi.authme.initialization.samples.Duration;
+import fr.xephi.authme.initialization.samples.FieldInjectionWithAnnotations;
+import fr.xephi.authme.initialization.samples.InvalidClass;
+import fr.xephi.authme.initialization.samples.InvalidPostConstruct;
+import fr.xephi.authme.initialization.samples.PostConstructTestClass;
+import fr.xephi.authme.initialization.samples.ProvidedClass;
+import fr.xephi.authme.initialization.samples.Size;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Test for {@link AuthMeServiceInitializer}.
+ */
+public class AuthMeServiceInitializerTest {
+
+ private static final String ALLOWED_PACKAGE = "fr.xephi.authme.initialization";
+
+ private AuthMeServiceInitializer initializer;
+
+ @Before
+ public void setInitializer() {
+ initializer = new AuthMeServiceInitializer(ALLOWED_PACKAGE);
+ initializer.register(new ProvidedClass(""));
+ }
+
+ @Test
+ public void shouldInitializeElements() {
+ // given / when
+ BetaManager betaManager = initializer.get(BetaManager.class);
+
+ // then
+ assertThat(betaManager, not(nullValue()));
+ for (Object o : betaManager.getDependencies()) {
+ assertThat(o, not(nullValue()));
+ }
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void shouldThrowForInvalidPackage() {
+ // given / when / then
+ initializer.get(InvalidClass.class);
+ }
+
+ @Test
+ public void shouldPassValueByAnnotation() {
+ // given
+ int size = 12;
+ long duration = -15482L;
+ initializer.provide(Size.class, size);
+ initializer.provide(Duration.class, duration);
+
+ // when
+ ClassWithAnnotations object = initializer.get(ClassWithAnnotations.class);
+
+ // then
+ assertThat(object, not(nullValue()));
+ assertThat(object.getSize(), equalTo(size));
+ assertThat(object.getDuration(), equalTo(duration));
+ // some sample check to make sure we only have one instance of GammaService
+ assertThat(object.getGammaService(), equalTo(initializer.get(BetaManager.class).getDependencies()[1]));
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void shouldRecognizeCircularReferences() {
+ // given / when / then
+ initializer.get(CircularClasses.Circular3.class);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void shouldThrowForUnregisteredAnnotation() {
+ // given
+ initializer.provide(Size.class, 4523);
+
+ // when / then
+ initializer.get(ClassWithAnnotations.class);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void shouldThrowForFieldInjectionWithNoDefaultConstructor() {
+ // given / when / then
+ initializer.get(BadFieldInjection.class);
+ }
+
+ @Test
+ public void shouldInjectFieldsWithAnnotationsProperly() {
+ // given
+ initializer.provide(Size.class, 2809375);
+ initializer.provide(Duration.class, 13095L);
+
+ // when
+ FieldInjectionWithAnnotations result = initializer.get(FieldInjectionWithAnnotations.class);
+
+ // then
+ assertThat(result.getSize(), equalTo(2809375));
+ assertThat(result.getDuration(), equalTo(13095L));
+ assertThat(result.getBetaManager(), not(nullValue()));
+ assertThat(result.getClassWithAnnotations(), not(nullValue()));
+ assertThat(result.getClassWithAnnotations().getGammaService(),
+ equalTo(result.getBetaManager().getDependencies()[1]));
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void shouldThrowForAnnotationAsKey() {
+ // given / when / then
+ initializer.get(Size.class);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void shouldThrowForSecondRegistration() {
+ // given / when / then
+ initializer.register(new ProvidedClass(""));
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void shouldThrowForSecondAnnotationRegistration() {
+ // given
+ initializer.provide(Size.class, 12);
+
+ // when / then
+ initializer.provide(Size.class, -8);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void shouldThrowForNullValueAssociatedToAnnotation() {
+ // given / when / then
+ initializer.provide(Duration.class, null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void shouldThrowForRegisterWithNull() {
+ // given / when / then
+ initializer.register(String.class, null);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void shouldThrowForRegisterOfType() {
+ // given / when / then
+ // this most likely means that the second argument was forgotten, so throw an error and force
+ // the API user to use the explicit register(Class.class, String.class) if really, really desired
+ // (Though for such generic types, an annotation would be a lot better)
+ initializer.register(String.class);
+ }
+
+ @Test
+ public void shouldExecutePostConstructMethod() {
+ // given
+ initializer.provide(Size.class, 15123);
+
+ // when
+ PostConstructTestClass testClass = initializer.get(PostConstructTestClass.class);
+
+ // then
+ assertThat(testClass.werePostConstructsCalled(), equalTo(true));
+ assertThat(testClass.getBetaManager(), not(nullValue()));
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void shouldThrowForInvalidPostConstructMethod() {
+ // given / when / then
+ initializer.get(InvalidPostConstruct.class);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void shouldThrowForAbstractNonRegisteredDependency() {
+ // given / when / then
+ initializer.get(ClassWithAbstractDependency.class);
+ }
+
+ @Test
+ public void shouldInstantiateWithImplementationOfAbstractDependency() {
+ // given
+ ClassWithAbstractDependency.ConcreteDependency concrete = new ClassWithAbstractDependency.ConcreteDependency();
+ initializer.register(ClassWithAbstractDependency.AbstractDependency.class, concrete);
+
+ // when
+ ClassWithAbstractDependency cwad = initializer.get(ClassWithAbstractDependency.class);
+
+ // then
+ assertThat(cwad.getAbstractDependency() == concrete, equalTo(true));
+ assertThat(cwad.getAlphaService(), not(nullValue()));
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/AlphaService.java b/src/test/java/fr/xephi/authme/initialization/samples/AlphaService.java
new file mode 100644
index 00000000..2a93a43c
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/AlphaService.java
@@ -0,0 +1,20 @@
+package fr.xephi.authme.initialization.samples;
+
+import javax.inject.Inject;
+
+/**
+ * Sample - class with dependency to ProvidedClass.
+ */
+public class AlphaService {
+
+ private ProvidedClass providedClass;
+
+ @Inject
+ AlphaService(ProvidedClass providedClass) {
+ this.providedClass = providedClass;
+ }
+
+ public ProvidedClass getProvidedClass() {
+ return providedClass;
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/BadFieldInjection.java b/src/test/java/fr/xephi/authme/initialization/samples/BadFieldInjection.java
new file mode 100644
index 00000000..9dc41548
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/BadFieldInjection.java
@@ -0,0 +1,16 @@
+package fr.xephi.authme.initialization.samples;
+
+import javax.inject.Inject;
+
+/**
+ * Sample class with invalid field injection (requires default constructor).
+ */
+public class BadFieldInjection {
+
+ @Inject
+ private AlphaService alphaService;
+
+ public BadFieldInjection(BetaManager betaManager) {
+ throw new IllegalStateException("Should never be called");
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/BetaManager.java b/src/test/java/fr/xephi/authme/initialization/samples/BetaManager.java
new file mode 100644
index 00000000..8c2fe923
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/BetaManager.java
@@ -0,0 +1,20 @@
+package fr.xephi.authme.initialization.samples;
+
+import javax.inject.Inject;
+
+/**
+ * Sample - depends on Provided, alpha and gamma.
+ */
+public class BetaManager {
+
+ @Inject
+ private ProvidedClass providedClass;
+ @Inject
+ private GammaService gammaService;
+ @Inject
+ private AlphaService alphaService;
+
+ public Object[] getDependencies() {
+ return new Object[]{providedClass, gammaService, alphaService};
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/CircularClasses.java b/src/test/java/fr/xephi/authme/initialization/samples/CircularClasses.java
new file mode 100644
index 00000000..e9a1460e
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/CircularClasses.java
@@ -0,0 +1,30 @@
+package fr.xephi.authme.initialization.samples;
+
+import javax.inject.Inject;
+
+/**
+ * Classes with circular dependencies.
+ */
+public class CircularClasses {
+
+ public static final class Circular1 {
+ @Inject
+ public Circular1(AlphaService alphaService, Circular3 circular3) {
+ // --
+ }
+ }
+
+ public static final class Circular2 {
+ @Inject
+ public Circular2(Circular1 circular1) {
+ // --
+ }
+ }
+
+ public static final class Circular3 {
+ @Inject
+ public Circular3(Circular2 circular2, BetaManager betaManager) {
+ // --
+ }
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAbstractDependency.java b/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAbstractDependency.java
new file mode 100644
index 00000000..25b651b3
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAbstractDependency.java
@@ -0,0 +1,32 @@
+package fr.xephi.authme.initialization.samples;
+
+import javax.inject.Inject;
+
+/**
+ * Test with an abstract class declared as dependency.
+ */
+public class ClassWithAbstractDependency {
+
+ private final AlphaService alphaService;
+ private final AbstractDependency abstractDependency;
+
+ @Inject
+ public ClassWithAbstractDependency(AlphaService as, AbstractDependency ad) {
+ this.alphaService = as;
+ this.abstractDependency = ad;
+ }
+
+ public AlphaService getAlphaService() {
+ return alphaService;
+ }
+
+ public AbstractDependency getAbstractDependency() {
+ return abstractDependency;
+ }
+
+ public static abstract class AbstractDependency {
+ }
+
+ public static final class ConcreteDependency extends AbstractDependency {
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAnnotations.java b/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAnnotations.java
new file mode 100644
index 00000000..61dca71b
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/ClassWithAnnotations.java
@@ -0,0 +1,29 @@
+package fr.xephi.authme.initialization.samples;
+
+import javax.inject.Inject;
+
+public class ClassWithAnnotations {
+
+ private int size;
+ private GammaService gammaService;
+ private long duration;
+
+ @Inject
+ ClassWithAnnotations(@Size int size, GammaService gammaService, @Duration long duration) {
+ this.size = size;
+ this.gammaService = gammaService;
+ this.duration = duration;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public GammaService getGammaService() {
+ return gammaService;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/Duration.java b/src/test/java/fr/xephi/authme/initialization/samples/Duration.java
new file mode 100644
index 00000000..e61c6d28
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/Duration.java
@@ -0,0 +1,14 @@
+package fr.xephi.authme.initialization.samples;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Sample annotation.
+ */
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Duration {
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/FieldInjectionWithAnnotations.java b/src/test/java/fr/xephi/authme/initialization/samples/FieldInjectionWithAnnotations.java
new file mode 100644
index 00000000..65bdf537
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/FieldInjectionWithAnnotations.java
@@ -0,0 +1,40 @@
+package fr.xephi.authme.initialization.samples;
+
+import javax.inject.Inject;
+
+/**
+ * Sample - field injection, including custom annotations.
+ */
+public class FieldInjectionWithAnnotations {
+
+ @Inject
+ private BetaManager betaManager;
+ @Inject
+ @Size
+ private int size;
+ @Duration
+ @Inject
+ private long duration;
+ @Inject
+ protected ClassWithAnnotations classWithAnnotations;
+
+ FieldInjectionWithAnnotations() {
+ }
+
+ public BetaManager getBetaManager() {
+ return betaManager;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public ClassWithAnnotations getClassWithAnnotations() {
+ return classWithAnnotations;
+ }
+
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/GammaService.java b/src/test/java/fr/xephi/authme/initialization/samples/GammaService.java
new file mode 100644
index 00000000..8ee97032
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/GammaService.java
@@ -0,0 +1,20 @@
+package fr.xephi.authme.initialization.samples;
+
+import javax.inject.Inject;
+
+/**
+ * Sample - class dependent on alpha and provided.
+ */
+public class GammaService {
+
+ private AlphaService alphaService;
+
+ @Inject
+ GammaService(AlphaService alphaService) {
+ this.alphaService = alphaService;
+ }
+
+ public AlphaService getAlphaService() {
+ return alphaService;
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/InvalidClass.java b/src/test/java/fr/xephi/authme/initialization/samples/InvalidClass.java
new file mode 100644
index 00000000..b896af9d
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/InvalidClass.java
@@ -0,0 +1,14 @@
+package fr.xephi.authme.initialization.samples;
+
+import javax.inject.Inject;
+
+/**
+ * Sample - invalid class, since Integer parameter type is outside of the allowed package and not annotated.
+ */
+public class InvalidClass {
+
+ @Inject
+ public InvalidClass(AlphaService alphaService, Integer i) {
+ throw new IllegalStateException("Should never be called");
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/InvalidPostConstruct.java b/src/test/java/fr/xephi/authme/initialization/samples/InvalidPostConstruct.java
new file mode 100644
index 00000000..85c7f4c4
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/InvalidPostConstruct.java
@@ -0,0 +1,19 @@
+package fr.xephi.authme.initialization.samples;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+/**
+ * Class with invalid @PostConstruct method.
+ */
+public class InvalidPostConstruct {
+
+ @Inject
+ private AlphaService alphaService;
+ @Inject
+ private ProvidedClass providedClass;
+
+ @PostConstruct
+ public void invalidPostConstr(BetaManager betaManager) {
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/PostConstructTestClass.java b/src/test/java/fr/xephi/authme/initialization/samples/PostConstructTestClass.java
new file mode 100644
index 00000000..a4e57032
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/PostConstructTestClass.java
@@ -0,0 +1,37 @@
+package fr.xephi.authme.initialization.samples;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+/**
+ * Sample class for testing the execution of the @PostConstruct method.
+ */
+public class PostConstructTestClass {
+
+ @Inject
+ @Size
+ private int size;
+ @Inject
+ private BetaManager betaManager;
+ private boolean wasPostConstructCalled = false;
+ private boolean wasSecondPostConstructCalled = false;
+
+ @PostConstruct
+ protected void setFieldToTrue() {
+ wasPostConstructCalled = true;
+ }
+
+ @PostConstruct
+ public int otherPostConstructMethod() {
+ wasSecondPostConstructCalled = true;
+ return 42;
+ }
+
+ public boolean werePostConstructsCalled() {
+ return wasPostConstructCalled && wasSecondPostConstructCalled;
+ }
+
+ public BetaManager getBetaManager() {
+ return betaManager;
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/ProvidedClass.java b/src/test/java/fr/xephi/authme/initialization/samples/ProvidedClass.java
new file mode 100644
index 00000000..7ce81bd3
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/ProvidedClass.java
@@ -0,0 +1,18 @@
+package fr.xephi.authme.initialization.samples;
+
+import javax.inject.Inject;
+
+/**
+ * Sample - class that is always provided to the initializer beforehand.
+ */
+public class ProvidedClass {
+
+ @Inject
+ public ProvidedClass() {
+ throw new IllegalStateException("Should never be called (tests always provide this class)");
+ }
+
+ public ProvidedClass(String manualConstructor) {
+ }
+
+}
diff --git a/src/test/java/fr/xephi/authme/initialization/samples/Size.java b/src/test/java/fr/xephi/authme/initialization/samples/Size.java
new file mode 100644
index 00000000..320a7b7c
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/initialization/samples/Size.java
@@ -0,0 +1,14 @@
+package fr.xephi.authme.initialization.samples;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Sample annotation.
+ */
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Size {
+}
diff --git a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java
index ab935d02..f641b1f0 100644
--- a/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java
+++ b/src/test/java/fr/xephi/authme/process/ProcessServiceTest.java
@@ -13,9 +13,9 @@ import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.BukkitService;
import fr.xephi.authme.util.ValidationService;
import org.bukkit.command.CommandSender;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
@@ -31,6 +31,7 @@ import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class ProcessServiceTest {
+ @InjectMocks
private ProcessService processService;
@Mock
private ValidationService validationService;
@@ -51,12 +52,6 @@ public class ProcessServiceTest {
@Mock
private BukkitService bukkitService;
- @Before
- public void setUpService() {
- processService = new ProcessService(settings, messages, authMe, dataSource, passwordSecurity,
- pluginHooks, spawnLoader, validationService, bukkitService);
- }
-
@Test
public void shouldGetProperty() {
// given