[picocontainer-scm] [5785] java/2.x/trunk/pico/container/src/test/org/picocontainer/injectors: Fix a subtle thread local bug

paul-yCVjj/[email protected] Sun, 1 May 2011 19:36:34 -0500 (CDT)
Newsgroups gmane.comp.java.picocontainer.cvs
Message-ID <[email protected]>
Revision 5785
Author paul
Date 2011-05-01 19:36:34 -0500 (Sun, 01 May 2011)

Log Message

Fix a subtle thread local bug

Modified Paths

- java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/AbstractInjector.java

- java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/ConstructorInjector.java

- java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/IterativeInjector.java

- java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/MethodInjector.java

- java/2.x/trunk/pico/container/src/test/org/picocontainer/behaviors/ThreadCachingTestCase.java

- java/2.x/trunk/pico/container/src/test/org/picocontainer/injectors/ThreadLocalCyclicDependencyGuardTestCase.java

Diff

Modified: java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/AbstractInjector.java (5784 => 5785)

--- java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/AbstractInjector.java 2011-05-01 16:39:44 UTC (rev 5784)
+++ java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/AbstractInjector.java 2011-05-02 00:36:34 UTC (rev 5785)
@@ -248,25 +248,28 @@
*
* @return a value, if the functionality result in an expression,
* otherwise just return <code>null</code>
+ * @param instance
*/
- public abstract T run();
+ public abstract T run(Object instance);

/**
* Call the observing function. The provided guard will hold the {@link Boolean} value.
* If the guard is already <code>Boolean.TRUE</code> a {@link CyclicDependencyException}
* will be thrown.
*
+ *
* @param stackFrame the current stack frame
+ * @param instance
* @return the result of the <code>run</code> method
*/
- public final T observe(final Class<?> stackFrame) {
+ public final T observe(final Class<?> stackFrame, final Object instance) {
if (Boolean.TRUE.equals(get())) {
throw new CyclicDependencyException(stackFrame);
}
T result = null;
try {
set(Boolean.TRUE);
- result = run();
+ result = run(instance);
} catch (final CyclicDependencyException e) {
e.push(stackFrame);
throw e;

Modified: java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/ConstructorInjector.java (5784 => 5785)

--- java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/ConstructorInjector.java 2011-05-01 16:39:44 UTC (rev 5784)
+++ java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/ConstructorInjector.java 2011-05-02 00:36:34 UTC (rev 5785)
@@ -317,7 +317,7 @@
instantiationGuard = new ThreadLocalCyclicDependencyGuard<T>() {
@Override
@SuppressWarnings("synthetic-access")
- public T run() {
+ public T run(Object instance) {
CtorAndAdapters<T> ctorAndAdapters = getGreediestSatisfiableConstructor(guardedContainer, getComponentImplementation());
ComponentMonitor componentMonitor = currentMonitor();
Constructor<T> ctor = ctorAndAdapters.getConstructor();
@@ -351,7 +351,7 @@
};
}
instantiationGuard.setGuardedContainer(container);
- T inst = instantiationGuard.observe(getComponentImplementation());
+ T inst = instantiationGuard.observe(getComponentImplementation(), null);
decorate(inst, container);
return inst;
}
@@ -400,7 +400,7 @@
if (verifyingGuard == null) {
verifyingGuard = new ThreadLocalCyclicDependencyGuard() {
@Override
- public Object run() {
+ public Object run(Object instance) {
final Constructor constructor = getGreediestSatisfiableConstructor(guardedContainer).getConstructor();
final Class[] parameterTypes = constructor.getParameterTypes();
final Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
@@ -414,7 +414,7 @@
};
}
verifyingGuard.setGuardedContainer(container);
- verifyingGuard.observe(getComponentImplementation());
+ verifyingGuard.observe(getComponentImplementation(), null);
}

@Override

Modified: java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/IterativeInjector.java (5784 => 5785)

--- java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/IterativeInjector.java 2011-05-01 16:39:44 UTC (rev 5784)
+++ java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/IterativeInjector.java 2011-05-02 00:36:34 UTC (rev 5785)
@@ -145,7 +145,7 @@
final Constructor constructor = getConstructor();
if (instantiationGuard == null) {
instantiationGuard = new ThreadLocalCyclicDependencyGuard() {
- public Object run() {
+ public Object run(Object instance) {
final Parameter[] matchingParameters = getMatchingParameterListForSetters(guardedContainer);
Object componentInstance = makeInstance(container, constructor, currentMonitor());
return decorateComponentInstance(matchingParameters, currentMonitor(), componentInstance, container, guardedContainer);
@@ -153,7 +153,7 @@
};
}
instantiationGuard.setGuardedContainer(container);
- return (T) instantiationGuard.observe(getComponentImplementation());
+ return (T) instantiationGuard.observe(getComponentImplementation(), null);
}

private Object decorateComponentInstance(Parameter[] matchingParameters, ComponentMonitor componentMonitor, Object componentInstance, PicoContainer container, PicoContainer guardedContainer) {
@@ -221,14 +221,14 @@
public Object decorateComponentInstance(final PicoContainer container, Type into, final T instance) {
if (instantiationGuard == null) {
instantiationGuard = new ThreadLocalCyclicDependencyGuard() {
- public Object run() {
+ public Object run(Object inst) {
final Parameter[] matchingParameters = getMatchingParameterListForSetters(guardedContainer);
- return decorateComponentInstance(matchingParameters, currentMonitor(), instance, container, guardedContainer);
+ return decorateComponentInstance(matchingParameters, currentMonitor(), inst, container, guardedContainer);
}
};
}
instantiationGuard.setGuardedContainer(container);
- return instantiationGuard.observe(getComponentImplementation());
+ return instantiationGuard.observe(getComponentImplementation(), instance);
}

protected abstract Object injectIntoMember(AccessibleObject member, Object componentInstance, Object toInject) throws IllegalAccessException, InvocationTargetException;
@@ -237,7 +237,7 @@
public void verify(final PicoContainer container) throws PicoCompositionException {
if (verifyingGuard == null) {
verifyingGuard = new ThreadLocalCyclicDependencyGuard() {
- public Object run() {
+ public Object run(Object instance) {
final Parameter[] currentParameters = getMatchingParameterListForSetters(guardedContainer);
for (int i = 0; i < currentParameters.length; i++) {
currentParameters[i].verify(container, IterativeInjector.this, injectionTypes[i],
@@ -248,7 +248,7 @@
};
}
verifyingGuard.setGuardedContainer(container);
- verifyingGuard.observe(getComponentImplementation());
+ verifyingGuard.observe(getComponentImplementation(), null);
}

protected void initializeInjectionMembersAndTypeLists() {

Modified: java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/MethodInjector.java (5784 => 5785)

--- java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/MethodInjector.java 2011-05-01 16:39:44 UTC (rev 5784)
+++ java/2.x/trunk/pico/container/src/java/org/picocontainer/injectors/MethodInjector.java 2011-05-02 00:36:34 UTC (rev 5785)
@@ -16,7 +16,6 @@
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import org.picocontainer.ComponentMonitor;
-import org.picocontainer.LifecycleStrategy;
import org.picocontainer.Parameter;
import org.picocontainer.PicoCompositionException;
import org.picocontainer.PicoContainer;
@@ -80,7 +79,7 @@
instantiationGuard = new ThreadLocalCyclicDependencyGuard() {
@Override
@SuppressWarnings("synthetic-access")
- public Object run() {
+ public Object run(Object instance) {
Method method = getInjectorMethod();
T inst = null;
ComponentMonitor componentMonitor = currentMonitor();
@@ -106,7 +105,7 @@
};
}
instantiationGuard.setGuardedContainer(container);
- return (T) instantiationGuard.observe(getComponentImplementation());
+ return (T) instantiationGuard.observe(getComponentImplementation(), null);
}

protected Object[] getMemberArguments(PicoContainer container, final Method method) {
@@ -119,18 +118,18 @@
instantiationGuard = new ThreadLocalCyclicDependencyGuard() {
@Override
@SuppressWarnings("synthetic-access")
- public Object run() {
+ public Object run(Object inst) {
Method method = getInjectorMethod();
- if (method.getDeclaringClass().isAssignableFrom(instance.getClass())) {
+ if (method.getDeclaringClass().isAssignableFrom(inst.getClass())) {
Object[] methodParameters = getMemberArguments(guardedContainer, method);
- return invokeMethod(method, methodParameters, instance, container);
+ return invokeMethod(method, methodParameters, (T) inst, container);
}
return null;
}
};
}
instantiationGuard.setGuardedContainer(container);
- Object o = instantiationGuard.observe(getComponentImplementation());
+ Object o = instantiationGuard.observe(getComponentImplementation(), instance);
return o;
}

@@ -162,7 +161,7 @@
if (verifyingGuard == null) {
verifyingGuard = new ThreadLocalCyclicDependencyGuard() {
@Override
- public Object run() {
+ public Object run(Object instance) {
final Method method = getInjectorMethod();
final Class[] parameterTypes = method.getParameterTypes();
final Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
@@ -176,7 +175,7 @@
};
}
verifyingGuard.setGuardedContainer(container);
- verifyingGuard.observe(getComponentImplementation());
+ verifyingGuard.observe(getComponentImplementation(), null);
}

@Override

Modified: java/2.x/trunk/pico/container/src/test/org/picocontainer/behaviors/ThreadCachingTestCase.java (5784 => 5785)

--- java/2.x/trunk/pico/container/src/test/org/picocontainer/behaviors/ThreadCachingTestCase.java 2011-05-01 16:39:44 UTC (rev 5784)
+++ java/2.x/trunk/pico/container/src/test/org/picocontainer/behaviors/ThreadCachingTestCase.java 2011-05-02 00:36:34 UTC (rev 5785)
@@ -18,7 +18,6 @@
import org.picocontainer.Characteristics;
import org.picocontainer.DefaultPicoContainer;
import org.picocontainer.classname.DefaultClassLoadingPicoContainer;
-import org.picocontainer.containers.EmptyPicoContainer;
import org.picocontainer.injectors.CompositeInjection;
import org.picocontainer.injectors.ConstructorInjection;
import org.picocontainer.injectors.SetterInjection;
@@ -35,13 +34,24 @@

public static class Baz {

+ public Baz() {
+ }
+
+ public void setStringBuilder(StringBuilder sb) {
+ sb.append("<Baz");
+ }
+
+ }
+
+ public static class Qux {
+
private static final Object lock = new Object();

private static int CTR;

private int inst;

- public Baz(StringBuilder sb) {
+ public Qux(StringBuilder sb) {
synchronized (lock) {
inst = CTR++;
sb.append("!").append(inst).append(" ");
@@ -52,6 +62,11 @@
sb.append("<").append(inst).append(" ");
}
}
+
+ @Override
+ public String toString() {
+ return "baz2: " + inst;
+ }
}

public static class Bar {
@@ -137,7 +152,7 @@

@Test public void testThatTwoThreadsHaveSeparatedCacheValuesWithCompositeInjection() {

- final Baz[] bazs = new Baz[4];
+ final Qux[] quxs = new Qux[4];

DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
final DefaultPicoContainer child = new DefaultPicoContainer(new ThreadCaching().wrap(
@@ -145,33 +160,33 @@
new NullLifecycleStrategy(), parent);

parent.addComponent(StringBuilder.class);
- child.addComponent(Baz.class);
+ child.addComponent(Qux.class);

StringBuilder sb = parent.getComponent(StringBuilder.class);
- bazs[0] = child.getComponent(Baz.class);
+ quxs[0] = child.getComponent(Qux.class);

Thread thread = new Thread() {
public void run() {
- bazs[1] = child.getComponent(Baz.class);
- bazs[3] = child.getComponent(Baz.class);
+ quxs[1] = child.getComponent(Qux.class);
+ quxs[3] = child.getComponent(Qux.class);
}
};
thread.start();
- bazs[2] = child.getComponent(Baz.class);
+ quxs[2] = child.getComponent(Qux.class);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}

- assertNotNull(bazs[0]);
- assertNotNull(bazs[1]);
- assertNotNull(bazs[2]);
- assertNotNull(bazs[3]);
- assertSame(bazs[0],bazs[2]);
- assertEquals(bazs[1],bazs[3]);
- assertFalse(bazs[0] == bazs[1]);
+ assertNotNull(quxs[0]);
+ assertNotNull(quxs[1]);
+ assertNotNull(quxs[2]);
+ assertNotNull(quxs[3]);
+ assertSame(quxs[0],quxs[2]);
+ assertEquals(quxs[1],quxs[3]);
+ assertFalse(quxs[0] == quxs[1]);
assertEquals("!0 <0 !1 <1", sb.toString().trim());
- assertEquals("ThreadCached:CompositeInjector(ConstructorInjector+SetterInjector)-class org.picocontainer.behaviors.ThreadCachingTestCase$Baz", child.getComponentAdapter(Baz.class).toString());
+ assertEquals("ThreadCached:CompositeInjector(ConstructorInjector+SetterInjector)-class org.picocontainer.behaviors.ThreadCachingTestCase$Qux", child.getComponentAdapter(Qux.class).toString());
}

@Test public void testThatTwoThreadsHaveSeparatedCacheValuesWithInstanceRegistrationAndClassLoadingPicoContainer() {

Modified: java/2.x/trunk/pico/container/src/test/org/picocontainer/injectors/ThreadLocalCyclicDependencyGuardTestCase.java (5784 => 5785)

--- java/2.x/trunk/pico/container/src/test/org/picocontainer/injectors/ThreadLocalCyclicDependencyGuardTestCase.java 2011-05-01 16:39:44 UTC (rev 5784)
+++ java/2.x/trunk/pico/container/src/test/org/picocontainer/injectors/ThreadLocalCyclicDependencyGuardTestCase.java 2011-05-02 00:36:34 UTC (rev 5785)
@@ -31,7 +31,7 @@
public ThreadLocalRunner() {
this.blocker = new Blocker();
this.guard = new AbstractInjector.ThreadLocalCyclicDependencyGuard() {
- public Object run() {
+ public Object run(Object instance) {
try {
blocker.block();
} catch (InterruptedException e) {
@@ -43,7 +43,7 @@

public void run() {
try {
- guard.observe(ThreadLocalRunner.class);
+ guard.observe(ThreadLocalRunner.class, null);
} catch (AbstractInjector.CyclicDependencyException e) {
exception = e;
}

----------

To unsubscribe from this list please visit:

http://xircles.codehaus.org/manage_email