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/19 22:27:39 UTC
svn commit: r882303 - in /cayenne/sandbox/cayenne-di/src:
main/java/org/apache/cayenne/di/ main/java/org/apache/cayenne/di/spi/
test/java/org/apache/cayenne/di/mock/ test/java/org/apache/cayenne/di/spi/
Author: aadamchik
Date: Thu Nov 19 21:27:38 2009
New Revision: 882303
URL: http://svn.apache.org/viewvc?rev=882303&view=rev
Log:
playing with DI ideas
* adding constructor injection
Added:
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
- copied, changed from r880636, cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InjectingProvider.java
cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation4.java
- copied, changed from r880636, cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultConstructorProvider.java
cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface4.java
- copied, changed from r880636, cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java
Removed:
cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultConstructorProvider.java
cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InjectingProvider.java
Modified:
cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java
cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Inject.java
cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InterfaceBindingBuilder.java
cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/spi/MapInjectorTest.java
Modified: cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java?rev=882303&r1=882302&r2=882303&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java (original)
+++ cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java Thu Nov 19 21:27:38 2009
@@ -20,9 +20,10 @@
public interface Binder {
- /**
- * Starts a binding of a specific interface. Binding should continue using
- * returned BindingBuilder.
- */
- <T> BindingBuilder<T> bind(Class<T> type);
+ /**
+ * Starts a binding of a specific interface. Binding should continue using returned
+ * BindingBuilder.
+ */
+ <T> BindingBuilder<T> bind(Class<T> interfaceType);
+
}
Modified: cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Inject.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Inject.java?rev=882303&r1=882302&r2=882303&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Inject.java (original)
+++ cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Inject.java Thu Nov 19 21:27:38 2009
@@ -19,6 +19,7 @@
package org.apache.cayenne.di;
import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
@@ -26,7 +27,7 @@
@Retention(RUNTIME)
@Target( {
- FIELD
+ FIELD, PARAMETER
})
public @interface Inject {
Added: 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=882303&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorProvider.java (added)
+++ cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/ConstructorProvider.java Thu Nov 19 21:27:38 2009
@@ -0,0 +1,115 @@
+/*****************************************************************
+ * 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.spi;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+
+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 Constructor<? extends T> constructor;
+ private Injector injector;
+
+ ConstructorProvider(Class<? extends T> implementation, Injector injector) {
+
+ initConstructor(implementation);
+
+ if (constructor == null) {
+ throw new DIException(
+ "Can't find approprate constructor to create object of type "
+ + implementation.getName());
+ }
+
+ this.constructor.setAccessible(true);
+ this.injector = injector;
+ }
+
+ private void initConstructor(Class<? extends T> implementation) {
+
+ Constructor<? extends T>[] constructors = implementation
+ .getDeclaredConstructors();
+
+ Constructor<? extends T> lastMatch = null;
+ int lastSize = -1;
+
+ // pick the first constructor with all injection-annotated parameters, or the
+ // default constructor; constructor with the longest parameter list is preferred
+ // if multiple matches are found
+ for (Constructor<? extends T> constructor : constructors) {
+
+ int size = constructor.getParameterTypes().length;
+ if (size <= lastSize) {
+ continue;
+ }
+
+ if (size == 0) {
+ lastSize = 0;
+ lastMatch = constructor;
+ continue;
+ }
+
+ boolean injectable = true;
+ for (Annotation[] annotations : constructor.getParameterAnnotations()) {
+
+ boolean parameterInjectable = false;
+ for (Annotation annotation : annotations) {
+ if (annotation.annotationType().equals(Inject.class)) {
+ parameterInjectable = true;
+ break;
+ }
+ }
+
+ if (!parameterInjectable) {
+ injectable = false;
+ break;
+ }
+ }
+
+ if (injectable) {
+ lastSize = size;
+ lastMatch = constructor;
+ }
+ }
+
+ this.constructor = lastMatch;
+ }
+
+ public T get() {
+
+ Class<?>[] constructorParameters = constructor.getParameterTypes();
+ Object[] args = new Object[constructorParameters.length];
+
+ for (int i = 0; i < constructorParameters.length; i++) {
+ args[i] = injector.getInstance(constructorParameters[i]);
+ }
+
+ try {
+ return constructor.newInstance(args);
+ }
+ catch (Exception e) {
+ throw new DIException("Error instantiating class "
+ + constructor.getDeclaringClass().getName(), e);
+ }
+ }
+}
Copied: cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java (from r880636, cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InjectingProvider.java)
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java?p2=cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java&p1=cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InjectingProvider.java&r1=880636&r2=882303&rev=882303&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InjectingProvider.java (original)
+++ cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/FieldInjectingProvider.java Thu Nov 19 21:27:38 2009
@@ -27,12 +27,12 @@
import org.apache.cayenne.di.Injector;
import org.apache.cayenne.di.Provider;
-class InjectingProvider<T> implements Provider<T> {
+class FieldInjectingProvider<T> implements Provider<T> {
private Injector injector;
private Provider<T> delegate;
- InjectingProvider(Provider<T> delegate, Injector injector) {
+ FieldInjectingProvider(Provider<T> delegate, Injector injector) {
this.delegate = delegate;
this.injector = injector;
}
Modified: cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InterfaceBindingBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InterfaceBindingBuilder.java?rev=882303&r1=882302&r2=882303&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InterfaceBindingBuilder.java (original)
+++ cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/InterfaceBindingBuilder.java Thu Nov 19 21:27:38 2009
@@ -37,9 +37,12 @@
String key = KeyGenerator.toKey(interfaceType);
// creating a provider chain for lazy resolution of singletons...
- DefaultConstructorProvider<T> provider0 = new DefaultConstructorProvider<T>(
- implementation);
- InjectingProvider<T> provider1 = new InjectingProvider<T>(provider0, injector);
+ ConstructorProvider<T> provider0 = new ConstructorProvider<T>(
+ implementation,
+ injector);
+ FieldInjectingProvider<T> provider1 = new FieldInjectingProvider<T>(
+ provider0,
+ injector);
SingletonProvider<T> provider2 = new SingletonProvider<T>(provider1);
// TODO: andrus 11/15/2009 - report overriding the binding??
@@ -52,7 +55,9 @@
// creating a provider chain for lazy resolution of singletons...
ProviderConstructorProvider<T> provider0 = new ProviderConstructorProvider<T>(
providerType);
- InjectingProvider<T> provider1 = new InjectingProvider<T>(provider0, injector);
+ FieldInjectingProvider<T> provider1 = new FieldInjectingProvider<T>(
+ provider0,
+ injector);
SingletonProvider<T> provider2 = new SingletonProvider<T>(provider1);
// TODO: andrus 11/15/2009 - report overriding existing binding??
Copied: cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation4.java (from r880636, cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultConstructorProvider.java)
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation4.java?p2=cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation4.java&p1=cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultConstructorProvider.java&r1=880636&r2=882303&rev=882303&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/spi/DefaultConstructorProvider.java (original)
+++ cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockImplementation4.java Thu Nov 19 21:27:38 2009
@@ -16,27 +16,30 @@
* specific language governing permissions and limitations
* under the License.
****************************************************************/
-package org.apache.cayenne.di.spi;
+package org.apache.cayenne.di.mock;
-import org.apache.cayenne.di.DIException;
-import org.apache.cayenne.di.Provider;
+import org.apache.cayenne.di.Inject;
-class DefaultConstructorProvider<T> implements Provider<T> {
+public class MockImplementation4 implements MockInterface4 {
- private Class<? extends T> implementation;
+ private MockInterface1 service;
- DefaultConstructorProvider(Class<? extends T> implementation) {
- this.implementation = implementation;
+ public MockImplementation4() {
+ throw new UnsupportedOperationException(
+ "This constructor should not be picked for DI purposes");
}
- public T get() {
- try {
- return implementation.newInstance();
- }
- catch (Exception e) {
- throw new DIException(
- "Error instantiating class " + implementation.getName(),
- e);
- }
+ public MockImplementation4(@Inject MockInterface1 service) {
+ this.service = service;
}
+
+ public MockImplementation4(int i, int k) {
+ throw new UnsupportedOperationException(
+ "This constructor should not be picked for DI purposes");
+ }
+
+ public String getName() {
+ return "constructor_" + service.getName();
+ }
+
}
Copied: cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface4.java (from r880636, cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java)
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface4.java?p2=cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface4.java&p1=cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java&r1=880636&r2=882303&rev=882303&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-di/src/main/java/org/apache/cayenne/di/Binder.java (original)
+++ cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/mock/MockInterface4.java Thu Nov 19 21:27:38 2009
@@ -16,13 +16,9 @@
* specific language governing permissions and limitations
* under the License.
****************************************************************/
-package org.apache.cayenne.di;
+package org.apache.cayenne.di.mock;
-public interface Binder {
+public interface MockInterface4 {
- /**
- * Starts a binding of a specific interface. Binding should continue using
- * returned BindingBuilder.
- */
- <T> BindingBuilder<T> bind(Class<T> type);
+ String getName();
}
Modified: cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/spi/MapInjectorTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/spi/MapInjectorTest.java?rev=882303&r1=882302&r2=882303&view=diff
==============================================================================
--- cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/spi/MapInjectorTest.java (original)
+++ cayenne/sandbox/cayenne-di/src/test/java/org/apache/cayenne/di/spi/MapInjectorTest.java Thu Nov 19 21:27:38 2009
@@ -9,10 +9,12 @@
import org.apache.cayenne.di.mock.MockImplementation2;
import org.apache.cayenne.di.mock.MockImplementation2Sub1;
import org.apache.cayenne.di.mock.MockImplementation3;
+import org.apache.cayenne.di.mock.MockImplementation4;
import org.apache.cayenne.di.mock.MockInterface1;
import org.apache.cayenne.di.mock.MockInterface1Provider;
import org.apache.cayenne.di.mock.MockInterface2;
import org.apache.cayenne.di.mock.MockInterface3;
+import org.apache.cayenne.di.mock.MockInterface4;
public class MapInjectorTest extends TestCase {
@@ -109,6 +111,23 @@
assertEquals("altered_MyName:XName", service.getAlteredName());
}
+ public void testConstructorInjection() {
+
+ Module module = new Module() {
+
+ public void configure(Binder binder) {
+ binder.bind(MockInterface1.class).to(MockImplementation1.class);
+ binder.bind(MockInterface4.class).to(MockImplementation4.class);
+ }
+ };
+
+ MapInjector injector = new MapInjector(module);
+
+ MockInterface4 service = injector.getInstance(MockInterface4.class);
+ assertNotNull(service);
+ assertEquals("constructor_MyName", service.getName());
+ }
+
public void testProviderBinding() {
Module module = new Module() {
@@ -125,7 +144,7 @@
assertNotNull(service);
assertEquals("MyName", service.getName());
}
-
+
public void testClassReBinding() {
Module module = new Module() {