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