mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-11-23 10:45:23 +01:00
#835 Remove all injector classes from AuthMe, update installer tasks
This commit is contained in:
parent
4144281a77
commit
d791fcba94
@ -1,86 +0,0 @@
|
||||
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.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* Functionality for constructor injection.
|
||||
*/
|
||||
class ConstructorInjection<T> implements Injection<T> {
|
||||
|
||||
private final Constructor<T> constructor;
|
||||
|
||||
private ConstructorInjection(Constructor<T> 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) {
|
||||
validateNoNullValues(values);
|
||||
try {
|
||||
return constructor.newInstance(values);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new UnsupportedOperationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Provider<ConstructorInjection<T>> provide(final Class<T> clazz) {
|
||||
return new Provider<ConstructorInjection<T>>() {
|
||||
@Override
|
||||
public ConstructorInjection<T> get() {
|
||||
Constructor<T> 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 <T> the class' type
|
||||
* @return injection constructor for the class, null if not applicable
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> Constructor<T> getInjectionConstructor(Class<T> clazz) {
|
||||
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
if (constructor.isAnnotationPresent(Inject.class)) {
|
||||
constructor.setAccessible(true);
|
||||
return (Constructor<T>) constructor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void validateNoNullValues(Object[] array) {
|
||||
for (Object entry : array) {
|
||||
Preconditions.checkNotNull(entry);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
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.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Functionality for field injection.
|
||||
*/
|
||||
class FieldInjection<T> implements Injection<T> {
|
||||
|
||||
private final Field[] fields;
|
||||
private final Constructor<T> defaultConstructor;
|
||||
|
||||
private FieldInjection(Constructor<T> defaultConstructor, Collection<Field> 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 {
|
||||
Preconditions.checkNotNull(values[i]);
|
||||
fields[i].set(instance, values[i]);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new UnsupportedOperationException(e);
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a provider for a {@code FieldInjection<T>} instance, i.e. a provides an object
|
||||
* with which field injection can be performed on the given class if applicable. The provided
|
||||
* value is {@code null} if field injection cannot be applied to the class.
|
||||
*
|
||||
* @param clazz the class to provide field injection for
|
||||
* @param <T> the class' type
|
||||
* @return field injection provider for the given class, or null if not applicable
|
||||
*/
|
||||
public static <T> Provider<FieldInjection<T>> provide(final Class<T> clazz) {
|
||||
return new Provider<FieldInjection<T>>() {
|
||||
@Override
|
||||
public FieldInjection<T> get() {
|
||||
Constructor<T> constructor = getDefaultConstructor(clazz);
|
||||
if (constructor == null) {
|
||||
return null;
|
||||
}
|
||||
List<Field> fields = getInjectionFields(clazz);
|
||||
return fields.isEmpty() ? null : new FieldInjection<>(constructor, fields);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static List<Field> getInjectionFields(Class<?> clazz) {
|
||||
List<Field> fields = new ArrayList<>();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.isAnnotationPresent(Inject.class)) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException(String.format("Field '%s' in class '%s' is static but "
|
||||
+ "annotated with @Inject", field.getName(), clazz.getSimpleName()));
|
||||
}
|
||||
field.setAccessible(true);
|
||||
fields.add(field);
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
private static Class<?> getFirstNonInjectAnnotation(Field field) {
|
||||
for (Annotation annotation : field.getAnnotations()) {
|
||||
if (annotation.annotationType() != Inject.class) {
|
||||
return annotation.annotationType();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> Constructor<T> getDefaultConstructor(Class<T> clazz) {
|
||||
try {
|
||||
Constructor<?> defaultConstructor = clazz.getDeclaredConstructor();
|
||||
defaultConstructor.setAccessible(true);
|
||||
return (Constructor<T>) defaultConstructor;
|
||||
} catch (NoSuchMethodException ignore) {
|
||||
// no default constructor available
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package fr.xephi.authme.initialization;
|
||||
|
||||
/**
|
||||
* Common interface for all injection methods.
|
||||
*
|
||||
* @param <T> the type of the concerned object
|
||||
*/
|
||||
public interface Injection<T> {
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
package fr.xephi.authme.initialization;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.inject.Provider;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/**
|
||||
* Helper class for functions relating to injecting.
|
||||
*/
|
||||
public class InjectionHelper {
|
||||
|
||||
private InjectionHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Injection} for the given class, or null if none applicable.
|
||||
*
|
||||
* @param clazz the class to process
|
||||
* @param <T> the class' type
|
||||
* @return injection of the class or null if none detected
|
||||
*/
|
||||
public static <T> Injection<T> getInjection(Class<T> clazz) {
|
||||
return firstNotNull(
|
||||
ConstructorInjection.provide(clazz),
|
||||
FieldInjection.provide(clazz),
|
||||
InstantiationFallback.provide(clazz));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and locates the given class' post construct method. Returns {@code null} if none present.
|
||||
*
|
||||
* @param clazz the class to search
|
||||
* @return post construct method, or null
|
||||
*/
|
||||
public static Method getAndValidatePostConstructMethod(Class<?> clazz) {
|
||||
Method postConstructMethod = null;
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
if (method.isAnnotationPresent(PostConstruct.class)) {
|
||||
if (postConstructMethod != null) {
|
||||
throw new IllegalStateException("Multiple methods with @PostConstruct on " + clazz);
|
||||
} else if (method.getParameterTypes().length > 0 || Modifier.isStatic(method.getModifiers())) {
|
||||
throw new IllegalStateException("@PostConstruct method may not be static or have any parameters. "
|
||||
+ "Invalid method in " + clazz);
|
||||
} else if (method.getReturnType() != void.class) {
|
||||
throw new IllegalStateException("@PostConstruct method must have return type void. "
|
||||
+ "Offending class: " + clazz);
|
||||
} else {
|
||||
postConstructMethod = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
return postConstructMethod;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static <T> Injection<T> firstNotNull(Provider<? extends Injection<T>>... providers) {
|
||||
for (Provider<? extends Injection<T>> provider : providers) {
|
||||
Injection<T> object = provider.get();
|
||||
if (object != null) {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
package fr.xephi.authme.initialization;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* Fallback instantiation method for classes with an accessible no-args constructor
|
||||
* and no elements whatsoever annotated with {@link Inject} or {@link PostConstruct}.
|
||||
*/
|
||||
class InstantiationFallback<T> implements Injection<T> {
|
||||
|
||||
private final Constructor<T> constructor;
|
||||
|
||||
private InstantiationFallback(Constructor<T> constructor) {
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getDependencies() {
|
||||
return new Class<?>[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getDependencyAnnotations() {
|
||||
return new Class<?>[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public T instantiateWith(Object... values) {
|
||||
if (values == null || values.length > 0) {
|
||||
throw new UnsupportedOperationException("Instantiation fallback cannot have parameters");
|
||||
}
|
||||
try {
|
||||
return constructor.newInstance();
|
||||
} catch (InvocationTargetException | IllegalAccessException | InstantiationException e) {
|
||||
throw new UnsupportedOperationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instantiation fallback if the class is applicable.
|
||||
*
|
||||
* @param clazz the class
|
||||
* @param <T> the class' type
|
||||
* @return instantiation fallback provider for the given class, or null if not applicable
|
||||
*/
|
||||
public static <T> Provider<InstantiationFallback<T>> provide(final Class<T> clazz) {
|
||||
return new Provider<InstantiationFallback<T>>() {
|
||||
@Override
|
||||
public InstantiationFallback<T> get() {
|
||||
Constructor<T> noArgsConstructor = getNoArgsConstructor(clazz);
|
||||
// Return fallback only if we have no args constructor and no @Inject annotation anywhere
|
||||
if (noArgsConstructor != null
|
||||
&& !isInjectionAnnotationPresent(clazz.getDeclaredConstructors())
|
||||
&& !isInjectionAnnotationPresent(clazz.getDeclaredFields())
|
||||
&& !isInjectionAnnotationPresent(clazz.getDeclaredMethods())) {
|
||||
return new InstantiationFallback<>(noArgsConstructor);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static <T> Constructor<T> getNoArgsConstructor(Class<T> clazz) {
|
||||
try {
|
||||
// Note ljacqu 20160504: getConstructor(), unlike getDeclaredConstructor(), only considers public members
|
||||
return clazz.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static <A extends AccessibleObject> boolean isInjectionAnnotationPresent(A[] accessibles) {
|
||||
for (A accessible : accessibles) {
|
||||
if (accessible.isAnnotationPresent(Inject.class) || accessible.isAnnotationPresent(PostConstruct.class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -3,18 +3,16 @@ package tools.checktestmocks;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Sets;
|
||||
import fr.xephi.authme.initialization.Injection;
|
||||
import fr.xephi.authme.initialization.InjectionHelper;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import org.mockito.Mock;
|
||||
import tools.utils.AutoToolTask;
|
||||
import tools.utils.InjectorUtils;
|
||||
import tools.utils.ToolsConstants;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
@ -76,8 +74,10 @@ public class CheckTestMocks implements AutoToolTask {
|
||||
Class<?> realClass = returnRealClass(testClass);
|
||||
if (realClass != null) {
|
||||
Set<Class<?>> mockFields = getMocks(testClass);
|
||||
Set<Class<?>> injectFields = getRealClassDependencies(realClass);
|
||||
if (!injectFields.containsAll(mockFields)) {
|
||||
Set<Class<?>> injectFields = InjectorUtils.getDependencies(realClass);
|
||||
if (injectFields == null) {
|
||||
addErrorEntry(testClass, "Could not find instantiation method");
|
||||
} else if (!injectFields.containsAll(mockFields)) {
|
||||
addErrorEntry(testClass, "Error - Found the following mocks absent as @Inject: "
|
||||
+ formatClassList(Sets.difference(mockFields, injectFields)));
|
||||
} else if (!mockFields.containsAll(injectFields)) {
|
||||
@ -137,13 +137,6 @@ public class CheckTestMocks implements AutoToolTask {
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<Class<?>> getRealClassDependencies(Class<?> realClass) {
|
||||
Injection<?> injection = InjectionHelper.getInjection(realClass);
|
||||
return injection == null
|
||||
? Collections.<Class<?>>emptySet()
|
||||
: Sets.<Class<?>>newHashSet(injection.getDependencies());
|
||||
}
|
||||
|
||||
private static boolean isTestClassWithMocks(Class<?> clazz) {
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.isAnnotationPresent(Mock.class)) {
|
||||
|
@ -1,16 +1,17 @@
|
||||
package tools.dependencygraph;
|
||||
|
||||
import ch.jalu.injector.handlers.instantiation.DependencyDescription;
|
||||
import ch.jalu.injector.handlers.instantiation.Instantiation;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Multimap;
|
||||
import fr.xephi.authme.command.ExecutableCommand;
|
||||
import fr.xephi.authme.converter.Converter;
|
||||
import fr.xephi.authme.initialization.Injection;
|
||||
import fr.xephi.authme.initialization.InjectionHelper;
|
||||
import fr.xephi.authme.process.AsynchronousProcess;
|
||||
import fr.xephi.authme.process.SynchronousProcess;
|
||||
import fr.xephi.authme.security.crypts.EncryptionMethod;
|
||||
import org.bukkit.event.Listener;
|
||||
import tools.utils.InjectorUtils;
|
||||
import tools.utils.ToolTask;
|
||||
import tools.utils.ToolsConstants;
|
||||
|
||||
@ -143,8 +144,8 @@ public class DrawDependency implements ToolTask {
|
||||
}
|
||||
|
||||
private List<String> getDependencies(Class<?> clazz) {
|
||||
Injection<?> injection = InjectionHelper.getInjection(clazz);
|
||||
return injection == null ? null : formatInjectionDependencies(injection);
|
||||
Instantiation<?> instantiation = InjectorUtils.getInstantiationMethod(clazz);
|
||||
return instantiation == null ? null : formatInjectionDependencies(instantiation);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,9 +156,15 @@ public class DrawDependency implements ToolTask {
|
||||
* @param injection the injection whose dependencies should be formatted
|
||||
* @return list of dependencies in a friendly format
|
||||
*/
|
||||
private List<String> formatInjectionDependencies(Injection<?> injection) {
|
||||
Class<?>[] dependencies = injection.getDependencies();
|
||||
Class<?>[] annotations = injection.getDependencyAnnotations();
|
||||
private List<String> formatInjectionDependencies(Instantiation<?> injection) {
|
||||
List<? extends DependencyDescription> descriptions = injection.getDependencies();
|
||||
final int totalDependencies = descriptions.size();
|
||||
Class<?>[] dependencies = new Class<?>[totalDependencies];
|
||||
Class<?>[] annotations = new Class<?>[totalDependencies];
|
||||
for (int i = 0; i < descriptions.size(); ++i) {
|
||||
dependencies[i] = descriptions.get(i).getType();
|
||||
annotations[i] = null; // FIXME #835 descriptions.get(i).getAnnotations();
|
||||
}
|
||||
|
||||
List<String> result = new ArrayList<>(dependencies.length);
|
||||
for (int i = 0; i < dependencies.length; ++i) {
|
||||
|
55
src/test/java/tools/utils/InjectorUtils.java
Normal file
55
src/test/java/tools/utils/InjectorUtils.java
Normal file
@ -0,0 +1,55 @@
|
||||
package tools.utils;
|
||||
|
||||
import ch.jalu.injector.InjectorBuilder;
|
||||
import ch.jalu.injector.handlers.instantiation.DependencyDescription;
|
||||
import ch.jalu.injector.handlers.instantiation.Instantiation;
|
||||
import ch.jalu.injector.handlers.instantiation.InstantiationProvider;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utility for operations with the injector.
|
||||
*/
|
||||
public final class InjectorUtils {
|
||||
|
||||
private InjectorUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a class' dependencies as determined by the injector.
|
||||
*
|
||||
* @param clazz the class to process
|
||||
* @return the class' dependencies, or null if no instantiation method found
|
||||
*/
|
||||
public static Set<Class<?>> getDependencies(Class<?> clazz) {
|
||||
Instantiation<?> instantiation = getInstantiationMethod(clazz);
|
||||
if (instantiation == null) {
|
||||
return null;
|
||||
}
|
||||
Set<Class<?>> dependencies = new HashSet<>();
|
||||
for (DependencyDescription description : instantiation.getDependencies()) {
|
||||
dependencies.add(description.getType());
|
||||
}
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the instantiation method for the given class.
|
||||
*
|
||||
* @param clazz the class to process
|
||||
* @return the instantiation method for the class, or null if none applicable
|
||||
*/
|
||||
public static Instantiation<?> getInstantiationMethod(Class<?> clazz) {
|
||||
List<InstantiationProvider> providers = InjectorBuilder.createInstantiationProviders();
|
||||
for (InstantiationProvider provider : providers) {
|
||||
Instantiation<?> instantiation = provider.get(clazz);
|
||||
if (instantiation != null) {
|
||||
return instantiation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user