Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save gissuebot/65062e1df7507ef31b3c to your computer and use it in GitHub Desktop.
Save gissuebot/65062e1df7507ef31b3c to your computer and use it in GitHub Desktop.
Migrated attachment for Guice issue 779, comment 0
From 04039d5d84d4cf162c2657564caec161a6ae0c9c Mon Sep 17 00:00:00 2001
From: Tavian Barnes <tavianator@tavianator.com>
Date: Wed, 6 Nov 2013 13:44:13 -0500
Subject: [PATCH 1/3] De-duplicate ProvisionListeners.
If a binding has two equivalent ProvisionListeners, only fire one of them.
---
.../inject/internal/ProvisionListenerStackCallback.java | 9 ++++++---
core/test/com/google/inject/ProvisionListenerTest.java | 13 +++++++++++++
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java b/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java
index a99c513..45347f0 100644
--- a/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java
+++ b/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java
@@ -16,14 +16,16 @@
package com.google.inject.internal;
+import java.util.List;
+import java.util.Set;
+
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
import com.google.inject.Binding;
import com.google.inject.ProvisionException;
import com.google.inject.spi.DependencyAndSource;
import com.google.inject.spi.ProvisionListener;
-import java.util.List;
-
/**
* Intercepts provisions with a stack of listeners.
*
@@ -49,7 +51,8 @@ final class ProvisionListenerStackCallback<T> {
if (listeners.isEmpty()) {
this.listeners = EMPTY_LISTENER;
} else {
- this.listeners = listeners.toArray(new ProvisionListener[listeners.size()]);
+ Set<ProvisionListener> deDuplicated = Sets.newLinkedHashSet(listeners);
+ this.listeners = deDuplicated.toArray(new ProvisionListener[deDuplicated.size()]);
}
}
diff --git a/core/test/com/google/inject/ProvisionListenerTest.java b/core/test/com/google/inject/ProvisionListenerTest.java
index 478949f..54a11fa 100644
--- a/core/test/com/google/inject/ProvisionListenerTest.java
+++ b/core/test/com/google/inject/ProvisionListenerTest.java
@@ -694,4 +694,17 @@ public class ProvisionListenerTest extends TestCase {
this.x = xProvider.get();
}
}
+
+ public void testDeDuplicateProvisionListeners() {
+ final Counter counter = new Counter();
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ bindListener(Matchers.any(), counter);
+ bindListener(Matchers.any(), counter);
+ }
+ });
+ injector.getInstance(Many.class);
+ assertEquals("ProvisionListener not de-duplicated", 1, counter.count);
+ }
}
--
1.8.4.2
From 9aca6281939c9b9036d1e3cd8f45f11fdd1dc69a Mon Sep 17 00:00:00 2001
From: Tavian Barnes <tavianator@tavianator.com>
Date: Wed, 6 Nov 2013 15:09:38 -0500
Subject: [PATCH 2/3] De-duplicate TypeListeners, MembersInjectors, and
InjectionListeners.
---
.../inject/internal/MembersInjectorImpl.java | 5 ++-
.../inject/internal/MembersInjectorStore.java | 21 ++++++----
core/test/com/google/inject/TypeListenerTest.java | 48 ++++++++++++++++++++++
3 files changed, 64 insertions(+), 10 deletions(-)
diff --git a/core/src/com/google/inject/internal/MembersInjectorImpl.java b/core/src/com/google/inject/internal/MembersInjectorImpl.java
index ba32d28..42ab050 100644
--- a/core/src/com/google/inject/internal/MembersInjectorImpl.java
+++ b/core/src/com/google/inject/internal/MembersInjectorImpl.java
@@ -45,8 +45,9 @@ final class MembersInjectorImpl<T> implements MembersInjector<T> {
this.injector = injector;
this.typeLiteral = typeLiteral;
this.memberInjectors = memberInjectors;
- this.userMembersInjectors = encounter.getMembersInjectors();
- this.injectionListeners = encounter.getInjectionListeners();
+ // De-duplicate members injectors and listeners
+ this.userMembersInjectors = ImmutableSet.copyOf(encounter.getMembersInjectors()).asList();
+ this.injectionListeners = ImmutableSet.copyOf(encounter.getInjectionListeners()).asList();
/*if[AOP]*/
this.addedAspects = encounter.getAspects();
/*end[AOP]*/
diff --git a/core/src/com/google/inject/internal/MembersInjectorStore.java b/core/src/com/google/inject/internal/MembersInjectorStore.java
index 7604d4c..37a7f1b 100644
--- a/core/src/com/google/inject/internal/MembersInjectorStore.java
+++ b/core/src/com/google/inject/internal/MembersInjectorStore.java
@@ -16,17 +16,19 @@
package com.google.inject.internal;
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Set;
+
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import com.google.inject.ConfigurationException;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.TypeListener;
import com.google.inject.spi.TypeListenerBinding;
-import java.lang.reflect.Field;
-import java.util.List;
-import java.util.Set;
-
/**
* Members injectors by type.
*
@@ -97,12 +99,15 @@ final class MembersInjectorStore {
errors.throwIfNewErrors(numErrorsBefore);
EncounterImpl<T> encounter = new EncounterImpl<T>(errors, injector.lookups);
- for (TypeListenerBinding typeListener : typeListenerBindings) {
- if (typeListener.getTypeMatcher().matches(type)) {
+ Set<TypeListener> typeListeners = Sets.newHashSet();
+ for (TypeListenerBinding binding : typeListenerBindings) {
+ TypeListener typeListener = binding.getListener();
+ if (!typeListeners.contains(typeListener) && binding.getTypeMatcher().matches(type)) {
+ typeListeners.add(typeListener);
try {
- typeListener.getListener().hear(type, encounter);
+ typeListener.hear(type, encounter);
} catch (RuntimeException e) {
- errors.errorNotifyingTypeListener(typeListener, type, e);
+ errors.errorNotifyingTypeListener(binding, type, e);
}
}
}
diff --git a/core/test/com/google/inject/TypeListenerTest.java b/core/test/com/google/inject/TypeListenerTest.java
index e4b5f63..a1468dd 100644
--- a/core/test/com/google/inject/TypeListenerTest.java
+++ b/core/test/com/google/inject/TypeListenerTest.java
@@ -38,6 +38,8 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import org.junit.experimental.runners.Enclosed;
+
/**
* @author jessewilson@google.com (Jesse Wilson)
*/
@@ -630,6 +632,52 @@ public class TypeListenerTest extends TestCase {
}
}
+ private static class CountingMembersInjector implements MembersInjector<D> {
+ @Override
+ public void injectMembers(D instance) {
+ ++instance.userInjected;
+ }
+ }
+
+ private static class CountingInjectionListener implements InjectionListener<D> {
+ @Override
+ public void afterInjection(D injectee) {
+ ++injectee.listenersNotified;
+ }
+ }
+
+ private static class DuplicatingTypeListener implements TypeListener {
+ int count = 0;
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Override
+ public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
+ ++count;
+
+ MembersInjector membersInjector = new CountingMembersInjector();
+ encounter.register(membersInjector);
+ encounter.register(membersInjector);
+
+ InjectionListener injectionListener = new CountingInjectionListener();
+ encounter.register(injectionListener);
+ encounter.register(injectionListener);
+ }
+ }
+
+ public void testDeDuplicateTypeListeners() {
+ final DuplicatingTypeListener typeListener = new DuplicatingTypeListener();
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ bindListener(any(), typeListener);
+ bindListener(only(new TypeLiteral<D>() { }), typeListener);
+ }
+ });
+ D d = injector.getInstance(D.class);
+ d.assertAllCounts(1);
+ assertEquals(1, typeListener.count);
+ }
+
// TODO: recursively accessing a lookup should fail
static class A {
--
1.8.4.2
From 89c80b9285f05fcd80b9c130c854cfaf3827ddbe Mon Sep 17 00:00:00 2001
From: Tavian Barnes <tavianator@tavianator.com>
Date: Wed, 6 Nov 2013 15:39:13 -0500
Subject: [PATCH 3/3] De-duplicate MethodInterceptors.
---
core/src/com/google/inject/internal/ProxyFactory.java | 6 ++++--
core/test/com/google/inject/MethodInterceptionTest.java | 14 ++++++++++++++
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/core/src/com/google/inject/internal/ProxyFactory.java b/core/src/com/google/inject/internal/ProxyFactory.java
index 0b39f76..07d0045 100644
--- a/core/src/com/google/inject/internal/ProxyFactory.java
+++ b/core/src/com/google/inject/internal/ProxyFactory.java
@@ -20,6 +20,7 @@ import static com.google.inject.internal.BytecodeGen.newFastClass;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.spi.InjectionPoint;
@@ -135,8 +136,9 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> {
interceptorsMapBuilder = ImmutableMap.builder();
}
- interceptorsMapBuilder.put(pair.method, ImmutableList.copyOf(pair.interceptors));
- callbacks[i] = new InterceptorStackCallback(pair.method, pair.interceptors);
+ ImmutableList<MethodInterceptor> deDuplicated = ImmutableSet.copyOf(pair.interceptors).asList();
+ interceptorsMapBuilder.put(pair.method, deDuplicated);
+ callbacks[i] = new InterceptorStackCallback(pair.method, deDuplicated);
}
interceptors = interceptorsMapBuilder != null
diff --git a/core/test/com/google/inject/MethodInterceptionTest.java b/core/test/com/google/inject/MethodInterceptionTest.java
index 6fe8b4e..e3bb97e 100644
--- a/core/test/com/google/inject/MethodInterceptionTest.java
+++ b/core/test/com/google/inject/MethodInterceptionTest.java
@@ -313,4 +313,18 @@ public class MethodInterceptionTest extends TestCase {
}
}
+ public void testDeDuplicateInterceptors() throws Exception {
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ CountingInterceptor interceptor = new CountingInterceptor();
+ bindInterceptor(Matchers.any(), Matchers.any(), interceptor);
+ bindInterceptor(Matchers.any(), Matchers.any(), interceptor);
+ }
+ });
+
+ Interceptable interceptable = injector.getInstance(Interceptable.class);
+ interceptable.foo();
+ assertEquals(1, count.get());
+ }
}
--
1.8.4.2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment