aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrazyboblee <crazyboblee@d779f126-a31b-0410-b53b-1d3aecad763e>2007-02-20 19:23:10 +0000
committercrazyboblee <crazyboblee@d779f126-a31b-0410-b53b-1d3aecad763e>2007-02-20 19:23:10 +0000
commit9d573ed1c5c3f2f5d72195e013cafd545ffe38fc (patch)
treefc42efb0149ebc81a57286fd8b3087273d833637
parente5073a2cc66bf1340ed76f30e6ac19cf2d0cdc3b (diff)
downloadguice-9d573ed1c5c3f2f5d72195e013cafd545ffe38fc.tar.gz
Hid BinderImpl. Redesigned SoureProvider API.
git-svn-id: https://google-guice.googlecode.com/svn/trunk@195 d779f126-a31b-0410-b53b-1d3aecad763e
-rw-r--r--build.properties2
-rw-r--r--src/com/google/inject/AbstractModule.java31
-rw-r--r--src/com/google/inject/BinderImpl.java30
-rw-r--r--src/com/google/inject/Container.java2
-rw-r--r--src/com/google/inject/Module.java4
-rw-r--r--src/com/google/inject/name/Names.java65
-rw-r--r--src/com/google/inject/package-info.java2
-rw-r--r--src/com/google/inject/spi/DefaultSourceProvider.java62
-rw-r--r--src/com/google/inject/spi/SourceConsumer.java62
-rw-r--r--src/com/google/inject/spi/SourceProviders.java110
-rw-r--r--test/com/google/inject/servlet/ServletTest.java15
11 files changed, 193 insertions, 192 deletions
diff --git a/build.properties b/build.properties
index f1cfe8b1..e6a1b113 100644
--- a/build.properties
+++ b/build.properties
@@ -5,4 +5,4 @@ test.dir=test
build.dir=build
javadoc.packagenames=com.google.inject,com.google.inject.spi,\
com.google.inject.matcher,com.google.inject.servlet,com.google.inject.name,\
- com.google.inject.tools.jmx
+ com.google.inject.tools.jmx,com.google.inject.binder
diff --git a/src/com/google/inject/AbstractModule.java b/src/com/google/inject/AbstractModule.java
index 24b6cce7..289fb3d6 100644
--- a/src/com/google/inject/AbstractModule.java
+++ b/src/com/google/inject/AbstractModule.java
@@ -21,6 +21,7 @@ import com.google.inject.binder.ConstantBindingBuilder;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.matcher.Matcher;
import com.google.inject.util.Objects;
+import com.google.inject.spi.SourceProviders;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor;
@@ -29,7 +30,7 @@ import org.aopalliance.intercept.MethodInterceptor;
* A support class for {@link Module Modules} which reduces repetition and
* results in a more readable configuration. Simply extends this class,
* implement {@link #configure()}, and call the inherited methods which mirror
- * those found in {@link BinderImpl}. For example:
+ * those found in {@link Binder}. For example:
*
* <pre>
* import static com.google.inject.Names.named;
@@ -48,9 +49,13 @@ import org.aopalliance.intercept.MethodInterceptor;
*/
public abstract class AbstractModule implements Module {
+ static {
+ SourceProviders.skip(AbstractModule.class);
+ }
+
Binder builder;
- public final synchronized void configure(BinderImpl builder) {
+ public final synchronized void configure(Binder builder) {
try {
if (this.builder != null) {
throw new IllegalStateException("Re-entry is not allowed.");
@@ -66,7 +71,7 @@ public abstract class AbstractModule implements Module {
}
/**
- * Configures a {@link BinderImpl} via the exposed methods.
+ * Configures a {@link Binder} via the exposed methods.
*/
protected abstract void configure();
@@ -78,7 +83,7 @@ public abstract class AbstractModule implements Module {
}
/**
- * @see BinderImpl#bindScope(Class, Scope)
+ * @see Binder#bindScope(Class, Scope)
*/
protected void scope(Class<? extends Annotation> scopeAnnotation,
Scope scope) {
@@ -86,14 +91,14 @@ public abstract class AbstractModule implements Module {
}
/**
- * @see BinderImpl#bind(Key)
+ * @see Binder#bind(Key)
*/
protected <T> BindingBuilder<T> bind(Key<T> key) {
return builder.bind(key);
}
/**
- * @see BinderImpl#bind(TypeLiteral)
+ * @see Binder#bind(TypeLiteral)
*/
protected <T> BindingBuilder<T> bind(
TypeLiteral<T> typeLiteral) {
@@ -101,21 +106,21 @@ public abstract class AbstractModule implements Module {
}
/**
- * @see BinderImpl#bind(Class)
+ * @see Binder#bind(Class)
*/
protected <T> BindingBuilder<T> bind(Class<T> clazz) {
return builder.bind(clazz);
}
/**
- * @see BinderImpl#link(Key)
+ * @see Binder#link(Key)
*/
protected <T> LinkedBindingBuilder<T> link(Key<T> key) {
return builder.link(key);
}
/**
- * @see BinderImpl#bindConstant(Class)
+ * @see Binder#bindConstant(Class)
*/
protected ConstantBindingBuilder bindConstant(
Class<? extends Annotation> annotationType) {
@@ -123,7 +128,7 @@ public abstract class AbstractModule implements Module {
}
/**
- * @see BinderImpl#bindConstant(java.lang.annotation.Annotation)
+ * @see Binder#bindConstant(java.lang.annotation.Annotation)
*/
protected ConstantBindingBuilder bindConstant(
Annotation annotation) {
@@ -131,21 +136,21 @@ public abstract class AbstractModule implements Module {
}
/**
- * @see BinderImpl#install(Module)
+ * @see Binder#install(Module)
*/
protected void install(Module module) {
builder.install(module);
}
/**
- * @see BinderImpl#requestStaticInjection(Class[])
+ * @see Binder#requestStaticInjection(Class[])
*/
protected void requestStaticInjection(Class<?>... types) {
builder.requestStaticInjection(types);
}
/**
- * @see BinderImpl#bindInterceptor(com.google.inject.matcher.Matcher,
+ * @see Binder#bindInterceptor(com.google.inject.matcher.Matcher,
* com.google.inject.matcher.Matcher,
* org.aopalliance.intercept.MethodInterceptor[])
*/
diff --git a/src/com/google/inject/BinderImpl.java b/src/com/google/inject/BinderImpl.java
index 1f3ea6c7..c6ec0ec3 100644
--- a/src/com/google/inject/BinderImpl.java
+++ b/src/com/google/inject/BinderImpl.java
@@ -21,7 +21,7 @@ import com.google.inject.Key.AnnotationStrategy;
import static com.google.inject.Scopes.CONTAINER;
import com.google.inject.matcher.Matcher;
import com.google.inject.spi.Message;
-import com.google.inject.spi.SourceConsumer;
+import com.google.inject.spi.SourceProviders;
import static com.google.inject.util.Objects.nonNull;
import com.google.inject.util.Stopwatch;
import java.lang.annotation.Annotation;
@@ -50,7 +50,11 @@ import org.aopalliance.intercept.MethodInterceptor;
*
* @author crazybob@google.com (Bob Lee)
*/
-public final class BinderImpl extends SourceConsumer implements Binder {
+class BinderImpl implements Binder {
+
+ static {
+ SourceProviders.skip(BinderImpl.class);
+ }
private static final Logger logger
= Logger.getLogger(BinderImpl.class.getName());
@@ -141,13 +145,11 @@ public final class BinderImpl extends SourceConsumer implements Binder {
public void bindInterceptor(Matcher<? super Class<?>> classMatcher,
Matcher<? super Method> methodMatcher, MethodInterceptor... interceptors) {
- ensureNotCreated();
proxyFactoryBuilder.intercept(classMatcher, methodMatcher, interceptors);
}
public void bindScope(Class<? extends Annotation> annotationType,
Scope scope) {
- ensureNotCreated();
Scope existing = scopes.get(nonNull(annotationType, "annotation type"));
if (existing != null) {
addError(source(), ErrorMessages.DUPLICATE_SCOPES, existing,
@@ -159,7 +161,6 @@ public final class BinderImpl extends SourceConsumer implements Binder {
}
public <T> BindingBuilderImpl<T> bind(Key<T> key) {
- ensureNotCreated();
BindingBuilderImpl<T> builder = new BindingBuilderImpl<T>(this, key, source());
bindingBuilders.add(builder);
return builder;
@@ -174,7 +175,6 @@ public final class BinderImpl extends SourceConsumer implements Binder {
}
public <T> LinkedBindingBuilderImpl<T> link(Key<T> key) {
- ensureNotCreated();
LinkedBindingBuilderImpl<T> builder =
new LinkedBindingBuilderImpl<T>(this, key).from(source());
linkedBindingBuilders.add(builder);
@@ -192,13 +192,11 @@ public final class BinderImpl extends SourceConsumer implements Binder {
}
public ConstantBindingBuilderImpl bindConstant(Annotation annotation) {
- ensureNotCreated();
return bind(source(), Key.strategyFor(annotation));
}
public ConstantBindingBuilderImpl bindConstant(
Class<? extends Annotation> annotationType) {
- ensureNotCreated();
return bind(source(), Key.strategyFor(annotationType));
}
@@ -243,12 +241,10 @@ public final class BinderImpl extends SourceConsumer implements Binder {
* expectation is that the application will log this exception and exit.
* @throws IllegalStateException if called more than once
*/
- public synchronized Container createContainer()
- throws CreationException {
+ Container createContainer() throws CreationException {
stopwatch.resetAndLog(logger, "Configuration");
// Create the container.
- ensureNotCreated();
Map<Key<?>, Binding<?>> bindings = new HashMap<Key<?>, Binding<?>>();
container = new ContainerImpl(
proxyFactoryBuilder.create(), bindings, scopes);
@@ -409,16 +405,10 @@ public final class BinderImpl extends SourceConsumer implements Binder {
}
/**
- * Currently we only support creating one Container instance per builder. If
- * we want to support creating more than one container per builder, we should
- * move to a "factory factory" model where we create a factory instance per
- * Container. Right now, one factory instance would be shared across all the
- * containers, which means container-scoped objects would be shared, etc.
+ * Gets the current source.
*/
- private void ensureNotCreated() {
- if (container != null) {
- throw new IllegalStateException("Container already created.");
- }
+ Object source() {
+ return SourceProviders.defaultSource();
}
ErrorHandler configurationErrorHandler = new AbstractErrorHandler() {
diff --git a/src/com/google/inject/Container.java b/src/com/google/inject/Container.java
index 8f077b2f..96e9ca41 100644
--- a/src/com/google/inject/Container.java
+++ b/src/com/google/inject/Container.java
@@ -30,7 +30,7 @@ import java.util.Map;
* {@code int}, the container will look for a binding to {@code Integer}.
*
* @author crazybob@google.com (Bob Lee)
- * @see BinderImpl
+ * @see Binder
*/
public interface Container {
diff --git a/src/com/google/inject/Module.java b/src/com/google/inject/Module.java
index e1919108..12c0382f 100644
--- a/src/com/google/inject/Module.java
+++ b/src/com/google/inject/Module.java
@@ -18,7 +18,7 @@ package com.google.inject;
/**
* A module contributes a set of configurations, typically interface bindings,
- * to a {@link BinderImpl} which will later create a {@link Container}.
+ * to a {@link Binder} which will later be used to create a {@link Container}.
* Implementing this interface is the standard means for encapsulating and
* reusing configuration logic. Your Module classes can use a more streamlined
* syntax by extending {@link AbstractModule} rather than implementing this
@@ -33,5 +33,5 @@ public interface Module {
* that the resulting {@link Container} will include this module properly set
* up.
*/
- void configure(BinderImpl builder);
+ void configure(Binder binder);
}
diff --git a/src/com/google/inject/name/Names.java b/src/com/google/inject/name/Names.java
index 28ed13a2..ea2f8431 100644
--- a/src/com/google/inject/name/Names.java
+++ b/src/com/google/inject/name/Names.java
@@ -17,9 +17,8 @@
package com.google.inject.name;
import com.google.inject.Binder;
-import com.google.inject.BinderImpl;
import com.google.inject.Key;
-import com.google.inject.spi.DefaultSourceProvider;
+import com.google.inject.spi.SourceProviders;
import com.google.inject.spi.SourceProvider;
import java.util.Map;
import java.util.Properties;
@@ -33,6 +32,10 @@ public class Names {
private Names() {}
+ static {
+ SourceProviders.skip(Names.class);
+ }
+
/**
* Creates a {@link Named} annotation with {@code name} as the value.
*/
@@ -43,35 +46,49 @@ public class Names {
/**
* Creates a constant binding to {@code @Named(key)} for each property.
*/
- public static void bindProperties(BinderImpl binder,
- Map<String, String> properties) {
- skipNames(binder);
- for (Map.Entry<String, String> entry : properties.entrySet()) {
- String key = entry.getKey();
- String value = entry.getValue();
- ((Binder) binder).bind(
- Key.get(String.class, new NamedImpl(key))).to(value);
- }
+ public static void bindProperties(final Binder binder,
+ final Map<String, String> properties) {
+ SourceProviders.withDefault(
+ new SimpleSourceProvider(SourceProviders.defaultSource()),
+ new Runnable() {
+ public void run() {
+ for (Map.Entry<String, String> entry : properties.entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ binder.bind(Key.get(String.class, new NamedImpl(key))).to(value);
+ }
+ }
+ });
}
/**
* Creates a constant binding to {@code @Named(key)} for each property.
*/
- public static void bindProperties(BinderImpl binder,
- Properties properties) {
- skipNames(binder);
- for (Map.Entry<Object, Object> entry : properties.entrySet()) {
- String key = (String) entry.getKey();
- String value = (String) entry.getValue();
- ((Binder) binder).bind(
- Key.get(String.class, new NamedImpl(key))).to(value);
- }
+ public static void bindProperties(final Binder binder,
+ final Properties properties) {
+ SourceProviders.withDefault(
+ new SimpleSourceProvider(SourceProviders.defaultSource()),
+ new Runnable() {
+ public void run() {
+ for (Map.Entry<Object, Object> entry : properties.entrySet()) {
+ String key = (String) entry.getKey();
+ String value = (String) entry.getValue();
+ binder.bind(Key.get(String.class, new NamedImpl(key))).to(value);
+ }
+ }
+ });
}
- private static void skipNames(BinderImpl builder) {
- SourceProvider sourceProvider = builder.getSourceProvider();
- if (sourceProvider instanceof DefaultSourceProvider) {
- ((DefaultSourceProvider) sourceProvider).skip(Names.class);
+ static class SimpleSourceProvider implements SourceProvider {
+
+ final Object source;
+
+ SimpleSourceProvider(Object source) {
+ this.source = source;
+ }
+
+ public Object source() {
+ return source;
}
}
}
diff --git a/src/com/google/inject/package-info.java b/src/com/google/inject/package-info.java
index 4bca06f5..ebc78e57 100644
--- a/src/com/google/inject/package-info.java
+++ b/src/com/google/inject/package-info.java
@@ -34,7 +34,7 @@
* instructions for how Guice should handle injection -- for a particular
* set of interfaces.
*
- * <dt>{@link BinderImpl}
+ * <dt>{@link com.google.inject.Binder}
* <dd>The object that Guice passes into your {@link com.google.inject.Module}
* to collect these bindings.
*
diff --git a/src/com/google/inject/spi/DefaultSourceProvider.java b/src/com/google/inject/spi/DefaultSourceProvider.java
deleted file mode 100644
index f6f8d7e6..00000000
--- a/src/com/google/inject/spi/DefaultSourceProvider.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * Copyright (C) 2006 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.spi;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.BinderImpl;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * A source provider which returns {@code Binder}'s caller's {@code
- * StackTraceElement}.
- *
- * @author crazybob@google.com (Bob Lee)
- */
-public class DefaultSourceProvider implements SourceProvider {
-
- final Set<String> skippedClassNames = new HashSet<String>(Arrays.asList(
- BinderImpl.class.getName(),
- AbstractModule.class.getName(),
- DefaultSourceProvider.class.getName(),
- SourceConsumer.class.getName()
- ));
-
- /**
- * Instructs the provider to skip the given class in the stack trace when
- * determining the source. Use this to keep the container builder from
- * logging utility methods as the sources of bindings (i.e. it will skip to
- * the utility methods' callers instead).
- *
- * <p>Skipping only takes place after this method is called.
- */
- public void skip(Class<?> clazz) {
- skippedClassNames.add(clazz.getName());
- }
-
- public Object source() {
- // Search up the stack until we find a class outside of this one.
- for (final StackTraceElement element : new Throwable().getStackTrace()) {
- String className = element.getClassName();
- if (!skippedClassNames.contains(className)) {
- return element;
- }
- }
- throw new AssertionError();
- }
-}
diff --git a/src/com/google/inject/spi/SourceConsumer.java b/src/com/google/inject/spi/SourceConsumer.java
deleted file mode 100644
index 90d02838..00000000
--- a/src/com/google/inject/spi/SourceConsumer.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * Copyright (C) 2006 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.spi;
-
-/**
- * Support for classes which use source objects.
- *
- * @author crazybob@google.com (Bob Lee)
- */
-public class SourceConsumer {
-
- SourceProvider sourceProvider = new DefaultSourceProvider();
-
- /**
- * Returns the current source.
- */
- protected Object source() {
- return sourceProvider.source();
- }
-
- /**
- * Gets the current source provider.
- */
- public SourceProvider getSourceProvider() {
- return sourceProvider;
- }
-
- /**
- * Sets the current source provider.
- */
- public void setSourceProvider(SourceProvider sourceProvider) {
- this.sourceProvider = sourceProvider;
- }
-
- /**
- * Sets the source provider, runs the given command, and restores the
- * previous source provider.
- */
- public void withSourceProvider(SourceProvider sourceProvider, Runnable r) {
- SourceProvider previous = this.sourceProvider;
- try {
- this.sourceProvider = sourceProvider;
- r.run();
- } finally {
- this.sourceProvider = previous;
- }
- }
-}
diff --git a/src/com/google/inject/spi/SourceProviders.java b/src/com/google/inject/spi/SourceProviders.java
new file mode 100644
index 00000000..e52e7d8b
--- /dev/null
+++ b/src/com/google/inject/spi/SourceProviders.java
@@ -0,0 +1,110 @@
+/**
+ * Copyright (C) 2006 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.spi;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Collections;
+
+/**
+ * Provides access to the default {@link SourceProvider} implementation and
+ * common controls for certain implementations.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ */
+public class SourceProviders {
+
+ private SourceProviders() {}
+
+ static final SourceProvider DEFAULT_INSTANCE = new StacktraceSourceProvider();
+
+ static Set<String> skippedClassNames = Collections.emptySet();
+
+ static {
+ skip(SourceProviders.class);
+ skip(StacktraceSourceProvider.class);
+ }
+
+ /**
+ * Instructs stacktrace-based providers to skip the given class in the stack
+ * trace when
+ * determining the source. Use this to keep the container builder from
+ * logging utility methods as the sources of bindings (i.e. it will skip to
+ * the utility methods' callers instead).
+ *
+ * <p>Skipping only takes place after this method is called.
+ */
+ public synchronized static void skip(Class<?> clazz) {
+ Set<String> copy = new HashSet<String>();
+ copy.addAll(skippedClassNames);
+ copy.add(clazz.getName());
+ skippedClassNames = Collections.unmodifiableSet(copy);
+ }
+
+ /**
+ * Gets the set of class names which should be skipped by stacktrace-based
+ * providers.
+ */
+ public synchronized static Set<String> getSkippedClassNames() {
+ return skippedClassNames;
+ }
+
+ static ThreadLocal<SourceProvider[]> localSourceProvider =
+ new ThreadLocal<SourceProvider[]>() {
+ protected SourceProvider[] initialValue() {
+ return new SourceProvider[] { DEFAULT_INSTANCE };
+ }
+ };
+
+ /**
+ * Returns the current source obtained from the default provider.
+ */
+ public static Object defaultSource() {
+ return localSourceProvider.get()[0].source();
+ }
+
+ /**
+ * Sets the default source provider, runs the given command, and then
+ * restores the previous default source provider.
+ */
+ public static void withDefault(
+ SourceProvider sourceProvider, Runnable r) {
+ // We use a holder so we perform only 1 thread local access instead of 3.
+ SourceProvider[] holder = localSourceProvider.get();
+ SourceProvider previous = holder[0];
+ try {
+ holder[0] = sourceProvider;
+ r.run();
+ } finally {
+ holder[0] = previous;
+ }
+ }
+
+ static class StacktraceSourceProvider implements SourceProvider {
+ public Object source() {
+ // Search up the stack until we find a class outside of this one.
+ Set<String> skippedClassNames = getSkippedClassNames();
+ for (final StackTraceElement element : new Throwable().getStackTrace()) {
+ String className = element.getClassName();
+ if (!skippedClassNames.contains(className)) {
+ return element;
+ }
+ }
+ throw new AssertionError();
+ }
+ }
+}
diff --git a/test/com/google/inject/servlet/ServletTest.java b/test/com/google/inject/servlet/ServletTest.java
index 7d9a72fc..ec12ea6a 100644
--- a/test/com/google/inject/servlet/ServletTest.java
+++ b/test/com/google/inject/servlet/ServletTest.java
@@ -16,10 +16,11 @@
package com.google.inject.servlet;
-import com.google.inject.BinderImpl;
import com.google.inject.Container;
import com.google.inject.CreationException;
import com.google.inject.Key;
+import com.google.inject.Guice;
+import com.google.inject.AbstractModule;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
@@ -170,11 +171,13 @@ public class ServletTest extends TestCase {
}
private Container createContainer() throws CreationException {
- BinderImpl builder = new BinderImpl();
- builder.install(new ServletModule());
- builder.bind(InSession.class);
- builder.bind(InRequest.class);
- return builder.createContainer();
+ return Guice.createContainer(new AbstractModule() {
+ protected void configure() {
+ install(new ServletModule());
+ bind(InSession.class);
+ bind(InRequest.class);
+ }
+ });
}
@SessionScoped