下面列出了com.google.inject.spi.DefaultElementVisitor#com.google.inject.spi.Element 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public Void visit(ExposedBinding<? extends T> binding) {
final PrivateBinder privateBinder = this.binder.newPrivateBinder();
final Scoper scoper = new Scoper(privateBinder, scoping);
for(Element element : binding.getPrivateElements().getElements()) {
if(element instanceof Binding) {
((Binding) element).acceptTargetVisitor(scoper);
} else {
element.applyTo(privateBinder);
}
}
for(Key key : binding.getPrivateElements().getExposedKeys()) {
privateBinder.expose(key);
}
return null;
}
/**
* Parse single guice element.
*
* @param injector injector instance
* @param element element to analyze
* @return parsed descriptor or null if element is not supported (or intentionally skipped)
*/
public static BindingDeclaration parseElement(final Injector injector, final Element element) {
final BindingDeclaration dec = element.acceptVisitor(ELEMENT_VISITOR);
if (dec != null) {
fillDeclaration(dec, injector);
fillSource(dec, element);
dec.setModule(BindingUtils.getModules(element).get(0));
if (dec.getKey() != null) {
final Class ann = dec.getKey().getAnnotationType();
if (ann != null) {
if (ann.getName().equals("com.google.inject.internal.Element")) {
dec.setSpecial(Collections.singletonList("multibinding"));
}
if (ann.getName().startsWith("com.google.inject.internal.RealOptionalBinder")) {
dec.setSpecial(Collections.singletonList("optional binding"));
}
}
}
}
return dec;
}
private static Map<String, ModuleDeclaration> indexElements(final Injector injector,
final Collection<? extends Element> elements) {
final Map<String, ModuleDeclaration> index = new LinkedHashMap<>();
for (Element element : elements) {
try {
final BindingDeclaration dec = parseElement(injector, element);
if (dec == null) {
continue;
}
// create modules for entire modules chains
final ModuleDeclaration mod = initModules(index, BindingUtils.getModules(element));
mod.getDeclarations().add(dec);
} catch (PrivateModuleException ex) {
// private module appeared
indexPrivate(index, injector, ex.getElements());
}
}
return index;
}
private void renderGuiceWeb(final TreeNode filter) throws Exception {
final List<String> servlets = new ArrayList<>();
final List<String> filters = new ArrayList<>();
for (Element element : Elements.getElements(Stage.TOOL, modules)) {
if (!(element instanceof Binding)) {
continue;
}
@SuppressWarnings("unchecked") final WebElementModel model =
(WebElementModel) ((Binding) element).acceptTargetVisitor(VISITOR);
if (model == null) {
continue;
}
final String line = renderGuiceWebElement(model, element);
if (model.getType().equals(WebElementType.FILTER)) {
filters.add(line);
} else {
servlets.add(line);
}
}
renderGucieWebElements(servlets, filters, filter);
}
private static boolean isInDisabledModule(final Element element,
final List<String> disabled,
final Set<String> actuallyDisabled) {
if (!disabled.isEmpty()) {
final List<String> modules = BindingUtils.getModules(element);
// need to check from top modules to lower, otherwise removed modules list will be incorrect
for (int i = modules.size() - 1; i >= 0; i--) {
final String mod = modules.get(i);
if (disabled.contains(mod)) {
actuallyDisabled.add(mod);
return true;
}
}
}
return false;
}
/**
* Resolve guice configuration element declaration module chain. The first list element is declaration module.
* Later elements appear if module was installed by other module.
*
* @param element guice SPI element
* @return modules chain from declaration point or single {@link #JIT_MODULE} if binding is a JIT binding
*/
public static List<String> getModules(final Element element) {
final List<String> modules;
if (element.getSource() instanceof ElementSource) {
ElementSource source = (ElementSource) element.getSource();
// if module was repackaged by elements api, we need an original source in order to build correct report
if (source.getOriginalElementSource() != null) {
source = source.getOriginalElementSource();
}
modules = source.getModuleClassNames();
} else {
// consider JIT binding
modules = Collections.singletonList(JIT_MODULE);
}
return modules;
}
@Override
protected void configure() {
for (Element element : privateElements.getElements()) {
if (element instanceof Binding && isExcluded(((Binding<?>) element).getKey())) {
continue;
}
element.applyTo(binder());
}
for (Key<?> exposedKey : privateElements.getExposedKeys()) {
if (isExcluded(exposedKey)) {
continue;
}
expose(exposedKey);
}
}
default void installIn(Scoping scoping, Module... modules) {
final Scoper scoper = new Scoper(this, scoping);
for(Element element : Elements.getElements(modules)) {
if(element instanceof Binding) {
((Binding) element).acceptTargetVisitor(scoper);
} else {
element.applyTo(this);
}
}
}
public DependencyCollector processElements(Iterable<Element> elements) {
final ElementVisitor visitor = new ElementVisitor();
for(Element element : elements) {
element.acceptVisitor(visitor);
}
processImplicitBindings();
return this;
}
public static <T> Optional<Binding<T>> findBinding(Iterable<? extends Element> elements, Key<T> key) {
for(Element element : elements) {
if(element instanceof Binding && key.equals(((Binding<?>) element).getKey())) {
return Optional.of((Binding<T>) element);
}
}
return Optional.empty();
}
private Module createModule() {
List<Element> allElements = new LinkedList<>();
for (List<Element> moduleElements : modules.values()) {
allElements.addAll(moduleElements);
}
ElementCollector collector = new ElementCollector();
for (ListIterator<Element> it = allElements.listIterator(allElements.size()); it.hasPrevious(); ) {
it.previous().acceptVisitor(collector);
}
return Elements.getModule(collector.elements);
}
public void assertAllDependenciesDeclared() {
List<Key> requiredKeys = new ArrayList<>();
List<Element> elements = Elements.getElements(module);
for (Element element : elements) {
element.acceptVisitor(new DefaultElementVisitor<Void>() {
@Override
public <T> Void visit(ProviderLookup<T> providerLookup) {
// Required keys are the only ones with null injection points.
if (providerLookup.getDependency().getInjectionPoint() == null) {
requiredKeys.add(providerLookup.getKey());
}
return null;
}
});
}
Injector injector = Guice.createInjector(module,
new AbstractModule() {
@Override
@SuppressWarnings("unchecked")
protected void configure() {
binder().disableCircularProxies();
binder().requireAtInjectOnConstructors();
binder().requireExactBindingAnnotations();
for (Key<?> key : requiredKeys) {
bind((Key) key).toProvider(Providers.of(null));
}
}
});
injector.getAllBindings();
}
@Override
public String renderReport(final GuiceAopConfig config) {
final StringBuilder res = new StringBuilder();
// AOP declarations
final List<Element> declared = Elements.getElements(Stage.TOOL, modules).stream()
.filter(it -> it instanceof InterceptorBinding)
.collect(Collectors.toList());
if (!config.isHideDeclarationsBlock()) {
final List<ModuleDeclaration> declarationModules = GuiceModelParser.parse(injector, declared);
res.append(Reporter.NEWLINE).append(Reporter.NEWLINE);
renderDeclared(declarationModules, res);
}
if (!declared.isEmpty()) {
// AOP appliance map
final List<Binding> guiceManagedObjects = injector.getAllBindings().values().stream()
.filter(it -> it instanceof ConstructorBinding)
.collect(Collectors.toList());
final List<AopDeclaration> tree = filter(GuiceModelParser.parse(injector, guiceManagedObjects), config);
if (!tree.isEmpty()) {
res.append(Reporter.NEWLINE).append(Reporter.NEWLINE);
renderMap(tree, res);
}
}
return res.toString();
}
/**
* NOTE: this will work only for elements, parsed with SPI api, and not for real bindings!
*
* @param element guice binding element
* @return element declaration stacktrace element
*/
public static StackTraceElement getDeclarationSource(final Element element) {
final Object source = element.getSource();
StackTraceElement traceElement = null;
if (source instanceof ElementSource) {
final ElementSource src = (ElementSource) source;
if (src.getDeclaringSource() instanceof StackTraceElement) {
traceElement = (StackTraceElement) src.getDeclaringSource();
} else if (src.getDeclaringSource() instanceof Method) {
traceElement = (StackTraceElement) StackTraceElements.forMember((Method) src.getDeclaringSource());
}
}
return traceElement;
}
/**
* Parse guice elements into modules tree. Only direct bindings are accepted. Supports both module elements
* and injector bindings (but result will slightly vary). JIT bindings are also grouped into special module.
*
* @param injector injector instance
* @param elements elements to analyze
* @return tree of modules.
*/
public static List<ModuleDeclaration> parse(final Injector injector,
final Collection<? extends Element> elements) {
final Map<String, ModuleDeclaration> index = indexElements(injector, elements);
final List<ModuleDeclaration> res = new ArrayList<>();
// build modules tree
for (ModuleDeclaration mod : index.values()) {
if (mod.getParent() != null) {
index.get(mod.getParent()).getChildren().add(mod);
} else {
res.add(mod);
}
// sort declarations according to declaration order (in module)
mod.getDeclarations().sort(Comparator
.comparingInt(BindingDeclaration::getSourceLine)
.thenComparing(BindingDeclaration::getType)
.thenComparing(it -> it.getScope() != null ? it.getScope().getSimpleName() : "")
.thenComparing(it -> it.getKey() != null ? GuiceModelUtils.renderKey(it.getKey()) : ""));
}
// sort entire tree by module name for predictable order
final Comparator<ModuleDeclaration> moduleComparator = Comparator.comparing(ModuleDeclaration::isJitModule)
.thenComparing(it -> it.getType().getName());
res.sort(moduleComparator);
GuiceModelUtils.visit(res, it -> it.getChildren().sort(moduleComparator));
// return only root modules
return res;
}
private static void fillSource(final BindingDeclaration dec, final Element element) {
final StackTraceElement trace = GuiceModelUtils.getDeclarationSource(element);
if (trace != null) {
// using full stacktrace element to grant proper link highlight in idea
dec.setSource(trace.toString());
dec.setSourceLine(trace.getLineNumber());
} else {
final Object source = element.getSource();
if (source instanceof Class) {
dec.setSource(((Class) source).getName());
} else {
LOGGER.warn("Unknown element '{}' source: {}", dec, source);
}
}
}
private String renderGuiceWebElement(final WebElementModel model, final Element element) throws Exception {
return String.format("%-15s %-20s %-7s %-30s %s",
model.getType().equals(WebElementType.FILTER) ? "guicefilter" : "guiceservlet",
model.getPattern(),
model.getPatternType() == UriPatternType.REGEX ? "regex" : "",
(model.isInstance() ? "instance of " : "") + GuiceModelUtils.renderKey(model.getKey()),
RenderUtils.renderClass(Class.forName(BindingUtils.getModules(element).get(0))));
}
/**
* Search for extensions in guice bindings (directly declared in modules).
* Only user provided modules are analyzed. Overriding modules are not analyzed.
* <p>
* Use guice SPI. In order to avoid duplicate analysis in injector creation time, wrap
* parsed elements as new module (and use it instead of original modules). Also, if
* bound extension is disabled, target binding is simply removed (in order to
* provide the same disable semantic as with usual extensions).
*
* @param context configuration context
* @return list of repackaged modules to use
*/
private static List<Module> analyzeModules(final ConfigurationContext context,
final Stopwatch modulesTimer) {
List<Module> modules = context.getNormalModules();
final Boolean configureFromGuice = context.option(AnalyzeGuiceModules);
// one module mean no user modules registered
if (modules.size() > 1 && configureFromGuice) {
// analyzing only user bindings (excluding overrides and guicey technical bindings)
final GuiceBootstrapModule bootstrap = (GuiceBootstrapModule) modules.remove(modules.size() - 1);
try {
// find extensions and remove bindings if required (disabled extensions)
final Stopwatch gtime = context.stat().timer(Stat.BindingsResolutionTime);
final List<Element> elements = new ArrayList<>(
Elements.getElements(context.option(InjectorStage), modules));
gtime.stop();
// exclude analysis time from modules processing time (it's installer time)
modulesTimer.stop();
analyzeAndFilterBindings(context, modules, elements);
modulesTimer.start();
// wrap raw elements into module to avoid duplicate work on guice startup and put back bootstrap
modules = Arrays.asList(Elements.getModule(elements), bootstrap);
} catch (Exception ex) {
// better show meaningful message then just fail entire startup with ambiguous message
// NOTE if guice configuration is not OK it will fail here too, but user will see injector creation
// error as last error in logs.
LOGGER.error("Failed to analyze guice bindings - skipping this step. Note that configuration"
+ " from bindings may be switched off with " + GuiceyOptions.class.getSimpleName() + "."
+ AnalyzeGuiceModules.name() + " option.", ex);
// recover and use original modules
modules.add(bootstrap);
if (!modulesTimer.isRunning()) {
modulesTimer.start();
}
}
}
return modules;
}
protected V message(Element element, String text) {
return message(element.getSource(), text);
}
public static List<Element> visit(ElementVisitor<?> visitor, Iterable<? extends Module> modules) {
final List<Element> elements = Elements.getElements(Stage.TOOL, modules);
elements.forEach(e -> e.acceptVisitor(visitor));
return elements;
}
public static List<Element> visit(ElementVisitor<?> visitor, Module... modules) {
return visit(visitor, Arrays.asList(modules));
}
@Override
public Boolean visitOther(Element element) {
elements.add(element);
return Boolean.TRUE;
}
/**
* May return {@link Module} if JIT binding provided.
*
* @param element guice SPI element
* @return top module class name
*/
public static Class<? extends Module> getTopDeclarationModule(final Element element) {
final List<String> modulesStack = getModules(element);
// top most element is top most module (registered by user)
return getModuleClass(modulesStack.get(modulesStack.size() - 1));
}