mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-12-24 17:47:38 +01:00
Injector - disallow static PostConstruct methods, add more tests
This commit is contained in:
parent
ee08eb9efb
commit
2c491803d3
@ -121,17 +121,19 @@ public class AuthMeServiceInitializer {
|
||||
if (Annotation.class.isAssignableFrom(clazz)) {
|
||||
throw new UnsupportedOperationException("Cannot retrieve annotated elements in this way!");
|
||||
} else if (objects.containsKey(clazz)) {
|
||||
return getObject(clazz);
|
||||
return clazz.cast(objects.get(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.
|
||||
// First time we come across clazz, need to instantiate it. Validate that we can do so
|
||||
validatePackage(clazz);
|
||||
validateInstantiable(clazz);
|
||||
|
||||
// Add the clazz to the list of traversed classes in a new Set, so each path we take has its own Set.
|
||||
traversedClasses = new HashSet<>(traversedClasses);
|
||||
traversedClasses.add(clazz);
|
||||
return instantiate(clazz, traversedClasses);
|
||||
T object = instantiate(clazz, traversedClasses);
|
||||
storeObject(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,7 +156,6 @@ public class AuthMeServiceInitializer {
|
||||
validateInjectionHasNoCircularDependencies(injection.getDependencies(), traversedClasses);
|
||||
Object[] dependencies = resolveDependencies(injection, traversedClasses);
|
||||
T object = injection.instantiateWith(dependencies);
|
||||
storeObject(object);
|
||||
executePostConstructMethods(object);
|
||||
return object;
|
||||
}
|
||||
@ -186,27 +187,6 @@ public class AuthMeServiceInitializer {
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal method to retrieve an object from the objects map for <b>non-annotation classes</b>.
|
||||
* In such cases, the type of the entry always corresponds to the key, i.e. the entry of key
|
||||
* {@code Class<T>} is guaranteed to be of type {@code T}.
|
||||
* <p>
|
||||
* 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 <T> the type
|
||||
* @return the implementation
|
||||
*/
|
||||
private <T> T getObject(Class<T> 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.
|
||||
@ -262,7 +242,7 @@ public class AuthMeServiceInitializer {
|
||||
private static void executePostConstructMethods(Object object) {
|
||||
for (Method method : object.getClass().getDeclaredMethods()) {
|
||||
if (method.isAnnotationPresent(PostConstruct.class)) {
|
||||
if (method.getParameterTypes().length == 0) {
|
||||
if (method.getParameterTypes().length == 0 && !Modifier.isStatic(method.getModifiers())) {
|
||||
try {
|
||||
method.setAccessible(true);
|
||||
method.invoke(object);
|
||||
@ -270,8 +250,9 @@ public class AuthMeServiceInitializer {
|
||||
throw new UnsupportedOperationException(e);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("@PostConstruct methods must have an empty parameter list. " +
|
||||
"Found parameters in " + method + " belonging to " + object.getClass());
|
||||
throw new IllegalStateException(String.format("@PostConstruct methods may not be static or have "
|
||||
+ " any parameters. Method '%s' of class '%s' is either static or has parameters",
|
||||
method.getName(), object.getClass().getSimpleName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package fr.xephi.authme.initialization;
|
||||
|
||||
import fr.xephi.authme.initialization.samples.AlphaService;
|
||||
import fr.xephi.authme.initialization.samples.BadFieldInjection;
|
||||
import fr.xephi.authme.initialization.samples.BetaManager;
|
||||
import fr.xephi.authme.initialization.samples.CircularClasses;
|
||||
@ -18,6 +19,7 @@ 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.hamcrest.Matchers.sameInstance;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
@ -47,12 +49,18 @@ public class AuthMeServiceInitializerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void shouldThrowForInvalidPackage() {
|
||||
// given / when / then
|
||||
initializer.get(InvalidClass.class);
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void shouldThrowForUnregisteredPrimitiveType() {
|
||||
// given / when / then
|
||||
initializer.get(int.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPassValueByAnnotation() {
|
||||
// given
|
||||
@ -169,7 +177,19 @@ public class AuthMeServiceInitializerTest {
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void shouldThrowForInvalidPostConstructMethod() {
|
||||
// given / when / then
|
||||
initializer.get(InvalidPostConstruct.class);
|
||||
initializer.get(InvalidPostConstruct.WithParams.class);
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void shouldThrowForStaticPostConstructMethod() {
|
||||
// given / when / then
|
||||
initializer.get(InvalidPostConstruct.Static.class);
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void shouldForwardExceptionFromPostConstruct() {
|
||||
// given / when / then
|
||||
initializer.get(InvalidPostConstruct.ThrowsException.class);
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
@ -191,4 +211,26 @@ public class AuthMeServiceInitializerTest {
|
||||
assertThat(cwad.getAbstractDependency() == concrete, equalTo(true));
|
||||
assertThat(cwad.getAlphaService(), not(nullValue()));
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void shouldThrowForAlreadyRegisteredClass() {
|
||||
// given
|
||||
initializer.register(new BetaManager());
|
||||
|
||||
// when / then
|
||||
initializer.register(BetaManager.class, new BetaManager());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateNewUntrackedInstance() {
|
||||
// given / when
|
||||
AlphaService singletonScoped = initializer.get(AlphaService.class);
|
||||
AlphaService requestScoped = initializer.newInstance(AlphaService.class);
|
||||
|
||||
// then
|
||||
assertThat(singletonScoped.getProvidedClass(), not(nullValue()));
|
||||
assertThat(singletonScoped.getProvidedClass(), equalTo(requestScoped.getProvidedClass()));
|
||||
assertThat(singletonScoped, not(sameInstance(requestScoped)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
package fr.xephi.authme.initialization;
|
||||
|
||||
import fr.xephi.authme.initialization.samples.AlphaService;
|
||||
import fr.xephi.authme.initialization.samples.BetaManager;
|
||||
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.GammaService;
|
||||
import fr.xephi.authme.initialization.samples.ProvidedClass;
|
||||
import fr.xephi.authme.initialization.samples.Size;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.arrayContaining;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link FieldInjection}.
|
||||
*/
|
||||
public class FieldInjectionTest {
|
||||
|
||||
@Test
|
||||
public void shouldReturnDependencies() {
|
||||
// given
|
||||
FieldInjection<FieldInjectionWithAnnotations> injection =
|
||||
FieldInjection.provide(FieldInjectionWithAnnotations.class).get();
|
||||
|
||||
// when
|
||||
Class<?>[] dependencies = injection.getDependencies();
|
||||
Class<?>[] annotations = injection.getDependencyAnnotations();
|
||||
|
||||
// then
|
||||
assertThat(dependencies, arrayContaining(BetaManager.class, int.class, long.class, ClassWithAnnotations.class));
|
||||
assertThat(annotations, arrayContaining((Class<?>) null, Size.class, Duration.class, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInstantiateClass() {
|
||||
// given
|
||||
FieldInjection<BetaManager> injection = FieldInjection.provide(BetaManager.class).get();
|
||||
ProvidedClass providedClass = new ProvidedClass("");
|
||||
AlphaService alphaService = AlphaService.newInstance(providedClass);
|
||||
GammaService gammaService = new GammaService(alphaService);
|
||||
|
||||
// when
|
||||
BetaManager betaManager = injection.instantiateWith(providedClass, gammaService, alphaService);
|
||||
|
||||
// then
|
||||
assertThat(betaManager, not(nullValue()));
|
||||
assertThat(betaManager.getDependencies(), arrayContaining(providedClass, gammaService, alphaService));
|
||||
}
|
||||
|
||||
}
|
@ -17,4 +17,14 @@ public class AlphaService {
|
||||
public ProvidedClass getProvidedClass() {
|
||||
return providedClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance (for instantiations in tests).
|
||||
*
|
||||
* @param providedClass .
|
||||
* @return created instance
|
||||
*/
|
||||
public static AlphaService newInstance(ProvidedClass providedClass) {
|
||||
return new AlphaService(providedClass);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ public class GammaService {
|
||||
private AlphaService alphaService;
|
||||
|
||||
@Inject
|
||||
GammaService(AlphaService alphaService) {
|
||||
public GammaService(AlphaService alphaService) {
|
||||
this.alphaService = alphaService;
|
||||
}
|
||||
|
||||
|
@ -8,12 +8,35 @@ import javax.inject.Inject;
|
||||
*/
|
||||
public class InvalidPostConstruct {
|
||||
|
||||
@Inject
|
||||
private AlphaService alphaService;
|
||||
@Inject
|
||||
private ProvidedClass providedClass;
|
||||
public static final class WithParams {
|
||||
@Inject
|
||||
private AlphaService alphaService;
|
||||
@Inject
|
||||
private ProvidedClass providedClass;
|
||||
|
||||
@PostConstruct
|
||||
public void invalidPostConstr(BetaManager betaManager) {
|
||||
WithParams() { }
|
||||
|
||||
@PostConstruct
|
||||
public void invalidPostConstr(BetaManager betaManager) {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Static {
|
||||
@Inject
|
||||
Static(BetaManager betaManager) {
|
||||
// --
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public static void invalidMethod() {
|
||||
// --
|
||||
}
|
||||
}
|
||||
|
||||
public static final class ThrowsException {
|
||||
@PostConstruct
|
||||
public void throwingPostConstruct() {
|
||||
throw new IllegalStateException("Exception in post construct");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user