MentaContainer

Compare Revisions

Ignore whitespace Rev 102 → Rev 103

/trunk/src/test/java/org/mentacontainer/impl/MentaContainerTest.java
326,7 → 326,7
SomeAction a = new SomeAction();
c.populate(a); // great... properties of SomeAction were populated by container...
c.inject(a); // great... properties of SomeAction were populated by container...
// let's check if myDAO was injected...
343,6 → 343,61
Assert.assertNotNull(conn.getMyDep());
}
public static class SomeAction2 {
private final MyDAO myDAO;
public SomeAction2(MyDAO myDAO) {
this.myDAO = myDAO;
}
public MyDAO getMyDAO() { return myDAO; }
}
@Test
public void testConstructorDependency() {
Container c = new MentaContainer();
c.ioc("myDAO", JdbcMyDAO.class);
c.ioc("aDependency", SomeDependency.class, Scope.SINGLETON).addPropertyValue("name", "A super dependency!");
c.ioc("connection", Connection.class).addInitValue("A super JDBC connection!");
c.autowire("connection");
c.autowire("aDependency", "myDep");
c.ioc("someAction2", SomeAction2.class).addInitDependency("myDAO");
SomeAction2 action = c.get("someAction2");
Assert.assertNotNull(action.getMyDAO());
}
@Test
public void testConstruct() {
Container c = getConfiguredContainer();
SomeAction2 a = c.construct(SomeAction2.class);
// let's check if myDAO was injected...
Assert.assertNotNull(a.getMyDAO());
// also check if myDAO was corrected wired...
Connection conn = ((JdbcMyDAO) a.getMyDAO()).getConnection();
Assert.assertNotNull(conn);
// check if conn was also wired...
Assert.assertNotNull(conn.getMyDep());
}
private static class SomeObject {
private boolean cleared = false;
/trunk/src/main/java/org/mentacontainer/impl/ConstructorDependency.java
46,4 → 46,9
return true;
}
@Override
public String toString() {
return "[ConstructorDependency: sourceFromContainer=" + sourceFromContainer + "]";
}
}
/trunk/src/main/java/org/mentacontainer/impl/MentaContainer.java
452,13 → 452,15
@Override
public <T> T construct(Class<? extends Object> klass) {
for(ConstructorDependency d : forConstructMethod) System.out.println(d);
ClassFactory f = new ClassFactory(this, klass, forConstructMethod);
return (T) f.getInstance();
}
 
@Override
public Container populate(Object bean) {
public void inject(Object bean) {
Provider p = new Provider() {
484,8 → 486,6
throw new RuntimeException("Error populating bean: " + bean, e);
}
 
return this;
}
 
@Override
/trunk/src/main/java/org/mentacontainer/impl/ClassFactory.java
11,6 → 11,7
import java.util.Set;
 
import org.mentacontainer.ConfigurableFactory;
import org.mentacontainer.util.FindConstructor;
import org.mentacontainer.util.FindMethod;
 
/**
306,7 → 307,9
try {
constructor = klass.getConstructor(getClasses(initTypes));
//constructor = klass.getConstructor(getClasses(initTypes));
constructor = FindConstructor.getConstructor(klass, getClasses(initTypes));
} catch(Exception e) {
314,8 → 317,10
try {
constructor = klass.getConstructor(getClasses(convertToPrimitives(initTypes)));
//constructor = klass.getConstructor(getClasses(convertToPrimitives(initTypes)));
constructor = FindConstructor.getConstructor(klass, getClasses(convertToPrimitives(initTypes)));
} catch(Exception ee) {
throw new RuntimeException("Cannot find a constructor for class: " + klass);
/trunk/src/main/java/org/mentacontainer/Container.java
103,7 → 103,7
* @param bean The bean to be populated with other beans from the container.
* @return The container itself. (Fluent API)
*/
public Container populate(Object bean);
public void inject(Object bean);
public <T> T construct(Class<? extends Object> klass);
/trunk/src/main/java/org/mentacontainer/example/BasicOperations.java
236,7 → 236,7
 
SomeService service = new SomeService();
 
c.populate(service); // populate (inject) all properties of SomeService with
c.inject(service); // populate (inject) all properties of SomeService with
// beans from the container
 
service.doSomething(); // ==> "saoj"
/trunk/src/main/java/org/mentacontainer/util/FindMethod.java
21,7 → 21,7
*/
public static Method getMethod(Class<? extends Object> source,
String name,
Class[] parameterTypes)
Class<? extends Object>[] parameterTypes)
throws NoSuchMethodException {
return internalFind(source.getMethods(),
name,
35,9 → 35,9
* @param name Name of method to find
* @param parameterTypes Parameter types to search for
*/
public static Method getDeclaredMethod(Class source,
public static Method getDeclaredMethod(Class<? extends Object> source,
String name,
Class[] parameterTypes)
Class<? extends Object>[] parameterTypes)
throws NoSuchMethodException {
return internalFind(source.getDeclaredMethods(),
name,
49,7 → 49,7
*/
private static Method internalFind(Method[] toTest,
String name,
Class[] parameterTypes)
Class<? extends Object>[] parameterTypes)
throws NoSuchMethodException {
int l = parameterTypes.length;
 
61,7 → 61,7
if (!toTest[i].getName().equals(name))
continue;
// Check the parameters match
Class[] params = toTest[i].getParameterTypes();
Class<? extends Object>[] params = toTest[i].getParameterTypes();
 
if (params.length != l)
continue;
102,16 → 102,16
int j;
// In terms of the JLS, current is T
Method current = applicableMethods.get(i);
Class[] currentParams = current.getParameterTypes();
Class currentDeclarer = current.getDeclaringClass();
Class<? extends Object>[] currentParams = current.getParameterTypes();
Class<? extends Object> currentDeclarer = current.getDeclaringClass();
 
for (j = 0; j < size; j++) {
if (i == j)
continue;
// In terms of the JLS, test is U
Method test = applicableMethods.get(j);
Class[] testParams = test.getParameterTypes();
Class testDeclarer = test.getDeclaringClass();
Class<? extends Object>[] testParams = test.getParameterTypes();
Class<? extends Object> testDeclarer = test.getDeclaringClass();
 
// Check if T is a subclass of U, breaking if not
if (!testDeclarer.isAssignableFrom(currentDeclarer))
/trunk/src/main/java/org/mentacontainer/util/FindConstructor.java
New file
0,0 → 1,135
package org.mentacontainer.util;
import java.lang.reflect.Constructor;
import java.util.LinkedList;
import java.util.List;
 
/**
* Find constructor with polymorphism!
* Class.getConstructor only finds an exact match.
*
* @author Jon Skeet (http://groups.google.com/group/comp.lang.java.programmer/browse_thread/thread/921ab91865c8cc2e/9e141d3d62e7cb3f)
*/
public class FindConstructor {
 
/**
* Finds the most specific applicable constructor
*
* @param source Class to find a constructor for
* @param parameterTypes Parameter types to search for
*/
public static Constructor<? extends Object> getConstructor(Class<? extends Object> source,
Class<? extends Object>[] parameterTypes)
throws NoSuchMethodException {
return internalFind(source.getConstructors(),
parameterTypes);
}
 
/**
* Finds the most specific applicable declared constructor
*
* @param source Class to find method in
* @param parameterTypes Parameter types to search for
*/
public static Constructor<? extends Object> getDeclaredConstructor(Class<? extends Object> source,
Class<? extends Object>[] parameterTypes)
throws NoSuchMethodException {
return internalFind(source.getDeclaredConstructors(),
parameterTypes);
}
 
/**
* Internal method to find the most specific applicable method
*/
private static Constructor<? extends Object> internalFind(Constructor<? extends Object>[] toTest,
Class<? extends Object>[] parameterTypes)
throws NoSuchMethodException {
int l = parameterTypes.length;
 
// First find the applicable methods
List<Constructor<? extends Object>> applicableMethods = new LinkedList<Constructor<? extends Object>>();
 
for (int i = 0; i < toTest.length; i++) {
// Check the parameters match
Class<? extends Object>[] params = toTest[i].getParameterTypes();
 
if (params.length != l)
continue;
int j;
 
for (j = 0; j < l; j++)
if (!params[j].isAssignableFrom(parameterTypes[j]))
break;
// If so, add it to the list
if (j == l)
applicableMethods.add(toTest[i]);
}
 
/*
* If we've got one or zero methods, we can finish
* the job now.
*/
int size = applicableMethods.size();
 
if (size == 0)
throw new NoSuchMethodException ("No such constructor!");
if (size == 1)
return applicableMethods.get(0);
 
/*
* Now find the most specific method. Do this in a very primitive
* way - check whether each method is maximally specific. If more
* than one method is maximally specific, we'll throw an exception.
* For a definition of maximally specific, see JLS section 15.11.2.2.
*
* I'm sure there are much quicker ways - and I could probably
* set the second loop to be from i+1 to size. I'd rather not though,
* until I'm sure...
*/
int maximallySpecific = -1; // Index of maximally specific method
 
for (int i = 0; i < size; i++) {
int j;
// In terms of the JLS, current is T
Constructor<? extends Object> current = applicableMethods.get(i);
Class<? extends Object>[] currentParams = current.getParameterTypes();
Class<? extends Object> currentDeclarer = current.getDeclaringClass();
 
for (j = 0; j < size; j++) {
if (i == j)
continue;
// In terms of the JLS, test is U
Constructor<? extends Object> test = applicableMethods.get(j);
Class<? extends Object>[] testParams = test.getParameterTypes();
Class<? extends Object> testDeclarer = test.getDeclaringClass();
 
// Check if T is a subclass of U, breaking if not
if (!testDeclarer.isAssignableFrom(currentDeclarer))
break;
 
// Check if each parameter in T is a subclass of the
// equivalent parameter in U
int k;
 
for (k = 0; k < l; k++)
if (!testParams[k].isAssignableFrom(currentParams[k]))
break;
if (k != l)
break;
}
// Maximally specific!
if (j == size) {
if (maximallySpecific != -1)
throw new NoSuchMethodException
("Ambiguous method search - more " +
"than one maximally specific method");
maximallySpecific = i;
}
}
if (maximallySpecific == -1)
throw new NoSuchMethodException ("No maximally specific method.");
return applicableMethods.get(maximallySpecific);
}
 
}