diff --git a/projects/springapp/src/main/java/org/nohope/spring/app/Handler.java b/projects/springapp/src/main/java/org/nohope/spring/app/Handler.java index 6dcc290..dc49951 100644 --- a/projects/springapp/src/main/java/org/nohope/spring/app/Handler.java +++ b/projects/springapp/src/main/java/org/nohope/spring/app/Handler.java @@ -104,7 +104,7 @@ protected final T get(@Nonnull final Class clazz) { } @Nonnull - protected T get(@Nonnull final TypeReference reference) { + protected final T get(@Nonnull final TypeReference reference) { return get(reference.getTypeClass()); } diff --git a/projects/springapp/src/main/java/org/nohope/spring/app/HandlerWithStorage.java b/projects/springapp/src/main/java/org/nohope/spring/app/HandlerWithStorage.java index 5f3301e..4fdd7ae 100644 --- a/projects/springapp/src/main/java/org/nohope/spring/app/HandlerWithStorage.java +++ b/projects/springapp/src/main/java/org/nohope/spring/app/HandlerWithStorage.java @@ -43,7 +43,7 @@ protected final Map getModules(final Class clazz) { } /** - * @param clazz + * @param clazz module class * @param supertype of modules to be filtered * @return All the implementations of given superclass */ @@ -85,7 +85,7 @@ protected M getModule(final String moduleName) { protected Subtype getModule(final Class clazz, final String moduleName) { final ModuleDescriptor md = modules.get(moduleName); - if (clazz.isAssignableFrom(md.getClass())) { + if (clazz.isAssignableFrom(md.getModule().getClass())) { @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"}) final Subtype module = (Subtype) md.getModule(); return module; diff --git a/projects/springapp/src/main/java/org/nohope/spring/app/SpringAsyncModularApp.java b/projects/springapp/src/main/java/org/nohope/spring/app/SpringAsyncModularApp.java index 3d00a8b..929f399 100644 --- a/projects/springapp/src/main/java/org/nohope/spring/app/SpringAsyncModularApp.java +++ b/projects/springapp/src/main/java/org/nohope/spring/app/SpringAsyncModularApp.java @@ -370,13 +370,16 @@ public boolean matches(final Constructor obj) { final Type hold = ((ParameterizedType) type).getActualTypeArguments()[0]; final Class heldClass = IntrospectionUtils.getClass(hold); if (heldClass == null) { - throw new IllegalStateException("Missing type information"); + throw new IllegalStateException("Missing type information for dependency provider of " + + constructor.getDeclaringClass().getCanonicalName() + + " module"); } Class value = null; for (final Annotation a : annotations[paramIndex]) { if (a instanceof Dependency) { value = ((Dependency) a).value(); + break; } } @@ -388,7 +391,9 @@ public boolean matches(final Constructor obj) { + clazz); } } else { - throw new IllegalStateException("Unsupported type information"); + throw new IllegalStateException("Unsupported type information found for dependency provider of " + + constructor.getDeclaringClass().getCanonicalName() + + " module (no type specified?)"); } } paramIndex++; @@ -410,7 +415,6 @@ public boolean matches(final Constructor obj) { throw parameterQualifierMismatch(constructor, e.getKey(), pair.getKey()); } } - } } diff --git a/projects/springapp/src/test/java/org/nohope/spring/app/CrossDependenciesTest.java b/projects/springapp/src/test/java/org/nohope/spring/app/CrossDependenciesTest.java index 6302fee..7823158 100644 --- a/projects/springapp/src/test/java/org/nohope/spring/app/CrossDependenciesTest.java +++ b/projects/springapp/src/test/java/org/nohope/spring/app/CrossDependenciesTest.java @@ -1,18 +1,24 @@ package org.nohope.spring.app; import org.junit.Test; +import org.nohope.reflection.TypeReference; +import org.nohope.spring.BeanDefinition; +import org.springframework.context.ConfigurableApplicationContext; +import javax.annotation.Nonnull; import javax.inject.Inject; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Properties; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import static java.util.Arrays.asList; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import static org.nohope.spring.app.SpringAsyncModularApp.*; /** @@ -91,6 +97,111 @@ public DuplicateDependency(final IDependencyProvider param1, } } + public static class InvalidProviderType implements Module { + @Inject + public InvalidProviderType(final IDependencyProvider param) { + } + } + + public static class InvalidProviderType2 implements Module { + @Inject + public InvalidProviderType2(final IDependencyProvider param) { + } + } + + public static class MultiplyConstructors implements Module { + @Inject + public MultiplyConstructors(final IDependencyProvider param, + final IDependencyProvider param2) { + } + + @Inject + public MultiplyConstructors(final IDependencyProvider param) { + } + } + + public static class InvalidDependencyAnnotation implements KindC { + @Inject + public InvalidDependencyAnnotation(@Dependency(KindB.class) final IDependencyProvider param) { + } + } + + public static class InvalidDependencyAnnotation2 implements KindC { + @Inject + public InvalidDependencyAnnotation2(@Dependency(KindB.class) final IDependencyProvider param1, + @Dependency(KindA.class) final IDependencyProvider param2) { + } + } + + @Test + public void illegalDependencyProviderTypeParameter() { + try { + getResolutionOrder(Arrays.> asList(InvalidProviderType.class)); + fail(); + } catch (IllegalStateException e) { + assertEquals("Missing type information for dependency provider of " + + "org.nohope.spring.app.CrossDependenciesTest.InvalidProviderType " + + "module", e.getMessage()); + } + } + + @Test + public void illegalDependencyProviderTypeParameter2() { + try { + getResolutionOrder(Arrays.> asList(InvalidProviderType2.class)); + fail(); + } catch (IllegalStateException e) { + assertEquals("Unsupported type information found for dependency provider of " + + "org.nohope.spring.app.CrossDependenciesTest.InvalidProviderType2 " + + "module (no type specified?)", e.getMessage()); + } + } + + @Test + public void dependencyWithMultiplyInjectableConstructors() { + try { + getResolutionOrder(Arrays.asList( + TestClassA.class, + TestClassC.class, + MultiplyConstructors.class)); + fail(); + } catch (IllegalStateException e) { + assertEquals("More than one injectable constructor found for class " + + "org.nohope.spring.app.CrossDependenciesTest$MultiplyConstructors", e.getMessage()); + } + } + + @Test + public void invalidDependencyAnnotationValue() { + try { + getResolutionOrder(Arrays.asList( + TestClassA.class, + TestClassC.class, + InvalidDependencyAnnotation.class)); + fail(); + } catch (IllegalStateException e) { + assertEquals("Parameter 0 of public org.nohope.spring.app.CrossDependenciesTest$" + + "InvalidDependencyAnnotation(org.nohope.spring.app.IDependencyProvider) " + + "must be annotated with @Dependency(KindA.class)", e.getMessage()); + } + } + + @Test + public void invalidDependencyAnnotationValue2() { + try { + getResolutionOrder(Arrays.asList( + TestClassA.class, + TestClassC.class, + InvalidDependencyAnnotation2.class)); + fail(); + } catch (IllegalStateException e) { + assertEquals("Parameter 0 of public org.nohope.spring.app.CrossDependenciesTest$" + + "InvalidDependencyAnnotation2(org.nohope.spring.app.IDependencyProvider," + + "org.nohope.spring.app.IDependencyProvider) " + + "must be annotated with @Dependency(KindA.class)", e.getMessage()); + } + } + @Test(expected = IllegalArgumentException.class) public void cycleDependency() { getResolutionOrder( @@ -143,7 +254,60 @@ public void duplicateDependency() { getDependencies(DuplicateDependency.class); } + private static class TestSingleton { + } + + private static class TestSingleton2 { + } + private static class CrossdepsHandler extends HandlerWithStorage { + + @Override + protected void onModuleDiscoveryFinished() throws Exception { + assertNotNull(getAppContext()); + assertNotNull(getOrInstantiate(getAppContext(), TestSingleton.class)); + assertNotNull(getAppName()); + + final TestSingleton singleton = new TestSingleton(); + assertSame(singleton, registerSingleton("test", singleton)); + assertSame(singleton, getOrInstantiate(TestSingleton.class)); + assertSame(singleton, get(TestSingleton.class)); + assertSame(singleton, get(new TypeReference() {})); + assertSame(singleton, get(BeanDefinition.of("test", TestSingleton.class))); + assertSame(singleton, get("test", TestSingleton.class)); + assertSame(singleton, get("test", new TypeReference() {})); + assertSame(singleton, get(getAppContext(), "test", TestSingleton.class)); + assertSame(singleton, get(getAppContext(), "test", new TypeReference() {})); + + final TestSingleton2 singleton2 = getOrInstantiate(TestSingleton2.class); + assertNotNull(singleton2); + + assertSame(singleton2, registerSingleton("test2", singleton2)); + assertSame(singleton2, getOrInstantiate(TestSingleton2.class)); + assertSame(singleton2, get(TestSingleton2.class)); + assertSame(singleton2, get(new TypeReference() {})); + + assertEquals(5, getModuleDescriptors().size()); + assertNotNull(getDescriptors(KindA.class)); + assertNotNull(getModules(KindA.class)); + assertNotNull(getModule(TestClassA.class, "a")); + assertNotNull(getModule(KindA.class, "a")); + assertNotNull(getImplementations(KindA.class)); + + try { + getModule(KindB.class, "a"); + fail(); + } catch (final IllegalArgumentException ignored) { + } + } + + @Override + protected void onModuleDiscovered( + @Nonnull final Class clazz, + @Nonnull final ConfigurableApplicationContext ctx, + @Nonnull final Properties properties, @Nonnull final String name) { + super.onModuleDiscovered(clazz, ctx, properties, name); //To change body of overridden methods use File | Settings | File Templates. + } } @Test @@ -179,6 +343,11 @@ public void run() { } final CrossdepsHandler handler = app.getHandler(); + try { + handler.onModuleDiscoveryFinished(); + } catch (final Exception e) { + fail(); + } for (final ModuleDescriptor d : handler.getModuleDescriptors().values()) { final Module module = d.getModule(); if (module instanceof TestClassE) { diff --git a/projects/springapp/src/test/java/org/nohope/spring/app/ModuleDescriptorTest.java b/projects/springapp/src/test/java/org/nohope/spring/app/ModuleDescriptorTest.java new file mode 100644 index 0000000..56f49ee --- /dev/null +++ b/projects/springapp/src/test/java/org/nohope/spring/app/ModuleDescriptorTest.java @@ -0,0 +1,23 @@ +package org.nohope.spring.app; + +import org.junit.Test; +import org.springframework.context.support.GenericApplicationContext; + +import java.util.Properties; + +import static org.junit.Assert.assertEquals; + +/** + * @author Ketoth Xupack + * @since 2013-10-10 14:15 + */ +public class ModuleDescriptorTest { + + @Test + public void repr() { + final GenericApplicationContext ctx = new GenericApplicationContext(); + final ModuleDescriptor descriptor = + new ModuleDescriptor<>("test-module", new Object(), new Properties(), ctx); + assertEquals("test-module@java.lang.Object", descriptor.toString()); + } +}