You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2009/11/21 21:40:27 UTC
svn commit: r882988 - in /cayenne/sandbox/cayenne-di/src:
main/java/org/apache/cayenne/di/spi/ test/java/org/apache/cayenne/di/mock/
test/java/org/apache/cayenne/di/spi/
Author: aadamchik
Date: Sat Nov 21 20:40:26 2009
New Revision: 882988
URL: http://svn.apache.org/viewvc?rev=882988&view=rev
Log:
playing with DI ideas
* fixing circular dependency during constructor injection
Added:
cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_DepOn2Constructor.java
cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation2_Constructor.java
Modified:
cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorProvider.java
cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java
cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InjectionStack.java
cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorCircularInjectionTest.java
Modified: cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorProvider.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorProvider.java?rev=882988&r1=882987&r2=882988&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorProvider.java (original)
+++ cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorProvider.java Sat Nov 21 20:40:26 2009
@@ -26,17 +26,16 @@
import org.apache.cayenne.di.DIException;
import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.di.Injector;
import org.apache.cayenne.di.Provider;
class ConstructorProvider<T> implements Provider<T> {
private Class<T> interfaceType;
private Constructor<? extends T> constructor;
- private Injector injector;
+ private DefaultInjector injector;
ConstructorProvider(Class<T> interfaceType, Class<? extends T> implementation,
- Injector injector) {
+ DefaultInjector injector) {
initConstructor(implementation);
@@ -106,6 +105,7 @@
Class<?>[] constructorParameters = constructor.getParameterTypes();
Type[] genericTypes = constructor.getGenericParameterTypes();
Object[] args = new Object[constructorParameters.length];
+ InjectionStack stack = injector.getInjectionStack();
for (int i = 0; i < constructorParameters.length; i++) {
@@ -138,7 +138,14 @@
args[i] = injector.getProvider(objectClass);
}
else {
- args[i] = injector.getInstance(parameter);
+
+ stack.push(DIUtil.toKey(parameter));
+ try {
+ args[i] = injector.getInstance(parameter);
+ }
+ finally {
+ stack.pop();
+ }
}
}
Modified: cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java?rev=882988&r1=882987&r2=882988&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java (original)
+++ cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java Sat Nov 21 20:40:26 2009
@@ -71,51 +71,51 @@
object.getClass(),
new ArrayList<Field>());
- injector.getInjectionStack().push(bindingKey);
+ InjectionStack stack = injector.getInjectionStack();
- try {
+ for (Field field : injectableFields) {
+ Object value;
+ Class<?> fieldType = field.getType();
- for (Field field : injectableFields) {
- Object value;
- Class<?> fieldType = field.getType();
-
- if (Provider.class.equals(fieldType)) {
-
- Class<?> objectClass = DIUtil.parameterClass(field
- .getGenericType());
-
- if (objectClass == null) {
- String message = String.format(
- "Provider field %s.%s of type %s must be "
- + "parameterized to be usable for injection",
- field.getDeclaringClass().getName(),
- field.getName(),
- fieldType.getName());
- throw new DIException(message);
- }
+ if (Provider.class.equals(fieldType)) {
- value = injector.getProvider(objectClass);
- }
- else {
- value = injector.getInstance(fieldType);
- }
+ Class<?> objectClass = DIUtil.parameterClass(field.getGenericType());
- try {
- field.set(object, value);
- }
- catch (Exception e) {
+ if (objectClass == null) {
String message = String.format(
- "Error injecting into field %s.%s of type %s",
+ "Provider field %s.%s of type %s must be "
+ + "parameterized to be usable for injection",
field.getDeclaringClass().getName(),
field.getName(),
fieldType.getName());
- throw new DIException(message, e);
+ throw new DIException(message);
}
+
+ value = injector.getProvider(objectClass);
+ }
+ else {
+ stack.push(bindingKey);
+ try {
+ value = injector.getInstance(fieldType);
+ }
+ finally {
+ stack.pop();
+ }
+ }
+
+ try {
+ field.set(object, value);
+ }
+ catch (Exception e) {
+ String message = String.format(
+ "Error injecting into field %s.%s of type %s",
+ field.getDeclaringClass().getName(),
+ field.getName(),
+ fieldType.getName());
+ throw new DIException(message, e);
}
}
- finally {
- injector.getInjectionStack().pop();
- }
+
}
}
Modified: cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InjectionStack.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InjectionStack.java?rev=882988&r1=882987&r2=882988&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InjectionStack.java (original)
+++ cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InjectionStack.java Sat Nov 21 20:40:26 2009
@@ -49,9 +49,13 @@
}
if (localStack.contains(bindingKey)) {
- throw new DIException("Circular dependency detected: "
- + localStack
- + ". You should try injecting a provider instead.");
+ String message = String
+ .format(
+ "Circular dependency detected when binding a key \"%s\". Nested keys: %s"
+ + ". To resolve it, you should inject a Provider instead of an object.",
+ bindingKey,
+ localStack);
+ throw new DIException(message);
}
localStack.add(bindingKey);
Added: cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_DepOn2Constructor.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_DepOn2Constructor.java?rev=882988&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_DepOn2Constructor.java (added)
+++ cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation1_DepOn2Constructor.java Sat Nov 21 20:40:26 2009
@@ -0,0 +1,36 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.cayenne.di.mock;
+
+import org.apache.cayenne.di.Inject;
+
+public class MockImplementation1_DepOn2Constructor implements MockInterface1 {
+
+ private MockInterface2 interface2;
+
+ // this creates a circular dependency when MockImplementation2 is bound to
+ // MockInterface2.
+ public MockImplementation1_DepOn2Constructor(@Inject MockInterface2 interface2) {
+ this.interface2 = interface2;
+ }
+
+ public String getName() {
+ return interface2.getName();
+ }
+}
Added: cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation2_Constructor.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation2_Constructor.java?rev=882988&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation2_Constructor.java (added)
+++ cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation2_Constructor.java Sat Nov 21 20:40:26 2009
@@ -0,0 +1,38 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.cayenne.di.mock;
+
+import org.apache.cayenne.di.Inject;
+
+public class MockImplementation2_Constructor implements MockInterface2 {
+
+ private MockInterface1 service;
+
+ public MockImplementation2_Constructor(@Inject MockInterface1 service) {
+ this.service = service;
+ }
+
+ public String getAlteredName() {
+ return "altered_" + service.getName();
+ }
+
+ public String getName() {
+ return "MockImplementation2Name";
+ }
+}
Modified: cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorCircularInjectionTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorCircularInjectionTest.java?rev=882988&r1=882987&r2=882988&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorCircularInjectionTest.java (original)
+++ cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/spi/DefaultInjectorCircularInjectionTest.java Sat Nov 21 20:40:26 2009
@@ -24,8 +24,10 @@
import org.apache.cayenne.di.DIException;
import org.apache.cayenne.di.Module;
import org.apache.cayenne.di.mock.MockImplementation1_DepOn2;
+import org.apache.cayenne.di.mock.MockImplementation1_DepOn2Constructor;
import org.apache.cayenne.di.mock.MockImplementation1_DepOn2Provider;
import org.apache.cayenne.di.mock.MockImplementation2;
+import org.apache.cayenne.di.mock.MockImplementation2_Constructor;
import org.apache.cayenne.di.mock.MockInterface1;
import org.apache.cayenne.di.mock.MockInterface2;
@@ -71,4 +73,30 @@
MockInterface1 service = injector.getInstance(MockInterface1.class);
assertEquals("MockImplementation2Name", service.getName());
}
+
+ public void testConstructorInjection_CircularDependency() {
+
+ Module module = new Module() {
+
+ public void configure(Binder binder) {
+ binder.bind(MockInterface1.class).to(
+ MockImplementation1_DepOn2Constructor.class);
+ binder.bind(MockInterface2.class).to(
+ MockImplementation2_Constructor.class);
+ }
+ };
+
+ DefaultInjector injector = new DefaultInjector(module);
+
+ try {
+ injector.getInstance(MockInterface1.class);
+ fail("Circular dependency is not detected.");
+ }
+ catch (DIException e) {
+ // expected
+ }
+ catch (StackOverflowError e) {
+ fail("Circular dependency is not detected, causing stack overflow");
+ }
+ }
}