MentaContainer

Compare Revisions

Ignore whitespace Rev 96 → Rev 97

/trunk/src/test/java/org/mentacontainer/DependencyTest.java
File deleted
\ No newline at end of file
/trunk/src/test/java/org/mentacontainer/impl/ClassFactoryTest.java
30,7 → 30,7
@Test
public void testFactory() {
Container container = new MentaContainer();
MentaContainer container = new MentaContainer();
Factory c1 = new ClassFactory(container, User.class).addInitValue("saoj");
63,7 → 63,7
@Test
public void testDependable1() {
Container c = new MentaContainer();
MentaContainer c = new MentaContainer();
c.ioc("myString", String.class).addInitValue("hello");
92,7 → 92,7
@Test
public void testDependable2() {
Container c = new MentaContainer();
MentaContainer c = new MentaContainer();
c.ioc("myString", String.class).addInitValue("hello");
118,7 → 118,7
@Test
public void testPrimitivePropertyValue1() {
Container container = new MentaContainer();
MentaContainer container = new MentaContainer();
Factory f = new ClassFactory(container, TestObj2.class).addPropertyValue("integer", 20);
130,7 → 130,7
@Test
public void testPrimitivePropertyValue2() {
Container container = new MentaContainer();
MentaContainer container = new MentaContainer();
Factory f = new ClassFactory(container, TestObj2.class).addPropertyValue("integer", new Integer(20));
153,7 → 153,7
@Test
public void testPrimitivePropertyValue3() {
Container container = new MentaContainer();
MentaContainer container = new MentaContainer();
Factory f = new ClassFactory(container, TestObj2_1.class).addPropertyValue("integer", 20);
165,7 → 165,7
@Test
public void testPrimitivePropertyValue4() {
Container container = new MentaContainer();
MentaContainer container = new MentaContainer();
Factory f = new ClassFactory(container, TestObj2_1.class).addPropertyValue("integer", new Integer(20));
187,7 → 187,7
@Test
public void testPrimitiveInitValue1() {
Container container = new MentaContainer();
MentaContainer container = new MentaContainer();
Factory f = new ClassFactory(container, TestObj3.class).addInitValue(20);
208,7 → 208,7
@Test
public void testPrimitiveInitValue2() {
Container container = new MentaContainer();
MentaContainer container = new MentaContainer();
Factory f = new ClassFactory(container, TestObj3_1.class).addInitValue(20);
231,7 → 231,7
@Test
public void testPrimitiveInitValue3() {
Container container = new MentaContainer();
MentaContainer container = new MentaContainer();
Factory f = new ClassFactory(container, TestObj3_2.class).addInitValue(20).addInitPrimitive(30L);
259,7 → 259,7
@Test
public void testMixInitValues() {
Container container = new MentaContainer();
MentaContainer container = new MentaContainer();
Factory f = new ClassFactory(container, TestObj4.class).addInitPrimitive(20).addInitValue("hello").addInitValue(20L).addInitPrimitive(20L);
/trunk/src/test/java/org/mentacontainer/example/CoreExamplesTest.java
New file
0,0 → 1,198
package org.mentacontainer.example;
 
import java.util.Calendar;
import java.util.Date;
 
import junit.framework.Assert;
 
import org.junit.Test;
import org.mentacontainer.Container;
import org.mentacontainer.impl.MentaContainer;
 
public class CoreExamplesTest {
@Test
public void testBeanInitialization() {
Container c = new MentaContainer();
c.ioc("myString1", String.class);
String myString1 = c.get("myString1");
Assert.assertEquals("", myString1); // default constructor...
c.ioc("myString2", String.class).addInitValue("saoj");
String myString2 = c.get("myString2"); // using constructor....
Assert.assertEquals("saoj", myString2);
Assert.assertNotSame(c.get("myString1"), c.get("myString1")); // most be different instances...
// test setters...
c.ioc("myDate1", Date.class).addPropertyValue("hours", 15) // setHours(15)
.addPropertyValue("minutes", 10) // setMinutes(10)
.addPropertyValue("seconds", 45); // setSeconds(45)
Date myDate1 = c.get("myDate1");
Assert.assertTrue(myDate1.toString().indexOf("15:10:45") > 0);
// test setter together with constructor...
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1976);
c.ioc("myDate2", Date.class).addInitValue(cal.getTimeInMillis()).addPropertyValue("seconds", 59);
Date myDate2 = c.get("myDate2");
Assert.assertTrue(myDate2.toString().indexOf(":59") > 0);
Assert.assertTrue(myDate2.toString().indexOf("1976") > 0);
}
@Test
public void testDependencies() {
// constructor dependency...
Container c = new MentaContainer();
c.ioc("username", String.class).addInitValue("saoj");
 
c.ioc("myString", String.class).addInitDependency("username");
String myString = c.get("myString");
Assert.assertEquals("saoj", myString);
// setter dependency...
c.ioc("myBirthdayYear", Integer.class).addInitValue(76);
c.ioc("myBirthday", Date.class).addPropertyDependency("year", "myBirthdayYear").addPropertyValue("month", 0).addPropertyValue("date", 20);
Date myBirthday = c.get("myBirthday");
Assert.assertTrue(myBirthday.toString().indexOf("Jan 20") > 0);
Assert.assertTrue(myBirthday.toString().indexOf("1976") > 0);
// both...
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1976);
 
c.ioc("timeInMillis", Long.class).addInitValue(cal.getTimeInMillis());
c.ioc("myBirthdayMonth", Integer.class).addInitValue(0);
c.ioc("myBirthday", Date.class).addInitDependency("timeInMillis").addPropertyDependency("month", "myBirthdayMonth").addPropertyValue("date", 20);
myBirthday = c.get("myBirthday");
Assert.assertTrue(myBirthday.toString().indexOf("Jan 20") > 0);
Assert.assertTrue(myBirthday.toString().indexOf("1976") > 0);
}
@Test
public void testAutoWiring() {
// constructor dependency...
Container c = new MentaContainer();
c.ioc("username", String.class).addInitValue("saoj");
 
c.ioc("myString", String.class);
c.autowireByConstructor("username");
String myString = c.get("myString");
Assert.assertEquals("saoj", myString);
// setter dependency...
c = new MentaContainer();
c.ioc("myBirthdayYear", Integer.class).addInitValue(76);
c.ioc("myBirthday", Date.class).addPropertyValue("month", 0).addPropertyValue("date", 20);
c.autowireBySetter("year", "myBirthdayYear");
Date myBirthday = c.get("myBirthday");
Assert.assertTrue(myBirthday.toString().indexOf("Jan 20") > 0);
Assert.assertTrue(myBirthday.toString().indexOf("1976") > 0);
// both...
c = new MentaContainer();
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1976);
 
c.ioc("timeInMillis", Long.class).addInitValue(cal.getTimeInMillis());
c.ioc("myBirthdayMonth", Integer.class).addInitValue(0);
c.ioc("myBirthday", Date.class).addPropertyValue("date", 20);
c.autowireByConstructor("timeInMillis");
c.autowireBySetter("month", "myBirthdayMonth");
myBirthday = c.get("myBirthday");
Assert.assertTrue(myBirthday.toString().indexOf("Jan 20") > 0);
Assert.assertTrue(myBirthday.toString().indexOf("1976") > 0);
// bypass autowireByConstructor by specifying...
c = new MentaContainer();
cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1976);
 
Calendar cal2 = Calendar.getInstance();
cal2.set(Calendar.YEAR, 1977);
c.ioc("timeInMillis", Long.class).addInitValue(cal.getTimeInMillis());
c.ioc("timeInMillis2", Long.class).addInitValue(cal2.getTimeInMillis());
c.ioc("myBirthdayMonth", Integer.class).addInitValue(0);
c.ioc("myBirthday", Date.class).addPropertyValue("date", 20).addInitDependency("timeInMillis2");
c.autowireByConstructor("timeInMillis");
c.autowireBySetter("month", "myBirthdayMonth");
myBirthday = c.get("myBirthday");
Assert.assertTrue(myBirthday.toString().indexOf("Jan 20") > 0);
Assert.assertTrue(myBirthday.toString().indexOf("1977") > 0);
// bypass autowireBySetter by specifying...
// not supported yet...
// force zero arguments constructor...
c = new MentaContainer();
cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1976);
 
c.ioc("timeInMillis", Long.class).addInitValue(cal.getTimeInMillis());
c.ioc("myBirthdayMonth", Integer.class).addInitValue(0);
c.ioc("myBirthday", Date.class).addPropertyValue("date", 20).useZeroArgumentConstructor();
c.autowireByConstructor("timeInMillis");
c.autowireBySetter("month", "myBirthdayMonth");
myBirthday = c.get("myBirthday");
Assert.assertTrue(myBirthday.toString().indexOf("Jan 20") > 0);
Assert.assertTrue(myBirthday.toString().indexOf("1976") == -1);
}
}
/trunk/src/main/java/org/mentacontainer/SetterDependency.java
File deleted
/trunk/src/main/java/org/mentacontainer/impl/ConstructorDependency.java
New file
0,0 → 1,49
package org.mentacontainer.impl;
 
 
/**
* A simple implementation of the Dependency interface.
*
* @author sergio.oliveira.jr@gmail.com
*/
class ConstructorDependency {
private final String sourceFromContainer;
private final Class<? extends Object> sourceType;
public ConstructorDependency(String sourceFromContainer, Class<? extends Object> sourceType) {
this.sourceFromContainer = sourceFromContainer;
this.sourceType = sourceType;
}
public String getSource() {
return sourceFromContainer;
}
public Class<? extends Object> getSourceType() {
return sourceType;
}
@Override
public int hashCode() {
return sourceFromContainer.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ConstructorDependency)) return false;
ConstructorDependency d = (ConstructorDependency) obj;
if (!d.sourceFromContainer.equals(this.sourceFromContainer)) return false;
return true;
}
}
/trunk/src/main/java/org/mentacontainer/impl/SetterDependency.java
New file
0,0 → 1,141
package org.mentacontainer.impl;
 
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
 
import org.mentacontainer.util.InjectionUtils;
 
/**
* A simple implementation of the Dependency interface.
*
* @author sergio.oliveira.jr@gmail.com
*/
class SetterDependency {
private final String targetProperty;
private final String sourceFromContainer;
private final Class<? extends Object> sourceType;
private Map<String, Method> cache = new HashMap<String, Method>();
public SetterDependency(String targetProperty, String sourceFromContainer, Class<? extends Object> sourceType) {
this.targetProperty = targetProperty;
this.sourceFromContainer = sourceFromContainer;
this.sourceType = sourceType;
}
public String getTarget() {
return targetProperty;
}
public String getSource() {
return sourceFromContainer;
}
@Override
public int hashCode() {
return targetProperty.hashCode() * 31 + sourceFromContainer.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof SetterDependency)) return false;
SetterDependency d = (SetterDependency) obj;
if (!d.targetProperty.equals(this.targetProperty)) return false;
if (!d.sourceFromContainer.equals(this.sourceFromContainer)) return false;
return true;
}
public Method check(Class<? extends Object> targetClass) {
 
String className = targetClass.getName();
 
// first check cache...
Method m = null;
synchronized(cache) {
m = cache.get(className);
}
if (m == null && cache.containsKey(className)) return null; // it is null...
 
if (m != null) return m;
 
m = InjectionUtils.findMethodToInject(targetClass, targetProperty, sourceType);
/*
try {
Method[] methods = targetClass.getMethods();
StringBuilder sb = new StringBuilder(128);
sb.append("set");
sb.append(targetProperty.substring(0, 1).toUpperCase());
if (targetProperty.length() > 1) sb.append(targetProperty.substring(1));
String methodName = sb.toString();
for(Method theMethod : methods) {
if (theMethod.getName().equals(methodName)) {
// check type...
Class<? extends Object>[] params = theMethod.getParameterTypes();
if (params == null || params.length != 1) continue;
if (params[0].isAssignableFrom(sourceType)) {
m = theMethod;
break;
}
}
}
} catch(Exception e) {
e.printStackTrace();
}
*/
if (m != null) {
synchronized(cache) {
 
cache.put(className, m);
}
return m;
}
synchronized(cache) {
// save null to indicate there is no method here... (so you don't do again to find null !!!
cache.put(className, null);
}
 
return null;
}
}
/trunk/src/main/java/org/mentacontainer/impl/MentaContainer.java
14,7 → 14,6
import org.mentacontainer.Factory;
import org.mentacontainer.Interceptable;
import org.mentacontainer.Scope;
import org.mentacontainer.SetterDependency;
import org.mentacontainer.util.InjectionUtils;
import org.mentacontainer.util.InjectionUtils.Provider;
 
35,8 → 34,10
private Map<String, ThreadLocal<Object>> threadLocalsCache = new Hashtable<String, ThreadLocal<Object>>();
private Set<SetterDependency> dependencies = Collections.synchronizedSet(new HashSet<SetterDependency>());
private Set<SetterDependency> setterDependencies = Collections.synchronizedSet(new HashSet<SetterDependency>());
private Set<ConstructorDependency> constructorDependencies = Collections.synchronizedSet(new HashSet<ConstructorDependency>());
@Override
public Class<? extends Object> getType(String key) {
308,7 → 309,7
 
if (target != null) {
 
for (SetterDependency d : dependencies) {
for (SetterDependency d : setterDependencies) {
 
// has dependency ?
Method m = d.check(target.getClass());
422,22 → 423,35
}
 
@Override
public SetterDependency autowireBySetter(String targetProperty, String sourceFromContainer) {
public void autowireBySetter(String targetProperty, String sourceFromContainer) {
Class<? extends Object> sourceType = getType(sourceFromContainer);
 
SetterDependency d = new SetterDependency(targetProperty, sourceFromContainer, sourceType);
dependencies.add(d);
 
return d;
setterDependencies.add(d);
}
@Override
public SetterDependency autowireBySetter(String targetProperty) {
public void autowireBySetter(String targetProperty) {
return autowireBySetter(targetProperty, targetProperty);
autowireBySetter(targetProperty, targetProperty);
}
@Override
public void autowireByConstructor(String sourceFromContainer) {
Class<? extends Object> sourceType = getType(sourceFromContainer);
ConstructorDependency d = new ConstructorDependency(sourceFromContainer, sourceType);
constructorDependencies.add(d);
}
Set<ConstructorDependency> getConstructorDependencies() {
return constructorDependencies;
}
 
@Override
public Container populate(Object bean) {
/trunk/src/main/java/org/mentacontainer/impl/ClassFactory.java
3,13 → 3,14
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
import org.mentacontainer.ConfigurableFactory;
import org.mentacontainer.Container;
import org.mentacontainer.util.FindMethod;
 
/**
19,7 → 20,7
*/
class ClassFactory implements ConfigurableFactory {
private final Container container;
private final MentaContainer container;
private final Class<? extends Object> klass;
33,13 → 34,14
private Map<String, Method> cache = null;
private boolean useZeroArgumentConstructor = false;
private boolean useZeroArgumentsConstructor = false;
public ClassFactory(Container container, Class<? extends Object> klass) {
public ClassFactory(MentaContainer container, Class<? extends Object> klass) {
this.container = container;
this.klass = klass;
}
@Override
60,7 → 62,7
@Override
public ConfigurableFactory useZeroArgumentConstructor() {
this.useZeroArgumentConstructor = true;
this.useZeroArgumentsConstructor = true;
return this;
}
111,6 → 113,8
private List<Class<? extends Object>> convertToPrimitives(List<Class<? extends Object>> list) {
if (list == null) return null;
Iterator<Class<? extends Object>> iter = list.iterator();
List<Class<? extends Object>> results = new LinkedList<Class<? extends Object>>();
136,6 → 140,8
private Class<? extends Object>[] getClasses(List<Class<? extends Object>> values) {
if (values == null) return new Class[0];
Class<? extends Object>[] types = (Class<? extends Object>[]) new Class[values.size()];
return values.toArray(types);
143,6 → 149,8
private Object [] getValues(List<Object> values) throws InstantiationException {
if (values == null) return null;
Object [] array = new Object[values.size()];
int index = 0;
264,49 → 272,59
Object obj = null;
if (initValues != null && initValues.size() > 0) {
if (constructor == null) {
try {
constructor = klass.getConstructor(getClasses(initTypes));
} catch(Exception e) {
// try primitives...
try {
constructor = klass.getConstructor(getClasses(convertToPrimitives(initTypes)));
} catch(Exception ee) {
 
throw new RuntimeException("Cannot find a constructor for class: " + klass);
}
}
}
try {
obj = constructor.newInstance(getValues(initValues));
} catch(Exception e) {
throw new RuntimeException("Cannot create instance from constructor: " + constructor, e);
}
} else {
try {
obj = klass.newInstance();
} catch(Exception e) {
throw new RuntimeException("Cannot create instance from class: " + klass, e);
}
Object[] values = null;
synchronized(this) {
if (constructor == null) {
if (!useZeroArgumentsConstructor) {
checkConstructorDependencies();
} else {
if (initTypes != null) initTypes = null; // just in case client did something stupid...
if (initValues != null) initValues = null; // just in case client did something stupid...
}
try {
constructor = klass.getConstructor(getClasses(initTypes));
} catch(Exception e) {
// try primitives...
try {
constructor = klass.getConstructor(getClasses(convertToPrimitives(initTypes)));
} catch(Exception ee) {
throw new RuntimeException("Cannot find a constructor for class: " + klass);
}
}
}
try {
values = getValues(initValues);
} catch(Exception e) {
new RuntimeException("Cannot instantiate values for constructor!", e);
}
}
try {
obj = constructor.newInstance(values);
} catch(Exception e) {
throw new RuntimeException("Cannot create instance from constructor: " + constructor, e);
}
if (props != null && props.size() > 0) {
332,18 → 350,53
return (T) obj;
}
private Constructor<? extends Object> findConstructor(List<Object> valuesToBeUsed) {
private static boolean betterIsAssignableFrom(Class<? extends Object> klass1, Class<? extends Object> klass2) {
LinkedList<Class<? extends Object>> providedInitTypes = new LinkedList<Class<? extends Object>>(initTypes);
// with autoboxing both ways...
LinkedList<Object> providedInitValues = new LinkedList<Object>(initValues);
if (klass1.isAssignableFrom(klass2)) return true;
Class<? extends Object> k1 = klass1.isPrimitive() ? klass1 : getPrimitiveFrom(klass1);
Class<? extends Object> k2 = klass2.isPrimitive() ? klass2 : getPrimitiveFrom(klass2);
if (k1 == null || k2 == null) return false;
return k1.isAssignableFrom(k2);
}
private void checkConstructorDependencies() {
Constructor<? extends Object>[] constructors = klass.getConstructors();
Constructor<? extends Object> found = null;
for(Constructor<? extends Object> c : constructors) {
LinkedList<Class<? extends Object>> providedInitTypes = null;
if (initTypes != null) {
providedInitTypes = new LinkedList<Class<? extends Object>>(initTypes);
} else {
providedInitTypes = new LinkedList<Class<? extends Object>>();
}
LinkedList<Object> providedInitValues = null;
if (initValues != null) {
providedInitValues = new LinkedList<Object>(initValues);
} else {
providedInitValues = new LinkedList<Object>();
}
LinkedList<Class<? extends Object>> newInitTypes = new LinkedList<Class<? extends Object>>();
LinkedList<Object> newInitValues = new LinkedList<Object>();
Set<ConstructorDependency> dependencies = new HashSet<ConstructorDependency>(container.getConstructorDependencies());
Class<? extends Object>[] constructorParams = c.getParameterTypes();
if (constructorParams == null || constructorParams.length == 0) continue; // skip default constructor for now...
356,18 → 409,47
if (provided != null && constructorParam.isAssignableFrom(provided)) {
providedInitTypes.removeFirst(); // we matched this one, so removed...
newInitTypes.add(providedInitTypes.removeFirst()); // we matched this one, so remove...
continue; // found param, let's check the other one...
newInitValues.add(providedInitValues.removeFirst());
continue;
} else {
// check auto-wiring...
Iterator<ConstructorDependency> iter = dependencies.iterator();
while(iter.hasNext()) {
ConstructorDependency d = iter.next();
if (betterIsAssignableFrom(constructorParam, d.getSourceType())) {
iter.remove();
newInitTypes.add(d.getSourceType());
newInitValues.add(new DependencyKey(d.getSource()));
continue;
}
}
}
break; // no param... next constructor...
}
// done, check if found...
if (constructorParams.length == newInitTypes.size() && providedInitTypes.isEmpty()) {
this.initTypes = newInitTypes;
this.initValues = newInitValues;
}
}
return null;
}
private static class DependencyKey {
/trunk/src/main/java/org/mentacontainer/Container.java
1,5 → 1,6
package org.mentacontainer;
 
 
/**
* A very simple container that provides:
* <ul>
90,7 → 91,7
* @param source The dependency itself, coming from the container as well, in other words, the bean that will be injected in the original bean
* @return The container itself. (Fluent API)
*/
public SetterDependency autowireBySetter(String property);
public void autowireBySetter(String property);
/**
* Same as {@link #wire(String, Class, String)} except that it assumes that the property name will be the source name, in other words,
100,7 → 101,7
* @param klass
* @return The container itself. (Fluent API)
*/
public SetterDependency autowireBySetter(String property, String source);
public void autowireBySetter(String property, String source);
/**
* Setup a dependency.
109,7 → 110,7
* @return The dependency itself. (Fluent API)
* @see Dependency
*/
//public Dependency autowireByConstructor(Class<? extends Object> type, String source);
public void autowireByConstructor(String source);
/**
* Take a given bean and populate its properties with other beans coming from this container. Perhaps you can call this auto-wiring.