1 /* 2 * Copyright (C) 2008 Google Inc. 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 17 package com.google.inject.util; 18 19 import com.google.common.collect.ImmutableList; 20 import com.google.common.collect.ImmutableSet; 21 import com.google.common.collect.Iterables; 22 import com.google.common.collect.Lists; 23 import com.google.common.collect.Maps; 24 import com.google.common.collect.Sets; 25 import com.google.inject.AbstractModule; 26 import com.google.inject.Binder; 27 import com.google.inject.Binding; 28 import com.google.inject.Key; 29 import com.google.inject.Module; 30 import com.google.inject.PrivateBinder; 31 import com.google.inject.PrivateModule; 32 import com.google.inject.Scope; 33 import com.google.inject.internal.Errors; 34 import com.google.inject.spi.DefaultBindingScopingVisitor; 35 import com.google.inject.spi.DefaultElementVisitor; 36 import com.google.inject.spi.Element; 37 import com.google.inject.spi.ElementVisitor; 38 import com.google.inject.spi.Elements; 39 import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding; 40 import com.google.inject.spi.PrivateElements; 41 import com.google.inject.spi.ScopeBinding; 42 import java.lang.annotation.Annotation; 43 import java.util.Arrays; 44 import java.util.LinkedHashSet; 45 import java.util.List; 46 import java.util.Map; 47 import java.util.Set; 48 49 /** 50 * Static utility methods for creating and working with instances of {@link Module}. 51 * 52 * @author jessewilson@google.com (Jesse Wilson) 53 * @since 2.0 54 */ 55 public final class Modules { Modules()56 private Modules() {} 57 58 public static final Module EMPTY_MODULE = new EmptyModule(); 59 60 private static class EmptyModule implements Module { 61 @Override configure(Binder binder)62 public void configure(Binder binder) {} 63 } 64 65 /** 66 * Returns a builder that creates a module that overlays override modules over the given modules. 67 * If a key is bound in both sets of modules, only the binding from the override modules is kept. 68 * If a single {@link PrivateModule} is supplied or all elements are from a single {@link 69 * PrivateBinder}, then this will overwrite the private bindings. Otherwise, private bindings will 70 * not be overwritten unless they are exposed. This can be used to replace the bindings of a 71 * production module with test bindings: 72 * 73 * <pre> 74 * Module functionalTestModule 75 * = Modules.override(new ProductionModule()).with(new TestModule()); 76 * </pre> 77 * 78 * <p>Prefer to write smaller modules that can be reused and tested without overrides. 79 * 80 * @param modules the modules whose bindings are open to be overridden 81 */ override(Module... modules)82 public static OverriddenModuleBuilder override(Module... modules) { 83 return new RealOverriddenModuleBuilder(Arrays.asList(modules)); 84 } 85 86 /** 87 * Returns a builder that creates a module that overlays override modules over the given modules. 88 * If a key is bound in both sets of modules, only the binding from the override modules is kept. 89 * If a single {@link PrivateModule} is supplied or all elements are from a single {@link 90 * PrivateBinder}, then this will overwrite the private bindings. Otherwise, private bindings will 91 * not be overwritten unless they are exposed. This can be used to replace the bindings of a 92 * production module with test bindings: 93 * 94 * <pre> 95 * Module functionalTestModule 96 * = Modules.override(getProductionModules()).with(getTestModules()); 97 * </pre> 98 * 99 * <p>Prefer to write smaller modules that can be reused and tested without overrides. 100 * 101 * @param modules the modules whose bindings are open to be overridden 102 */ override(Iterable<? extends Module> modules)103 public static OverriddenModuleBuilder override(Iterable<? extends Module> modules) { 104 return new RealOverriddenModuleBuilder(modules); 105 } 106 107 /** Returns a new module that installs all of {@code modules}. */ combine(Module... modules)108 public static Module combine(Module... modules) { 109 return combine(ImmutableSet.copyOf(modules)); 110 } 111 112 /** Returns a new module that installs all of {@code modules}. */ combine(Iterable<? extends Module> modules)113 public static Module combine(Iterable<? extends Module> modules) { 114 return new CombinedModule(modules); 115 } 116 117 private static class CombinedModule implements Module { 118 final Set<Module> modulesSet; 119 CombinedModule(Iterable<? extends Module> modules)120 CombinedModule(Iterable<? extends Module> modules) { 121 this.modulesSet = ImmutableSet.copyOf(modules); 122 } 123 124 @Override configure(Binder binder)125 public void configure(Binder binder) { 126 binder = binder.skipSources(getClass()); 127 for (Module module : modulesSet) { 128 binder.install(module); 129 } 130 } 131 } 132 133 /** See the EDSL example at {@link Modules#override(Module[]) override()}. */ 134 public interface OverriddenModuleBuilder { 135 136 /** See the EDSL example at {@link Modules#override(Module[]) override()}. */ with(Module... overrides)137 Module with(Module... overrides); 138 139 /** See the EDSL example at {@link Modules#override(Module[]) override()}. */ with(Iterable<? extends Module> overrides)140 Module with(Iterable<? extends Module> overrides); 141 } 142 143 private static final class RealOverriddenModuleBuilder implements OverriddenModuleBuilder { 144 private final ImmutableSet<Module> baseModules; 145 RealOverriddenModuleBuilder(Iterable<? extends Module> baseModules)146 private RealOverriddenModuleBuilder(Iterable<? extends Module> baseModules) { 147 this.baseModules = ImmutableSet.copyOf(baseModules); 148 } 149 150 @Override with(Module... overrides)151 public Module with(Module... overrides) { 152 return with(Arrays.asList(overrides)); 153 } 154 155 @Override with(Iterable<? extends Module> overrides)156 public Module with(Iterable<? extends Module> overrides) { 157 return new OverrideModule(overrides, baseModules); 158 } 159 } 160 161 static class OverrideModule extends AbstractModule { 162 private final ImmutableSet<Module> overrides; 163 private final ImmutableSet<Module> baseModules; 164 OverrideModule(Iterable<? extends Module> overrides, ImmutableSet<Module> baseModules)165 OverrideModule(Iterable<? extends Module> overrides, ImmutableSet<Module> baseModules) { 166 this.overrides = ImmutableSet.copyOf(overrides); 167 this.baseModules = baseModules; 168 } 169 170 @Override configure()171 public void configure() { 172 Binder baseBinder = binder(); 173 List<Element> baseElements = Elements.getElements(currentStage(), baseModules); 174 175 // If the sole element was a PrivateElements, we want to override 176 // the private elements within that -- so refocus our elements 177 // and binder. 178 if (baseElements.size() == 1) { 179 Element element = Iterables.getOnlyElement(baseElements); 180 if (element instanceof PrivateElements) { 181 PrivateElements privateElements = (PrivateElements) element; 182 PrivateBinder privateBinder = 183 baseBinder.newPrivateBinder().withSource(privateElements.getSource()); 184 for (Key exposed : privateElements.getExposedKeys()) { 185 privateBinder.withSource(privateElements.getExposedSource(exposed)).expose(exposed); 186 } 187 baseBinder = privateBinder; 188 baseElements = privateElements.getElements(); 189 } 190 } 191 192 final Binder binder = baseBinder.skipSources(this.getClass()); 193 final LinkedHashSet<Element> elements = new LinkedHashSet<>(baseElements); 194 final Module scannersModule = extractScanners(elements); 195 final List<Element> overrideElements = 196 Elements.getElements( 197 currentStage(), 198 ImmutableList.<Module>builder().addAll(overrides).add(scannersModule).build()); 199 200 final Set<Key<?>> overriddenKeys = Sets.newHashSet(); 201 final Map<Class<? extends Annotation>, ScopeBinding> overridesScopeAnnotations = 202 Maps.newHashMap(); 203 204 // execute the overrides module, keeping track of which keys and scopes are bound 205 new ModuleWriter(binder) { 206 @Override 207 public <T> Void visit(Binding<T> binding) { 208 overriddenKeys.add(binding.getKey()); 209 return super.visit(binding); 210 } 211 212 @Override 213 public Void visit(ScopeBinding scopeBinding) { 214 overridesScopeAnnotations.put(scopeBinding.getAnnotationType(), scopeBinding); 215 return super.visit(scopeBinding); 216 } 217 218 @Override 219 public Void visit(PrivateElements privateElements) { 220 overriddenKeys.addAll(privateElements.getExposedKeys()); 221 return super.visit(privateElements); 222 } 223 }.writeAll(overrideElements); 224 225 // execute the original module, skipping all scopes and overridden keys. We only skip each 226 // overridden binding once so things still blow up if the module binds the same thing 227 // multiple times. 228 final Map<Scope, List<Object>> scopeInstancesInUse = Maps.newHashMap(); 229 final List<ScopeBinding> scopeBindings = Lists.newArrayList(); 230 new ModuleWriter(binder) { 231 @Override 232 public <T> Void visit(Binding<T> binding) { 233 if (!overriddenKeys.remove(binding.getKey())) { 234 super.visit(binding); 235 236 // Record when a scope instance is used in a binding 237 Scope scope = getScopeInstanceOrNull(binding); 238 if (scope != null) { 239 List<Object> existing = scopeInstancesInUse.get(scope); 240 if (existing == null) { 241 existing = Lists.newArrayList(); 242 scopeInstancesInUse.put(scope, existing); 243 } 244 existing.add(binding.getSource()); 245 } 246 } 247 248 return null; 249 } 250 251 void rewrite(Binder binder, PrivateElements privateElements, Set<Key<?>> keysToSkip) { 252 PrivateBinder privateBinder = 253 binder.withSource(privateElements.getSource()).newPrivateBinder(); 254 255 Set<Key<?>> skippedExposes = Sets.newHashSet(); 256 257 for (Key<?> key : privateElements.getExposedKeys()) { 258 if (keysToSkip.remove(key)) { 259 skippedExposes.add(key); 260 } else { 261 privateBinder.withSource(privateElements.getExposedSource(key)).expose(key); 262 } 263 } 264 265 for (Element element : privateElements.getElements()) { 266 if (element instanceof Binding && skippedExposes.remove(((Binding) element).getKey())) { 267 continue; 268 } 269 if (element instanceof PrivateElements) { 270 rewrite(privateBinder, (PrivateElements) element, skippedExposes); 271 continue; 272 } 273 element.applyTo(privateBinder); 274 } 275 } 276 277 @Override 278 public Void visit(PrivateElements privateElements) { 279 rewrite(binder, privateElements, overriddenKeys); 280 return null; 281 } 282 283 @Override 284 public Void visit(ScopeBinding scopeBinding) { 285 scopeBindings.add(scopeBinding); 286 return null; 287 } 288 }.writeAll(elements); 289 290 // execute the scope bindings, skipping scopes that have been overridden. Any scope that 291 // is overridden and in active use will prompt an error 292 new ModuleWriter(binder) { 293 @Override 294 public Void visit(ScopeBinding scopeBinding) { 295 ScopeBinding overideBinding = 296 overridesScopeAnnotations.remove(scopeBinding.getAnnotationType()); 297 if (overideBinding == null) { 298 super.visit(scopeBinding); 299 } else { 300 List<Object> usedSources = scopeInstancesInUse.get(scopeBinding.getScope()); 301 if (usedSources != null) { 302 StringBuilder sb = 303 new StringBuilder( 304 "The scope for @%s is bound directly and cannot be overridden."); 305 sb.append("%n original binding at " + Errors.convert(scopeBinding.getSource())); 306 for (Object usedSource : usedSources) { 307 sb.append("%n bound directly at " + Errors.convert(usedSource) + ""); 308 } 309 binder 310 .withSource(overideBinding.getSource()) 311 .addError(sb.toString(), scopeBinding.getAnnotationType().getSimpleName()); 312 } 313 } 314 return null; 315 } 316 }.writeAll(scopeBindings); 317 } 318 getScopeInstanceOrNull(Binding<?> binding)319 private Scope getScopeInstanceOrNull(Binding<?> binding) { 320 return binding.acceptScopingVisitor( 321 new DefaultBindingScopingVisitor<Scope>() { 322 @Override 323 public Scope visitScope(Scope scope) { 324 return scope; 325 } 326 }); 327 } 328 } 329 330 private static class ModuleWriter extends DefaultElementVisitor<Void> { 331 protected final Binder binder; 332 333 ModuleWriter(Binder binder) { 334 this.binder = binder.skipSources(this.getClass()); 335 } 336 337 @Override 338 protected Void visitOther(Element element) { 339 element.applyTo(binder); 340 return null; 341 } 342 343 void writeAll(Iterable<? extends Element> elements) { 344 for (Element element : elements) { 345 element.acceptVisitor(this); 346 } 347 } 348 } 349 350 private static Module extractScanners(Iterable<Element> elements) { 351 final List<ModuleAnnotatedMethodScannerBinding> scanners = Lists.newArrayList(); 352 ElementVisitor<Void> visitor = 353 new DefaultElementVisitor<Void>() { 354 @Override 355 public Void visit(ModuleAnnotatedMethodScannerBinding binding) { 356 scanners.add(binding); 357 return null; 358 } 359 }; 360 for (Element element : elements) { 361 element.acceptVisitor(visitor); 362 } 363 return new AbstractModule() { 364 @Override 365 protected void configure() { 366 for (ModuleAnnotatedMethodScannerBinding scanner : scanners) { 367 scanner.applyTo(binder()); 368 } 369 } 370 }; 371 } 372 } 373