PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/mycila-testing/tags/2.0-rc1/mycila-testing-plugins/mycila-testing-guice/src/main/java/com/mycila/testing/plugin/guice/Guice1TestPlugin.java

http://mycila.googlecode.com/
Java | 177 lines | 134 code | 23 blank | 20 comment | 13 complexity | 927eda5c2546656d34d34679ed15dda0 MD5 | raw file
Possible License(s): Apache-2.0
  1. /**
  2. * Copyright (C) 2008 Mathieu Carbou <mathieu.carbou@gmail.com>
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.mycila.testing.plugin.guice;
  17. import com.google.inject.AbstractModule;
  18. import com.google.inject.Binder;
  19. import com.google.inject.Guice;
  20. import com.google.inject.Inject;
  21. import com.google.inject.Injector;
  22. import com.google.inject.Module;
  23. import com.google.inject.Provider;
  24. import com.google.inject.Stage;
  25. import com.google.inject.TypeLiteral;
  26. import com.google.inject.binder.AnnotatedBindingBuilder;
  27. import com.google.inject.binder.LinkedBindingBuilder;
  28. import com.google.inject.binder.ScopedBindingBuilder;
  29. import com.mycila.testing.core.api.TestContext;
  30. import static com.mycila.testing.core.introspect.Filters.*;
  31. import com.mycila.testing.core.plugin.DefaultTestPlugin;
  32. import java.lang.reflect.Field;
  33. import java.lang.reflect.Method;
  34. import java.lang.reflect.Type;
  35. import java.util.ArrayList;
  36. import java.util.Arrays;
  37. import java.util.List;
  38. /**
  39. * @author Mathieu Carbou (mathieu.carbou@gmail.com)
  40. */
  41. public final class Guice1TestPlugin extends DefaultTestPlugin {
  42. public static final String INJECTOR = "com.google.inject.Injector";
  43. @Override
  44. public void prepareTestInstance(final TestContext context) {
  45. context.attributes().set("guice.providers", new ArrayList<Provider<?>>());
  46. GuiceContext ctx = context.introspector().testClass().getAnnotation(GuiceContext.class);
  47. // create modules
  48. List<Module> modules = new ArrayList<Module>();
  49. modules.add(new AbstractModule() {
  50. @Override
  51. protected void configure() {
  52. bind(ProviderSetup.class).toInstance(new ProviderSetup() {
  53. @Inject
  54. void inject(Injector injector) {
  55. for (Provider<?> provider : context.attributes().<List<Provider<?>>>remove("guice.providers")) {
  56. injector.injectMembers(provider);
  57. }
  58. }
  59. });
  60. }
  61. });
  62. modules.addAll(contextualModules(ctx));
  63. modules.addAll(providedModules(context));
  64. modules.add(bindings(context));
  65. modules.add(providedBindings(context));
  66. if (context.introspector().instance() instanceof Module) {
  67. modules.add((Module) context.introspector().instance());
  68. }
  69. // create injector
  70. Injector injector = Guice.createInjector(findStage(ctx), modules);
  71. context.attributes().set(INJECTOR, injector);
  72. injector.injectMembers(context.introspector().instance());
  73. }
  74. private Module bindings(final TestContext context) {
  75. return new Module() {
  76. public void configure(Binder binder) {
  77. for (final Field field : context.introspector().selectFields(fieldsAnnotatedBy(Bind.class))) {
  78. Guice1TestPlugin.this.configure(context, binder, field.getGenericType(), field.getAnnotation(Bind.class), new InjectedProvider<Object>() {
  79. public Object getInternal() {
  80. return context.introspector().get(field);
  81. }
  82. });
  83. }
  84. }
  85. };
  86. }
  87. private Module providedBindings(final TestContext context) {
  88. return new Module() {
  89. public void configure(Binder binder) {
  90. for (final Method method : context.introspector().selectMethods(excludeOverridenMethods(methodsAnnotatedBy(Bind.class)))) {
  91. Guice1TestPlugin.this.configure(context, binder, method.getGenericReturnType(), method.getAnnotation(Bind.class), new InjectedProvider<Object>() {
  92. public Object getInternal() {
  93. return context.introspector().invoke(method);
  94. }
  95. });
  96. }
  97. }
  98. };
  99. }
  100. @SuppressWarnings({"unchecked"})
  101. private <T> void configure(TestContext context, Binder binder, Type type, Bind annotation, InjectedProvider<T> provider) {
  102. AnnotatedBindingBuilder<T> builder1 = (AnnotatedBindingBuilder<T>) binder.bind(TypeLiteral.get(type));
  103. LinkedBindingBuilder<T> builder2 = annotation.annotatedBy().equals(NoAnnotation.class) ? builder1 : builder1.annotatedWith(annotation.annotatedBy());
  104. ScopedBindingBuilder builder3 = builder2.toProvider(provider);
  105. if (!annotation.scope().equals(NoAnnotation.class)) {
  106. builder3.in(annotation.scope());
  107. }
  108. context.attributes().<List<InjectedProvider<T>>>get("guice.providers").add(provider);
  109. }
  110. @SuppressWarnings({"unchecked"})
  111. private List<Module> providedModules(TestContext ctx) {
  112. List<Module> modules = new ArrayList<Module>();
  113. for (Method method : ctx.introspector().selectMethods(excludeOverridenMethods(and(methodsReturning(Module.class), methodsAnnotatedBy(ModuleProvider.class))))) {
  114. modules.add((Module) ctx.introspector().invoke(method));
  115. }
  116. for (Method method : ctx.introspector().selectMethods(excludeOverridenMethods(and(methodsReturning(Module[].class), methodsAnnotatedBy(ModuleProvider.class))))) {
  117. modules.addAll(Arrays.asList((Module[]) ctx.introspector().invoke(method)));
  118. }
  119. for (Method method : ctx.introspector().selectMethods(excludeOverridenMethods(and(methodsReturning(Iterable.class), methodsAnnotatedBy(ModuleProvider.class))))) {
  120. for (Module module : (Iterable<Module>) ctx.introspector().invoke(method)) {
  121. modules.add(module);
  122. }
  123. }
  124. return modules;
  125. }
  126. private Stage findStage(GuiceContext ctx) {
  127. return ctx == null ? Stage.DEVELOPMENT : ctx.stage();
  128. }
  129. private List<Module> contextualModules(GuiceContext context) {
  130. List<Module> modules = new ArrayList<Module>();
  131. if (context != null) {
  132. for (Class<? extends Module> moduleClass : context.value()) {
  133. try {
  134. modules.add(moduleClass.newInstance());
  135. } catch (Exception e) {
  136. throw new IllegalStateException(String.format("Error instanciating module class '%s': %s", moduleClass.getName(), e.getMessage()), e);
  137. }
  138. }
  139. }
  140. return modules;
  141. }
  142. private static interface ProviderSetup {
  143. }
  144. private static abstract class InjectedProvider<T> implements Provider<T> {
  145. @Inject
  146. Injector injector;
  147. public final T get() {
  148. T t = getInternal();
  149. injector.injectMembers(t);
  150. return t;
  151. }
  152. protected abstract T getInternal();
  153. }
  154. }