Revision: 1179
Author: [email protected]
Date: Sat Jul  3 07:55:29 2010
Log: Removing the ScopeChecker proof-of-concept.

I exercised this utility against a large body of production code trying to find problems. It didn't. It reported a few false positives and some dubious decisions, but ultimately I don't think it's worth having.
http://code.google.com/p/google-guice/source/detail?r=1179

Deleted:
 /trunk/src/com/google/inject/util/ScopeChecker.java
 /trunk/test/com/google/inject/util/ScopeCheckerTest.java

=======================================
--- /trunk/src/com/google/inject/util/ScopeChecker.java Thu Jul 23 17:48:12 2009
+++ /dev/null
@@ -1,180 +0,0 @@
-/**
- * Copyright (C) 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.inject.util;
-
-import com.google.inject.Binding;
-import com.google.inject.ConfigurationException;
-import com.google.inject.Injector;
-import com.google.inject.Key;
-import com.google.inject.Scope;
-import com.google.inject.Scopes;
-import com.google.inject.internal.ImmutableList;
-import com.google.inject.internal.ImmutableMap;
-import com.google.inject.internal.Lists;
-import com.google.inject.internal.Maps;
-import static com.google.inject.internal.Preconditions.checkArgument;
-import com.google.inject.spi.BindingScopingVisitor;
-import com.google.inject.spi.Dependency;
-import com.google.inject.spi.HasDependencies;
-import com.google.inject.spi.Message;
-import com.google.inject.spi.ProviderBinding;
-import java.lang.annotation.Annotation;
-import static java.util.Arrays.asList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Inspects an injector for scoping violations. Scoping violations exist whenever a long-lived - * object (such as a singleton) depends on a short-lived object (such as a request-scoped object). - * To use, create an scope checker and call it's {...@code check()} method with your scoping
- * annotations in decreasing duration:
- * <pre><code>
- *     ScopeChecker scopeChecker = new ScopeChecker(injector);
- * scopeChecker.check(Singleton.class, SessionScoped.class, RequestScoped.class);
- * </code></pre>
- * If there are scoping violations in the injector, the call will fail with a detailed {...@code
- * ConfigurationException}.
- *
- * @author [email protected] (Jesse Wilson)
- */
-public class ScopeChecker {
-
-  private final Injector injector;
-
-  public ScopeChecker(Injector injector) {
-    this.injector = injector;
-  }
-
-  /**
-   * Checks this checker's injector for scoping violations.
-   *
-   * @param longest the outermost scope, such as {...@code Singleton.class}.
-   * @param nested a scope immediately nested within {...@code longest}
- * @param furtherNested any scopes nested within {...@code nested}, in decreasing duration.
-   * @throws ConfigurationException if any violations are found.
-   */
- public void check(Class<? extends Annotation> longest, Class<? extends Annotation> nested,
-      Class<? extends Annotation>... furtherNested) {
-    Ranker ranker = new Ranker(longest, nested, furtherNested);
-    Map<Key<?>, Node> nodes = Maps.newHashMap();
-
-    // build the graph of node dependencies with scope ranks
-    for (Binding<?> binding : injector.getAllBindings().values()) {
-      Key<?> key = binding.getKey();
-      Node node = getNode(nodes, key);
-      ranker.rank(binding, node);
-
-      // explicitly ignore dependencies that come via providers.
-      if (binding instanceof ProviderBinding) {
-        continue;
-      }
-
-      if (binding instanceof HasDependencies) {
-        HasDependencies hasDependencies = (HasDependencies) binding;
- for (Dependency<?> dependency : hasDependencies.getDependencies()) {
-          getNode(nodes, dependency.getKey()).addUser(node);
-        }
-      }
-    }
-
- // walk through the nodes, pushing effective scopes through dependencies
-    for (Node node : nodes.values()) {
-      node.pushScopeToUsers();
-    }
-
- // on the nodes with dependencies narrower than themselves, print an error
-    List<Message> messages = Lists.newArrayList();
-    for (Node node : nodes.values()) {
-      if (node.isScopedCorrectly()) {
-        continue;
-      }
-
- StringBuilder error = new StringBuilder("Illegal scoped dependency: ").append(node);
-      Node dependency = node;
-      do {
-        dependency = dependency.effectiveScopeDependency();
-        error.append("\n  depends on ").append(dependency);
-      } while (!dependency.isEffectiveScopeAppliedScope());
-      messages.add(new Message(error.toString()));
-    }
-
-    if (!messages.isEmpty()) {
-      throw new ConfigurationException(messages);
-    }
-  }
-
-  private Node getNode(Map<Key<?>, Node> nodes, Key<?> key) {
-    Node node = nodes.get(key);
-    if (node == null) {
-      node = new Node(key);
-      nodes.put(key, node);
-    }
-    return node;
-  }
-
-  /**
- * Applies the scoping rank to a node. Scopes are stored as integers, and narrower scopes get
-   * greater values.
-   */
-  private class Ranker implements BindingScopingVisitor<Scope> {
- private final ImmutableList<Class<? extends Annotation>> scopeAnnotations;
-    private final ImmutableMap<Scope, Integer> scopeToRank;
-
- private Ranker(Class<? extends Annotation> longest, Class<? extends Annotation> nested,
-      Class<? extends Annotation>... furtherNested) {
- scopeAnnotations = new ImmutableList.Builder<Class<? extends Annotation>>()
-          .add(longest)
-          .add(nested)
-          .addAll(asList(furtherNested))
-          .build();
-
- ImmutableMap.Builder<Scope, Integer> scopeToRankBuilder = ImmutableMap.builder(); - Map<Class<? extends Annotation>, Scope> annotationToScope = injector.getScopeBindings();
-      int i = 0;
- for (Class<? extends Annotation> scopeAnnotation : scopeAnnotations) {
-        Scope scope = annotationToScope.get(scopeAnnotation);
- checkArgument(scope != null, "No scope binding for %s", scopeAnnotation);
-        scopeToRankBuilder.put(scope, i++);
-      }
-      scopeToRank = scopeToRankBuilder.build();
-    }
-
-    public void rank(Binding<?> binding, Node node) {
-      Scope scope = binding.acceptScopingVisitor(this);
-      Integer rank = scopeToRank.get(scope);
-      if (rank != null) {
-        node.setScopeRank(rank, scopeAnnotations.get(rank));
-      }
-    }
-
-    public Scope visitEagerSingleton() {
-      return Scopes.SINGLETON;
-    }
-
- public com.google.inject.Scope visitScope(com.google.inject.Scope scope) {
-      return scope;
-    }
-
- public Scope visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
-      throw new AssertionError();
-    }
-
-    public Scope visitNoScoping() {
-      return Scopes.NO_SCOPE;
-    }
-  }
-}
=======================================
--- /trunk/test/com/google/inject/util/ScopeCheckerTest.java Mon Aug 10 16:30:46 2009
+++ /dev/null
@@ -1,226 +0,0 @@
-/**
- * Copyright (C) 2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.inject.util;
-
-import com.google.inject.AbstractModule;
-import static com.google.inject.Asserts.assertContains;
-import com.google.inject.ConfigurationException;
-import com.google.inject.Guice;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.Key;
-import com.google.inject.Module;
-import com.google.inject.Provider;
-import com.google.inject.Scope;
-import com.google.inject.ScopeAnnotation;
-import com.google.inject.Singleton;
-import static java.lang.annotation.ElementType.TYPE;
-import java.lang.annotation.Retention;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import java.lang.annotation.Target;
-import junit.framework.TestCase;
-
-/**
- * @author [email protected] (Jesse Wilson)
- */
-public class ScopeCheckerTest extends TestCase {
-
-  @Target(TYPE) @Retention(RUNTIME) @ScopeAnnotation
-  @interface Annually {}
-
-  @Target(TYPE) @Retention(RUNTIME) @ScopeAnnotation
-  @interface Seasonally {}
-
-  @Target(TYPE) @Retention(RUNTIME) @ScopeAnnotation
-  @interface Daily {}
-
-  Module scopesModule = new AbstractModule() {
-    protected void configure() {
-      bindScope(Annually.class, newScope());
-      bindScope(Seasonally.class, newScope());
-      bindScope(Daily.class, newScope());
-    }
-  };
-
- /** change your shirt daily. Depends on the sleeve length appropriate for the weather */
-  static class Shirt {
-    @Inject SleeveLength sleeveLength;
-  }
-
-  /** long sleeves in the winter, short sleeves in the summer, etc. */
-  static class SleeveLength {
-    @Inject Style style;
-  }
-
-  /** fashion evolves over time */
-  static class Style {}
-
-  /** pants can be tweaked (with belts) to fit a changing style */
-  static class Pants {
-    @Inject Provider<Style> style;
-  }
-
-  public void testProperlyNestedScopes() {
-    Module module = new AbstractModule() {
-      protected void configure() {
-        bind(Style.class).in(Annually.class);
-        bind(SleeveLength.class).in(Seasonally.class);
-        bind(Shirt.class).in(Daily.class);
-      }
-    };
-
- ScopeChecker scopeChecker = new ScopeChecker(Guice.createInjector(scopesModule, module));
-    scopeChecker.check(Annually.class, Seasonally.class, Daily.class);
-  }
-
-  public void testDependingOnUnscoped() {
-    Module module = new AbstractModule() {
-      protected void configure() {
-        bind(Style.class);
-        bind(SleeveLength.class);
-        bind(Shirt.class).in(Daily.class);
-      }
-    };
-
- ScopeChecker scopeChecker = new ScopeChecker(Guice.createInjector(scopesModule, module));
-    scopeChecker.check(Annually.class, Seasonally.class, Daily.class);
-  }
-
-  public void testUsedByUnscoped() {
-    Module module = new AbstractModule() {
-      protected void configure() {
-        bind(Style.class).in(Annually.class);
-        bind(SleeveLength.class);
-        bind(Shirt.class);
-      }
-    };
-
- ScopeChecker scopeChecker = new ScopeChecker(Guice.createInjector(scopesModule, module));
-    scopeChecker.check(Annually.class, Seasonally.class, Daily.class);
-  }
-
-  public void testDirectViolation() {
-    Module module = new AbstractModule() {
-      protected void configure() {
-        bind(Style.class).in(Annually.class);
-        bind(SleeveLength.class).in(Seasonally.class);
-        bind(Shirt.class).in(Annually.class);
-      }
-    };
-
- ScopeChecker scopeChecker = new ScopeChecker(Guice.createInjector(scopesModule, module));
-    try {
-      scopeChecker.check(Annually.class, Seasonally.class, Daily.class);
-      fail();
-    } catch (ConfigurationException expected) {
-      assertContains(expected.getMessage(),
- "1) Illegal scoped dependency: " + Shirt.class.getName() + " in @Annually", - " depends on " + SleeveLength.class.getName() + " in @Seasonally");
-    }
-  }
-
-  public void testDirectDependencyOnProvider() {
-    Module module = new AbstractModule() {
-      protected void configure() {
-        bind(Style.class).in(Daily.class);
-        bind(Pants.class).in(Seasonally.class);
-      }
-    };
-
- ScopeChecker scopeChecker = new ScopeChecker(Guice.createInjector(scopesModule, module));
-    scopeChecker.check(Annually.class, Seasonally.class, Daily.class);
-  }
-
-  public void testIndirectViolation() {
-    Module module = new AbstractModule() {
-      protected void configure() {
-        bind(Style.class).in(Seasonally.class);
-        bind(Shirt.class).in(Annually.class);
-      }
-    };
-
- ScopeChecker scopeChecker = new ScopeChecker(Guice.createInjector(scopesModule, module));
-    try {
-      scopeChecker.check(Annually.class, Seasonally.class, Daily.class);
-      fail();
-    } catch (ConfigurationException expected) {
-      assertContains(expected.getMessage(),
- "1) Illegal scoped dependency: " + Shirt.class.getName() + " in @Annually",
-          "  depends on " + SleeveLength.class.getName(),
-          "  depends on " + Style.class.getName() + " in @Seasonally");
-    }
-  }
-
-  public void testValidCircularDependency() {
-    Module module = new AbstractModule() {
-      protected void configure() {
-        bind(Chicken.class).in(Daily.class);
-        bind(Egg.class).in(Daily.class);
-      }
-    };
-
- ScopeChecker scopeChecker = new ScopeChecker(Guice.createInjector(scopesModule, module));
-    scopeChecker.check(Annually.class, Seasonally.class, Daily.class);
-  }
-
-  public void testInvalidCircularDependency() {
-    Module module = new AbstractModule() {
-      protected void configure() {
-        bind(Chicken.class).in(Seasonally.class);
-        bind(Egg.class).in(Daily.class);
-      }
-    };
-
- ScopeChecker scopeChecker = new ScopeChecker(Guice.createInjector(scopesModule, module));
-    try {
-      scopeChecker.check(Annually.class, Seasonally.class, Daily.class);
-      fail();
-    } catch (ConfigurationException expected) {
-      assertContains(expected.getMessage(),
- "1) Illegal scoped dependency: " + Chicken.class.getName() + " in @Seasonally",
-          "  depends on " + Egg.class.getName() + " in @Daily");
-    }
-  }
-
-  public void testCheckUnboundScope() {
-    Injector injector = Guice.createInjector();
-    ScopeChecker scopeChecker = new ScopeChecker(injector);
-
-    try {
-      scopeChecker.check(Singleton.class, Daily.class);
-      fail();
-    } catch (IllegalArgumentException expected) {
-      assertContains(expected.getMessage(),
-          "No scope binding for " + Daily.class);
-    }
-  }
-
-  static class Chicken {
-    @Inject Egg source;
-  }
-  static class Egg {
-    @Inject Chicken source;
-  }
-
-  private Scope newScope() {
-    return new Scope() {
-      public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
-        return unscoped;
-      }
-    };
-  }
-}

--
You received this message because you are subscribed to the Google Groups 
"google-guice-dev" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-guice-dev?hl=en.

Reply via email to