Skip to content

Commit

Permalink
Changes since 20090512
Browse files Browse the repository at this point in the history
New API: Multibinder.permitDuplicates() and MapBinder.permitDuplicates().

Fixed bug where a unmatched scoping annotation didn't cause a required failure. (reported by Dmitry Skavish)

Fixed bug where Provider.get() would break if used while scoping another provider.

Moved JNDI and JMX extensions out as external build targets.

Servlet: Making forward() pass the original request URI. (Andrew McLaughlin)

Servlet: SerlvetRequest and ServletResponse bindings are now chained. (Isaac Shum)

SPI: Scopes.isSingleton()

SPI: Injector.getAllBindings(). 

SPI: Replaced ModuleWriter with Element.applyTo(Binder). ModuleWriter still exists in Google3 for backwards compatibility, but it is now deprecated. The main difference between the two is the treatment of private modules.

SPI: bind(Foo.class).toConstructor(...). Useful for the Turkey bacon problem and for using Guice with third-party APIs.

SPI: change scoping of instance bindings (Andrew McLaughlin)



git-svn-id: https://google-guice.googlecode.com/svn/tags/snapshot20090706@1043 d779f126-a31b-0410-b53b-1d3aecad763e
  • Loading branch information
limpbizkit committed Jul 9, 2009
1 parent 37387e2 commit 3333657
Show file tree
Hide file tree
Showing 20 changed files with 902 additions and 110 deletions.
4 changes: 2 additions & 2 deletions common.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

<!-- can be overridden at the command line with -Dversion=
or in IDEA, in the ant properties dialog -->
<property name="version" value="2.0"/>
<property name="api.version" value="1.2"/>
<property name="version" value="snapshot"/>
<property name="api.version" value="1.3"/>

<target name="compile" description="Compile Java source.">
<mkdir dir="${build.dir}/classes"/>
Expand Down
31 changes: 29 additions & 2 deletions guice.ipr
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,24 @@
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
<ADDITIONAL_INDENT_OPTIONS fileType="groovy">
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
<option name="TAB_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
<ADDITIONAL_INDENT_OPTIONS fileType="gsp">
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
<option name="TAB_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
<ADDITIONAL_INDENT_OPTIONS fileType="java">
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
Expand Down Expand Up @@ -137,6 +155,15 @@
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
<ADDITIONAL_INDENT_OPTIONS fileType="sql">
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
<option name="TAB_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
</ADDITIONAL_INDENT_OPTIONS>
<ADDITIONAL_INDENT_OPTIONS fileType="xml">
<option name="INDENT_SIZE" value="4" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
Expand Down Expand Up @@ -513,7 +540,7 @@
</component>
<component name="ProjectFileVersion" converted="true" />
<component name="ProjectKey">
<option name="state" value="https://google-guice.googlecode.com/svn/trunk/guice.ipr" />
<option name="state" value="https://google-guice.googlecode.com/svn/tags/snapshot20090706/guice.ipr" />
</component>
<component name="ProjectModuleManager">
<modules>
Expand All @@ -530,7 +557,7 @@
<module fileurl="file://$PROJECT_DIR$/extensions/throwingproviders/throwingproviders.iml" filepath="$PROJECT_DIR$/extensions/throwingproviders/throwingproviders.iml" />
</modules>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="java version &quot;1.5.0_06&quot;" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/classes" />
</component>
<component name="ResourceManagerContainer">
Expand Down
10 changes: 10 additions & 0 deletions src/com/google/inject/AbstractModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,16 @@ protected void requestInjection(Object instance) {
binder.requestInjection(instance);
}

/**
* @deprecated use multiple calls to {@link #requestInjection}.
*/
@Deprecated
protected void requestInjection(Object... objects) {
for (Object o : objects) {
requestInjection(o);
}
}

/**
* @see Binder#requestStaticInjection(Class[])
*/
Expand Down
10 changes: 5 additions & 5 deletions src/com/google/inject/ConfigurationException.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,18 @@
* Thrown when a programming error such as a misplaced annotation, illegal binding, or unsupported
* scope is found. Clients should catch this exception, log it, and stop execution.
*
* <strong>Note:</strong> this class temporarily extends ProvisionException to ease migration.
*
* @author [email protected] (Jesse Wilson)
* @since 2.0
*/
public final class ConfigurationException extends RuntimeException {
public final class ConfigurationException extends ProvisionException {

private final ImmutableSet<Message> messages;
private Object partialValue = null;

/** Creates a ConfigurationException containing {@code messages}. */
public ConfigurationException(Iterable<Message> messages) {
this.messages = ImmutableSet.copyOf(messages);
initCause(Errors.getOnlyCause(this.messages));
super(messages);
}

/** Returns a copy of this configuration exception with the specified partial value. */
Expand Down Expand Up @@ -71,4 +71,4 @@ public <E> E getPartialValue() {
}

private static final long serialVersionUID = 0;
}
}
4 changes: 2 additions & 2 deletions src/com/google/inject/ProvisionException.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
* @author [email protected] (Jesse Wilson)
* @since 2.0
*/
public final class ProvisionException extends RuntimeException {
public class ProvisionException extends RuntimeException {

private final ImmutableSet<Message> messages;
protected final ImmutableSet<Message> messages;

/** Creates a ConfigurationException containing {@code messages}. */
public ProvisionException(Iterable<Message> messages) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/**
* Copyright (C) 2008 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.commands.intercepting;

import static com.google.inject.internal.Preconditions.checkArgument;
import static com.google.inject.internal.Preconditions.checkNotNull;
import com.google.inject.internal.Sets;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Binding;
import com.google.inject.Guice;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.ProvidedBy;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.binder.ScopedBindingBuilder;
import com.google.inject.internal.UniqueAnnotations;
import com.google.inject.name.Names;
import com.google.inject.spi.DefaultBindingTargetVisitor;
import com.google.inject.spi.Element;
import com.google.inject.spi.Elements;
import com.google.inject.spi.ModuleWriter;
import com.google.inject.spi.UntargettedBinding;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;

/**
* Builds an {@link Injector} that intercepts provision.
*
* <p>The injector contains an extra binding for {@code Set<Key>} annotated
* with the name "Interceptable". This bound set contains all intercepted keys.
*
* <h3>Limitations of the current implementation</h3>
*
* <p>All intercepted bindings must have binding targets - for example, a type
* that is bound to itself cannot be intercepted:
* <pre class="code">bind(MyServiceClass.class);</pre>
*
* <p>All intercepted bindings must be bound explicitly. Interception cannot
* be applied to implicit bindings, or bindings that depend on
* {@literal @}{@link ProvidedBy}, {@literal @}{@link ImplementedBy}
* annotations.
*
* <p><strong>Implementation note:</strong> To intercept provision, an
* additional, internal binding is created for each intercepted key. This is
* used to bind the original (non-intercepted) provisioning strategy, and an
* intercepting binding is created for the original key. This shouldn't have
* any side-effects on the behaviour of the injector, but may confuse tools
* that depend on {@link Injector#getBindings()} and similar methods.
*
* @deprecated copy this class into your own project, or use guiceberry
* @author [email protected] (Jesse Wilson)
* @author [email protected] (Jerome Mourits)
*/
@Deprecated
public final class InterceptingInjectorBuilder {

private static final Key<ProvisionInterceptor> INJECTION_INTERCEPTOR_KEY
= Key.get(ProvisionInterceptor.class);

private final Collection<Module> modules = new ArrayList<Module>();
private final Set<Key<?>> keysToIntercept = Sets.newHashSet();
private boolean tolerateUnmatchedInterceptions = false;

public InterceptingInjectorBuilder() {
// bind the keys to intercept
modules.add(new AbstractModule() {
protected void configure() {
bind(new TypeLiteral<Set<Key>>() {})
.annotatedWith(Names.named("Interceptable"))
.toInstance(Collections.<Key>unmodifiableSet(keysToIntercept));
}
});
}

public InterceptingInjectorBuilder install(Module... modules) {
this.modules.addAll(Arrays.asList(modules));
return this;
}

public InterceptingInjectorBuilder install(Collection<Module> modules) {
this.modules.addAll(modules);
return this;
}

public InterceptingInjectorBuilder intercept(Key<?>... keys) {
this.keysToIntercept.addAll(Arrays.asList(keys));
return this;
}

public InterceptingInjectorBuilder intercept(Collection<Key<?>> keys) {
checkArgument(!keys.contains(INJECTION_INTERCEPTOR_KEY),
"Cannot intercept the interceptor!");

keysToIntercept.addAll(keys);
return this;
}

public InterceptingInjectorBuilder intercept(Class<?>... classes) {
List<Key<?>> keysAsList = new ArrayList<Key<?>>(classes.length);
for (Class<?> clas : classes) {
keysAsList.add(Key.get(clas));
}

return intercept(keysAsList);
}

public InterceptingInjectorBuilder tolerateUnmatchedInterceptions() {
this.tolerateUnmatchedInterceptions = true;
return this;
}

public Injector build() {
// record commands from the modules
List<Element> elements = Elements.getElements(modules);

// rewrite the commands to insert interception
ModuleRewriter rewriter = new ModuleRewriter();
Module module = rewriter.create(elements);

// create and injector with the rewritten commands
Injector injector = Guice.createInjector(module);

// fail if any interceptions were missing
if (!tolerateUnmatchedInterceptions
&& !rewriter.keysIntercepted.equals(keysToIntercept)) {
Set<Key<?>> keysNotIntercepted = Sets.newHashSet();
keysNotIntercepted.addAll(keysToIntercept);
keysNotIntercepted.removeAll(rewriter.keysIntercepted);
throw new IllegalArgumentException("An explicit binding is required for "
+ "all intercepted keys, but was not found for " + keysNotIntercepted);
}

return injector;
}

/** Replays commands, inserting the InterceptingProvider where necessary. */
private class ModuleRewriter extends ModuleWriter {
private Set<Key<?>> keysIntercepted = Sets.newHashSet();

@Override public <T> void writeBind(Binder binder, Binding<T> binding) {
final Key<T> key = binding.getKey();

if (!keysToIntercept.contains(key)) {
super.writeBind(binder, binding);
return;
}

binding.acceptTargetVisitor(new DefaultBindingTargetVisitor<T, Void>() {
public Void visitUntargetted(UntargettedBinding<? extends T> untargettedBinding) {
throw new UnsupportedOperationException(
String.format("Cannot intercept bare binding of %s.", key));
}
});

Key<T> anonymousKey = Key.get(key.getTypeLiteral(), UniqueAnnotations.create());
binder.bind(key).toProvider(new InterceptingProvider<T>(key, anonymousKey));

ScopedBindingBuilder scopedBindingBuilder = bindKeyToTarget(binding, binder, anonymousKey);

// we scope the user's provider, not the interceptor. This is dangerous,
// but convenient. It means that although the user's provider will live
// in its proper scope, the intereptor gets invoked without a scope
applyScoping(binding, scopedBindingBuilder);

keysIntercepted.add(key);
}
}

/**
* Provide {@code T}, with a hook for an {@link ProvisionInterceptor}.
*/
private static class InterceptingProvider<T> implements Provider<T> {
private final Key<T> key;
private final Key<T> anonymousKey;
private Provider<ProvisionInterceptor> injectionInterceptorProvider;
private Provider<? extends T> delegateProvider;

public InterceptingProvider(Key<T> key, Key<T> anonymousKey) {
this.key = key;
this.anonymousKey = anonymousKey;
}

@Inject void initialize(Injector injector,
Provider<ProvisionInterceptor> injectionInterceptorProvider) {
this.injectionInterceptorProvider
= checkNotNull(injectionInterceptorProvider, "injectionInterceptorProvider");
this.delegateProvider
= checkNotNull(injector.getProvider(anonymousKey), "delegateProvider");
}

public T get() {
checkNotNull(injectionInterceptorProvider, "injectionInterceptorProvider");
checkNotNull(delegateProvider, "delegateProvider");
return injectionInterceptorProvider.get().intercept(key, delegateProvider);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Copyright (C) 2008 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.commands.intercepting;

import com.google.inject.Key;
import com.google.inject.Provider;

/**
* Intercepts object provision.
*
* @deprecated copy this class into your own project, or use guiceberry
* @author [email protected] (Jesse Wilson)
* @author [email protected] (Jerome Mourits)
*/
@Deprecated
public interface ProvisionInterceptor {
<T> T intercept(Key<T> key, Provider<? extends T> delegate);
}
Loading

0 comments on commit 3333657

Please sign in to comment.