MentaContainer

Compare Revisions

Ignore whitespace Rev 61 → Rev 62

/tags/menta-container-0.9.3/src/test/java/org/mentacontainer/impl/GenericComponentTest.java
New file
0,0 → 1,43
package org.mentacontainer.impl;
 
import junit.framework.Assert;
 
import org.junit.Test;
import org.mentacontainer.Component;
import org.mentacontainer.Container;
 
public class GenericComponentTest {
public static class SomeFactory {
public String giveMeSomething() {
return String.valueOf(System.nanoTime());
}
}
@Test
public void testGenericComponent() throws Exception {
// in real life this will be a SessionFactory, a ConnectionPool or any factory...
SomeFactory factory = new SomeFactory();
Container c = new MentaContainer();
// giveMeSomething => method that will be called to return object
Component generic = new GenericComponent(factory, "giveMeSomething");
c.ioc("myFactory", generic);
String s1 = c.get("myFactory");
Thread.sleep(5); // so strings are different... my cpu is fast! :-)
String s2 = c.get("myFactory");
Assert.assertNotNull(s1);
Assert.assertNotNull(s2);
Assert.assertTrue(s1 != s2);
Assert.assertTrue(!s1.equals(s2));
}
}
/tags/menta-container-0.9.3/src/test/java/org/mentacontainer/impl/MentaDependencyTest.java
New file
0,0 → 1,50
package org.mentacontainer.impl;
 
import java.lang.reflect.Method;
 
import junit.framework.Assert;
 
import org.junit.Test;
import org.mentacontainer.Dependency;
 
public class MentaDependencyTest {
private static class User {
private String username;
public User() { }
public User(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
@Test
public void testDependency() {
Dependency d = new MentaDependency("username", String.class, "theUsername");
Assert.assertEquals("username", d.getTarget());
Assert.assertEquals(String.class, d.getType());
Assert.assertEquals("theUsername", d.getSource());
Method m = d.check(User.class);
Assert.assertNotNull(m);
Assert.assertEquals("setUsername", m.getName());
Assert.assertEquals(String.class, m.getParameterTypes()[0]);
}
}
/tags/menta-container-0.9.3/src/test/java/org/mentacontainer/impl/MentaComponentTest.java
New file
0,0 → 1,44
package org.mentacontainer.impl;
 
import junit.framework.Assert;
 
import org.junit.Test;
import org.mentacontainer.Component;
 
public class MentaComponentTest {
private static class User {
private String username;
public User() { }
public User(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
@Test
public void testComponent() {
Component c1 = new MentaComponent(User.class).addInitValue("saoj");
Component c2 = new MentaComponent(User.class).addProperty("username", "soliveira");
User u1 = c1.getInstance();
User u2 = c2.getInstance();
Assert.assertTrue(u1 != u2);
Assert.assertTrue(!u1.getUsername().equals(u2.getUsername()));
}
}
/tags/menta-container-0.9.3/src/test/java/org/mentacontainer/impl/MentaContainerTest.java
New file
0,0 → 1,308
package org.mentacontainer.impl;
 
import junit.framework.Assert;
 
import org.junit.Test;
import org.mentacontainer.Container;
import org.mentacontainer.Scope;
 
public class MentaContainerTest {
 
@Test
public void testSimpleGet() {
 
Container c = new MentaContainer();
 
c.ioc("myStr", String.class);
 
Assert.assertEquals("", c.get("myStr"));
 
String s1 = c.get("myStr");
 
String s2 = c.get("myStr");
 
Assert.assertTrue(s1 != s2);
 
Assert.assertTrue(s1.equals(s2));
}
 
@Test
public void testConstructorInit() {
 
Container c = new MentaContainer();
 
c.ioc("myStr", String.class).addInitValue("hello");
 
Assert.assertEquals("hello", c.get("myStr"));
 
String s1 = c.get("myStr");
 
String s2 = c.get("myStr");
 
Assert.assertTrue(s1 != s2);
 
Assert.assertTrue(s1.equals(s2));
 
c.ioc("anotherStr", String.class).addInitValue("hi");
 
String s3 = c.get("anotherStr");
 
Assert.assertTrue(s1 != s3);
 
Assert.assertFalse(s1.equals(s3));
}
 
@Test
public void testSingleton() {
 
Container c = new MentaContainer();
 
c.ioc("myStr", String.class, Scope.SINGLETON).addInitValue("hello");
 
Assert.assertEquals("hello", c.get("myStr"));
 
String s1 = c.get("myStr");
 
String s2 = c.get("myStr");
 
Assert.assertTrue(s1 == s2);
 
Assert.assertTrue(s1.equals(s2));
}
@Test
public void testCheckAndClear() {
Container c = new MentaContainer();
c.ioc("myStr", String.class, Scope.SINGLETON).addInitValue("hello");
 
Assert.assertEquals(false, c.check("myStr"));
String s1 = c.get("myStr");
Assert.assertEquals(true, c.check("myStr"));
String s2 = c.get("myStr");
Assert.assertTrue(s1 == s2);
c.clear(Scope.SINGLETON);
Assert.assertEquals(false, c.check("myStr"));
String s3 = c.get("myStr");
Assert.assertTrue(s3 != s2);
}
private static class MyThread extends Thread {
private final Container c;
private final String key;
private String value = null;
public MyThread(Container c, String key) {
super();
this.c = c;
this.key = key;
}
@Override
public void run() {
for(int i = 0; i < 50; i++) {
String v = c.get(key);
if (this.value != null) {
Assert.assertTrue(this.value == v);
}
this.value = v;
}
}
public String getValue() { return value; }
}
@Test
public void testThreadLocal() throws Exception {
final Container c = new MentaContainer();
c.ioc("myStr", String.class, Scope.THREAD).addInitValue("saoj");
String s1 = c.get("myStr");
MyThread t1 = new MyThread(c, "myStr");
MyThread t2 = new MyThread(c, "myStr");
t1.start();
t2.start();
t1.join();
t2.join();
String s2 = t1.getValue();
String s3 = t2.getValue();
Assert.assertTrue(s1 != s2);
Assert.assertTrue(s2 != s3);
}
 
public static interface MyDAO {
public Object getSomething();
}
public static class SomeDependency {
private String name;
public SomeDependency() { }
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static class Connection {
private final String name;
private SomeDependency dep;
public Connection(String name) {
this.name = name;
}
public String toString() {
return getClass().getName() + ": " + name;
}
public String getName() { return name; }
public void setMyDep(SomeDependency dep) { this.dep = dep; }
public SomeDependency getMyDep() { return dep; }
}
public static class JdbcMyDAO implements MyDAO {
private Connection conn;
public void setConn(Connection conn) { this.conn = conn; }
public Connection getConn() { return conn; }
public Object getSomething() {
// use the connection to do something...
Assert.assertNotNull(conn); // it cannot be null!
// also test if the connection also received the myDep dependency...
Assert.assertNotNull(conn.getMyDep());
return conn.toString();
}
}
private Container getConfiguredContainer() {
Container c = new MentaContainer();
c.ioc("myDAO", JdbcMyDAO.class);
c.ioc("aDependency", SomeDependency.class, Scope.SINGLETON).addProperty("name", "A super dependency!");
c.ioc("connection", Connection.class).addInitValue("A super JDBC connection!");
c.autowire("conn" /* the property name that will receive the dependency */,
Connection.class /* the type of the property that will receive the dependency */,
"connection" /* the source inside the container */);
c.autowire("myDep" /* notice this is the setter of the Connection class */,
SomeDependency.class /* the type - it could be an interface for better decoupling */,
"aDependency" /* again this is the name of the bean/component inside the container */);
return c;
}
@Test
public void testAutoWiring() {
Container c = getConfiguredContainer();
MyDAO myDAO = c.get("myDAO");
// check implementation...
Assert.assertEquals(JdbcMyDAO.class, myDAO.getClass());
// check dependency...
Connection conn = ((JdbcMyDAO) myDAO).getConn();
Assert.assertNotNull(conn);
Assert.assertEquals("A super JDBC connection!", conn.getName());
// check dependency of dependency...
Assert.assertEquals(c.get("aDependency"), conn.getMyDep());
Assert.assertTrue(c.get("aDependency") == conn.getMyDep()); // singleton!
// check DAO can do its job...
Assert.assertNotNull(myDAO.getSomething());
}
public static class SomeAction {
private MyDAO myDAO = null;
public void setMyDAO(MyDAO myDAO) {
this.myDAO = myDAO;
}
public MyDAO getMyDAO() { return myDAO; }
}
public void testPopulate() {
Container c = getConfiguredContainer();
SomeAction a = new SomeAction();
c.populate(a); // great... properties of SomeAction were populated by container...
// let's check if myDAO was injected...
Assert.assertNotNull(a.getMyDAO());
// also check if myDAO was corrected wired...
Connection conn = ((JdbcMyDAO) a.getMyDAO()).getConn();
Assert.assertNotNull(conn);
// check if conn was also wired...
Assert.assertNotNull(conn.getMyDep());
}
}
/tags/menta-container-0.9.3/src/main/java/org/mentacontainer/impl/GenericComponent.java
New file
0,0 → 1,42
package org.mentacontainer.impl;
 
import java.lang.reflect.Method;
 
import org.mentacontainer.Component;
import org.mentacontainer.util.FindMethod;
 
public class GenericComponent implements Component {
private final Object factory;
private final Method method;
public GenericComponent(Object factory, String methodName) {
this.factory = factory;
try {
this.method = FindMethod.getMethod(factory.getClass(), methodName, new Class[] { });
this.method.setAccessible(true);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
public <T> T getInstance() {
try {
return (T) method.invoke(factory, (Object[]) null);
} catch(Exception e) {
throw new RuntimeException("Cannot invoke method: " + method, e);
}
}
}
/tags/menta-container-0.9.3/src/main/java/org/mentacontainer/impl/MentaDependency.java
New file
0,0 → 1,113
package org.mentacontainer.impl;
 
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
 
import org.mentacontainer.Dependency;
import org.mentacontainer.util.InjectionUtils;
 
/**
* A simple implementation of the Dependency interface.
*
* @author sergio.oliveira.jr@gmail.com
*/
public class MentaDependency implements Dependency {
private final String target;
private String source;
private final Class<? extends Object> klass;
private Map<String, Method> cache = new HashMap<String, Method>();
public MentaDependency(String target, Class<? extends Object> klass, String source) {
this.klass = klass;
this.target = target;
this.source = source;
}
public MentaDependency(String target, Class<? extends Object> klass) {
this(target, klass, target);
}
public String getTarget() {
return target;
}
public String getSource() {
return source;
}
public Class<? extends Object> getType() {
return klass;
}
public int hashCode() {
return klass.hashCode() * 62 + target.hashCode() * 31 + source.hashCode();
}
public boolean equals(Object obj) {
if (!(obj instanceof MentaDependency)) return false;
MentaDependency d = (MentaDependency) obj;
if (!d.target.equals(this.target)) return false;
if (!d.klass.equals(this.klass)) 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, target, klass);
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;
}
}
/tags/menta-container-0.9.3/src/main/java/org/mentacontainer/impl/MentaComponent.java
New file
0,0 → 1,239
package org.mentacontainer.impl;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
 
import org.mentacontainer.ConfigurableComponent;
import org.mentacontainer.util.FindMethod;
 
/**
* A simple implementation of the Component interface.
*
* @author sergio.oliveira.jr@gmail.com
*/
public class MentaComponent implements ConfigurableComponent {
private final Class<? extends Object> klass;
private Map<String, Object> props = null;
private List<Object> initValues = null;
private Constructor<? extends Object> constructor = null;
private Map<String, Method> cache = null;
public MentaComponent(Class<? extends Object> klass) {
this.klass = klass;
}
public ConfigurableComponent addProperty(String name, Object value) {
if (props == null) {
props = new HashMap<String, Object>();
cache = new HashMap<String, Method>();
}
props.put(name, value);
return this;
}
public ConfigurableComponent addInitValue(Object value) {
if (initValues == null) {
initValues = new LinkedList<Object>();
}
initValues.add(value);
return this;
}
private Class<? extends Object>[] getClasses(List<Object> values) {
Class<? extends Object>[] types = (Class<? extends Object>[]) new Class[values.size()];
Iterator<Object> iter = values.iterator();
int index = 0;
while(iter.hasNext()) {
Object value = iter.next();
if (value != null) {
types[index++] = value.getClass();
} else {
types[index++] = null;
}
}
return types;
}
private Object [] getValues(List<Object> values) throws InstantiationException {
Object [] array = new Object[values.size()];
int index = 0;
Iterator<Object> iter = values.iterator();
while(iter.hasNext()) {
Object obj = iter.next();
array[index++] = obj;
}
return array;
}
/*
* Use reflection to set a property in the bean
*/
private void setValue(Object bean, String name, Object value) {
try {
StringBuffer sb = new StringBuffer(30);
sb.append("set");
sb.append(name.substring(0,1).toUpperCase());
if (name.length() > 1) sb.append(name.substring(1));
String methodName = sb.toString();
if (!cache.containsKey(name)) {
Method m = null;
try {
m = FindMethod.getMethod(klass, methodName, new Class[] { value.getClass() });
} catch(Exception e) {
// try primitive...
Class<? extends Object> primitive = getPrimitiveFrom(value);
if (primitive != null) {
try {
m = klass.getMethod(methodName, new Class[] { primitive });
} catch(Exception ex) {
// not found!
}
}
if (m == null) {
throw new InstantiationException("Cannot find method or field for property: " + name);
}
}
if (m != null) {
cache.put(name, m);
m.setAccessible(true);
}
}
 
Method m = cache.get(name);
if (m != null) {
m.invoke(bean, new Object[] { value });
}
} catch(Exception e) {
throw new RuntimeException("Error trying to set a property with reflection: " + name, e);
}
}
private static Class<? extends Object> getPrimitiveFrom(Object w) {
if (w instanceof Boolean) { return Boolean.TYPE; }
else if (w instanceof Byte) { return Byte.TYPE; }
else if (w instanceof Short) { return Short.TYPE; }
else if (w instanceof Character) { return Character.TYPE; }
else if (w instanceof Integer) { return Integer.TYPE; }
else if (w instanceof Long) { return Long.TYPE; }
else if (w instanceof Float) { return Float.TYPE; }
else if (w instanceof Double) { return Double.TYPE; }
return null;
}
public <T> T getInstance() {
Object obj = null;
if (initValues != null && initValues.size() > 0) {
if (constructor == null) {
try {
constructor = klass.getConstructor(getClasses(initValues));
} catch(Exception e) {
throw new RuntimeException("Cannot find a constructor for class: " + klass, e);
}
}
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);
}
}
if (props != null && props.size() > 0) {
Iterator<String> iter = props.keySet().iterator();
while(iter.hasNext()) {
String name = iter.next();
Object value = props.get(name);
setValue(obj, name, value);
}
}
return (T) obj;
}
}
/tags/menta-container-0.9.3/src/main/java/org/mentacontainer/impl/MentaContainer.java
New file
0,0 → 1,317
package org.mentacontainer.impl;
 
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
 
import org.mentacontainer.Component;
import org.mentacontainer.ConfigurableComponent;
import org.mentacontainer.Container;
import org.mentacontainer.Dependency;
import org.mentacontainer.Scope;
import org.mentacontainer.util.InjectionUtils;
import org.mentacontainer.util.InjectionUtils.Provider;
 
/**
* The implementation of the IoC container.
*
* @author sergio.oliveira.jr@gmail.com
*/
public class MentaContainer implements Container {
 
private Map<String, Component> beans = new HashMap<String, Component>();
private Map<String, Scope> scopes = new HashMap<String, Scope>();
private Map<String, Object> singletonsCache = new HashMap<String, Object>();
private Map<String, ThreadLocal<Object>> threadLocalsCache = new HashMap<String, ThreadLocal<Object>>();
 
private Set<Dependency> dependencies = new HashSet<Dependency>();
public synchronized void clear(Scope scope) {
if (scope == Scope.SINGLETON) {
singletonsCache.clear();
} else if (scope == Scope.THREAD) {
for(ThreadLocal<Object> t : threadLocalsCache.values()) {
t.set(null);
}
}
}
public synchronized <T> T clear(String key) {
if (!beans.containsKey(key)) return null;
Scope scope = scopes.get(key);
if (scope == Scope.SINGLETON) {
return (T) singletonsCache.remove(key);
} else if (scope == Scope.THREAD) {
ThreadLocal<Object> t = threadLocalsCache.get(key);
if (t != null) {
Object o = t.get();
if (o != null) {
t.set(null);
return (T) o;
}
}
return null;
} else if (scope == Scope.NONE) {
return null; // always...
} else {
throw new UnsupportedOperationException("Scope not supported: " + scope);
}
}
 
public synchronized <T> T get(String key) {
 
if (!beans.containsKey(key)) return null;
 
Component c = beans.get(key);
Scope scope = scopes.get(key);
Object target = null;
 
try {
 
if (scope == Scope.SINGLETON) {
 
if (singletonsCache.containsKey(key)) {
 
target = singletonsCache.get(key);
 
return (T) target; // no need to wire again...
 
} else {
 
target = c.getInstance();
 
singletonsCache.put(key, target);
}
} else if (scope == Scope.THREAD) {
if (threadLocalsCache.containsKey(key)) {
ThreadLocal<Object> t = threadLocalsCache.get(key);
target = t.get();
if (target == null) { // different thread...
target = c.getInstance();
t.set(target);
// don't return... let it be wired...
} else {
return (T) target; // no need to wire again...
}
} else {
ThreadLocal<Object> t = new ThreadLocal<Object>();
target = c.getInstance();
t.set(target);
threadLocalsCache.put(key, t);
// let it be wired...
}
} else if (scope == Scope.NONE) {
 
target = c.getInstance();
 
} else {
throw new UnsupportedOperationException("Don't know how to handle scope: " + scope);
}
 
if (target != null) {
 
for (Dependency d : dependencies) {
 
// has dependency ?
Method m = d.check(target.getClass());
 
if (m != null) {
 
String sourceKey = d.getSource();
 
if (sourceKey.equals(key)) {
 
// cannot depend on itself... also avoid recursive StackOverflow...
 
continue;
 
}
 
Object source = get(sourceKey);
 
boolean isAssignable = source != null && d.getType().isAssignableFrom(source.getClass());
 
// check if we can find the dependency and if it is
// assignable to the target dependency
if (isAssignable) {
 
try {
 
// inject
m.invoke(target, source);
 
} catch (Exception e) {
 
throw new RuntimeException("Cannot inject dependency: method = " + (m != null ? m.getName() : "NULL") + " / source = "
+ (source != null ? source : "NULL") + " / target = " + target, e);
 
}
 
}
}
}
}
 
return (T) target; // return target nicely with all the dependencies
 
} catch (Exception e) {
 
throw new RuntimeException(e);
}
}
 
public Component ioc(String key, Component component, Scope scope) {
beans.put(key, component);
singletonsCache.remove(key); // just in case we are overriding a previous singleton bean...
threadLocalsCache.remove(key); // just in case we are overriding a previous thread local...
scopes.put(key, scope);
return component;
}
public Component ioc(String key, Component component) {
return ioc(key, component, Scope.NONE);
}
public ConfigurableComponent ioc(String key, Class<? extends Object> klass) {
ConfigurableComponent cc = new MentaComponent(klass);
ioc(key, cc);
return cc;
}
public ConfigurableComponent ioc(String key, Class<? extends Object> klass, Scope scope) {
ConfigurableComponent cc = new MentaComponent(klass);
ioc(key, cc, scope);
return cc;
}
 
public Dependency autowire(Dependency d) {
 
dependencies.add(d);
 
return d;
}
 
public Dependency autowire(String property, Class<? extends Object> klass) {
return autowire(property, klass, property);
}
public Dependency autowire(String property, Class<? extends Object> klass, String source) {
return autowire(new MentaDependency(property, klass, source));
}
 
public Container populate(Object bean) {
Provider p = new Provider() {
public Object get(String key) {
return MentaContainer.this.get(key);
}
public boolean hasValue(String key) {
return MentaContainer.this.check(key);
}
};
try {
 
InjectionUtils.getObject(bean, p, false, null, true, false, true);
} catch(Exception e) {
throw new RuntimeException("Error populating bean: " + bean, e);
}
 
return this;
}
 
public synchronized boolean check(String key) {
if (!beans.containsKey(key)) return false;
Scope scope = scopes.get(key);
if (scope == Scope.NONE) {
return false; // always...
} else if (scope == Scope.SINGLETON) {
return singletonsCache.containsKey(key);
} else if (scope == Scope.THREAD) {
ThreadLocal<Object> t = threadLocalsCache.get(key);
return t.get() != null;
} else {
throw new UnsupportedOperationException("This scope is not supported: " + scope);
}
}
}
/tags/menta-container-0.9.3/src/main/java/org/mentacontainer/Component.java
New file
0,0 → 1,16
package org.mentacontainer;
 
/**
* An IoC component that knows how to create instances of itself.
*
* @author sergio.oliveira.jr@gmail.com
*/
public interface Component {
/**
* Instantiate the bean.
*
* @return The instantiated bean based on the container configuration.
*/
public <T> T getInstance();
}
/tags/menta-container-0.9.3/src/main/java/org/mentacontainer/Container.java
New file
0,0 → 1,147
package org.mentacontainer;
 
/**
* A very simple container that provides:
* <ul>
* <li> Bean instantiation (duh!)</li>
* <li> Constructor injection for bean setup</li>
* <li> Setter injection for bean setup</li>
* <li> Auto-wiring based on name and type</li>
* <li> Scopes: Singleton and ThreadLocal</li>
* <li> Wiring of external beans with the beans configured in this container</li>
* <li> Annotation and XML free (programmatic configuration is the way to go!)
* </ul>
*
* It does not get much simpler than that.
*
* @author sergio.oliveira.jr@gmail.com
*
*/
public interface Container {
/**
* Get an instance from the container.
*
* The instance will be fully initialized (constructor and/or setters) and fully wired.
*
* @param key The key representing the bean to return. The name of the bean in the container.
* @return The fully initialized and wired bean.
*/
public <T> T get(String key);
/**
* Configure a bean to be returned with the given implementation when {@link #get(String)} is called.
*
* @param key The key representing the bean to return. The name of the bean in the container.
* @param klass The class used to instantiate the bean, in other words, its implementation.
* @param scope The scope of the component.
* @return The component created as a ConfigurableComponent. (Fluent API)
* @see Scope
*/
public ConfigurableComponent ioc(String key, Class<? extends Object> klass, Scope scope);
/**
* Same as {@link #ioc(String, Class, Scope)} except that it assumes
* there is no scope (Scope.NONE).
*
* @param key
* @param klass
* @return The component created as a ConfigurableComponent. (Fluent API)
* @see Scope
*/
public ConfigurableComponent ioc(String key, Class<?extends Object> klass);
/**
* Set up IoC based on the component passed. The scope assumed is NONE.
*
* @param key The key representing the bean to return. The name of the bean in the container.
* @param component The component for the IoC.
* @return The component passed as a parameter.
* @see Component
*/
public Component ioc(String key, Component component);
/**
* Set up IoC based on the component passed. Specify the scope of the component.
*
* @param key The key representing the bean to return. The name of the bean in the container.
* @param component The component for the IoC.
* @param scope The scope used by the component.
* @return The component passed as a parameter.
* @see Component
* @see Scope
*/
public Component ioc(String key, Component component, Scope scope);
/**
* Configure a bean dependency to be auto-wired by the container. In general you want the
* type of the dependency to be an interface, for loosely couple dependencies. It works like that:<br/><br/>
*
* Whenever the container returns a bean, it checks to see if it has a property named <i>property</i>
* and if the type of the property is <i>klass</i>. If it does, then it looks for a bean named
* <i>source</i> and injects it inside the first bean it is returning. This approach is recursive
* so all properties are checked up the class hierarchy, until it reaches Object.
*
* @param property a bean property that will require another bean, in other words, the required
* bean will be injected in the property of the bean been requested from the container. (auto-wiring by name)
* @param klass the type of the dependency, in other words, the type of the auto-wiring. (auto-wiring by type)
* @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 Dependency autowire(String property, Class<? extends Object> klass, String source);
/**
* Same as {@link #autowire(String, Class, String)} except that it assumes that the property name will be the source name, in other words,
* the property name is the same as the bean name that will be injected as the dependency.
*
* @param property
* @param klass
* @return The container itself. (Fluent API)
*/
public Dependency autowire(String property, Class<? extends Object> klass);
/**
* Setup a dependency.
*
* @param dependency The dependency to setup
* @return The dependency itself. (Fluent API)
* @see Dependency
*/
public Dependency autowire(Dependency dependency);
/**
* Take a given bean and populate its properties with other beans coming from this container. Perhaps you can call this auto-wiring.
* You basically checking properties of the given bean and looking for values (by name and type!) inside the container. And injecting
* in the given bean, in other words, populating it.
*
* @param bean The bean to be populated with other beans from the container.
* @return The container itself. (Fluent API)
*/
public Container populate(Object bean);
/**
* Check whether the container currently has a value for this key. For example,
* if it is a singleton AND someone has requested it, the container will have it cached.
* The method is useful to check for an instance without forcing her creation.
*
* @param key The key representing the bean inside the container.
* @return true if the container has an instance cached in the scope for this key
*/
public boolean check(String key);
/**
* Clear all cached instances for that scope. If you have a thread pool for example you will
* have to clear the THREAD scope when your thread is returned to the pool.
*
* @param scope The scope to be cleared.
*/
public void clear(Scope scope);
/**
* Clear a single key from cache and return the instance that was cached.
*
* @param key The key representing the bean inside the container.
* @return The value that was cached and it is not anymore (was cleared)
*/
public <T> T clear(String key);
}
/tags/menta-container-0.9.3/src/main/java/org/mentacontainer/ConfigurableComponent.java
New file
0,0 → 1,29
package org.mentacontainer;
 
/**
* An IoC component that knows how to create instances of itself and
* can be configured by accepting values for its constructor
* and properties for its setters.
*
* @author sergio.oliveira.jr@gmail.com
*/
public interface ConfigurableComponent extends Component {
/**
* Add a constructor parameter to be used when the bean is instantiated. It can be called more than once to
* use constructors with more than one argument.
*
* @param value A parameter value to be used by a constructor.
* @return The component itself. (Fluent API)
*/
public ConfigurableComponent addInitValue(Object value);
/**
* Add a property to be injected through a setter when the component is instantiated.
*
* @param name The property name.
* @param value The property value.
* @return The component itself. (Fluent API)
*/
public ConfigurableComponent addProperty(String name, Object value);
}
/tags/menta-container-0.9.3/src/main/java/org/mentacontainer/Scope.java
New file
0,0 → 1,19
package org.mentacontainer;
 
public enum Scope {
/**
* The container calls component.get() on every request for the component, returning always new instances.
*/
NONE,
/**
* The container calls component.get() only once and caches the value, returning always the same instance.
*/
SINGLETON,
/**
* The container calls component.get() and caches the value on a thread local, so the same thread will always get the same instance.
*/
THREAD
}
/tags/menta-container-0.9.3/src/main/java/org/mentacontainer/example/BasicOperations.java
New file
0,0 → 1,139
package org.mentacontainer.example;
 
import java.util.Date;
 
import org.mentacontainer.Container;
import org.mentacontainer.Scope;
import org.mentacontainer.impl.MentaContainer;
 
public class BasicOperations {
public static void main(String[] args) {
case1();
case2();
case3();
case4();
}
private static void case1() {
Container c = new MentaContainer();
c.ioc("myString1", String.class);
String myString1 = c.get("myString1");
System.out.println(myString1); // ==> "" ==> default constructor new String() was used
c.ioc("myString2", String.class).addInitValue("saoj");
String myString2 = c.get("myString2");
System.out.println(myString2); // ==> "saoj" ==> constructor new String("saoj") was used
c.ioc("myDate1", Date.class).addProperty("hours", 15) // setHours(15)
.addProperty("minutes", 10) // setMinutes(10)
.addProperty("seconds", 45); // setSeconds(45)
Date myDate1 = c.get("myDate1");
System.out.println(myDate1); // ==> a date with time 15:10:45
}
private static void case2() {
Container c = new MentaContainer();
c.ioc("myString", String.class, Scope.SINGLETON).addInitValue("saoj");
String s1 = c.get("myString");
String s2 = c.get("myString");
System.out.println(s1 == s2); // ==> true ==> same instance
System.out.println(s1.equals(s2)); // ==> true => of course
}
public static interface UserDAO {
public String getUsername(int id);
}
public static class Connection {
}
public static class JdbcUserDAO implements UserDAO {
private Connection conn;
public void setConn(Connection conn) { this.conn = conn; }
public String getUsername(int id) {
// connection will be injected by the container...
if (conn == null) throw new IllegalStateException("conn is null!");
// use the connection to get the username...
return "saoj";
}
}
private static void case3() {
Container c = new MentaContainer();
c.ioc("userDAO", JdbcUserDAO.class);
c.ioc("connection", Connection.class); // in real life this would be a connection pool
// or the hibernate SessionFactory
// "conn" = the name of the property
// Connection.class = the type of the property
// "connection" = the source from where the dependency will come from
c.autowire("conn", Connection.class, "connection");
UserDAO userDAO = c.get("userDAO");
// the container detects that userDAO has a dependency: name = "conn" and type = "Connection.class"
// where does it go to get the dependency to insert?
// In itself: it does a Container.get("connection") => "connection" => the source
System.out.println(userDAO.getUsername(11)); // ==> "saoj" ==> connection is not null as expected...
}
public static class SomeService {
private UserDAO userDAO;
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
public void doSomething() {
System.out.println(userDAO.getUsername(11));
}
}
private static void case4() {
Container c = new MentaContainer();
c.ioc("userDAO", JdbcUserDAO.class);
c.ioc("connection", Connection.class);
c.autowire("conn", Connection.class, "connection");
SomeService service = new SomeService();
c.populate(service); // populate (inject) all properties of SomeService with
// beans from the container
service.doSomething(); // ==> "saoj"
}
}
/tags/menta-container-0.9.3/src/main/java/org/mentacontainer/util/FindMethod.java
New file
0,0 → 1,144
package org.mentacontainer.util;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
 
/**
* Find method with polymorphism!
* Class.getMethod only finds an exact match.
*
* @author Jon Skeet (http://groups.google.com/group/comp.lang.java.programmer/browse_thread/thread/921ab91865c8cc2e/9e141d3d62e7cb3f)
*/
public class FindMethod {
 
/**
* Finds the most specific applicable method
*
* @param source Class to find method in
* @param name Name of method to find
* @param parameterTypes Parameter types to search for
*/
public static Method getMethod(Class<? extends Object> source,
String name,
Class[] parameterTypes)
throws NoSuchMethodException {
return internalFind(source.getMethods(),
name,
parameterTypes);
}
 
/**
* Finds the most specific applicable declared method
*
* @param source Class to find method in
* @param name Name of method to find
* @param parameterTypes Parameter types to search for
*/
public static Method getDeclaredMethod(Class source,
String name,
Class[] parameterTypes)
throws NoSuchMethodException {
return internalFind(source.getDeclaredMethods(),
name,
parameterTypes);
}
 
/**
* Internal method to find the most specific applicable method
*/
private static Method internalFind(Method[] toTest,
String name,
Class[] parameterTypes)
throws NoSuchMethodException {
int l = parameterTypes.length;
 
// First find the applicable methods
List<Method> applicableMethods = new LinkedList<Method>();
 
for (int i = 0; i < toTest.length; i++) {
// Check the name matches
if (!toTest[i].getName().equals(name))
continue;
// Check the parameters match
Class[] 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 method: " + name);
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
Method current = applicableMethods.get(i);
Class[] currentParams = current.getParameterTypes();
Class 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();
 
// 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);
}
 
}
/tags/menta-container-0.9.3/src/main/java/org/mentacontainer/util/InjectionUtils.java
New file
0,0 → 1,806
package org.mentacontainer.util;
 
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
 
public class InjectionUtils {
 
/**
* The character used to separate the prefix from the value name when you are using the getObject method with a prefix. You can change the value of this prefix if you want to
* by changing this static variable.
*
* Ex: getObject(User.class, "user") will get all values that begin with "user.".
*/
public static char PREFIX_SEPARATOR = '.';
 
private static Map<Class<? extends Object>, Map<String, Object>> settersMaps = new HashMap<Class<? extends Object>, Map<String, Object>>();
 
private static Map<Class<? extends Object>, Map<String, Object>> fieldsMaps = new HashMap<Class<? extends Object>, Map<String, Object>>();
 
public static void prepareForInjection(Class<? extends Object> klass, Map<String, Object> setters, Map<String, Object> fields) {
 
StringBuffer sb = new StringBuffer(32);
 
Method[] methods = klass.getMethods();
 
for (int i = 0; i < methods.length; i++) {
 
Method m = methods[i];
 
String name = m.getName();
 
Class<?>[] types = m.getParameterTypes();
 
if (name.startsWith("set") && name.length() > 3 && types.length == 1) {
 
String var = name.substring(3);
 
if (var.length() > 1) {
 
sb.delete(0, sb.length());
 
sb.append(var.substring(0, 1).toLowerCase());
 
sb.append(var.substring(1));
 
var = sb.toString();
 
} else {
 
var = var.toLowerCase();
}
 
m.setAccessible(true);
 
if (setters.containsKey(var)) {
 
Object obj = setters.get(var);
 
if (obj instanceof List) {
 
List<Method> list = (List<Method>) obj;
 
list.add(m);
 
} else if (obj instanceof Method) {
 
List<Method> list = new ArrayList<Method>();
 
list.add((Method) obj);
 
list.add(m);
 
setters.put(var, list);
 
}
 
} else {
 
setters.put(var, m);
 
}
}
}
 
if (fields == null) return;
 
Field[] f = klass.getDeclaredFields();
 
for (int i = 0; i < f.length; i++) {
 
Field field = f[i];
 
field.setAccessible(true);
 
String name = field.getName();
 
if (setters.containsKey(name)) {
 
Object obj = setters.get(name);
 
if (obj instanceof Method) {
 
Method m = (Method) obj;
 
Class<?>[] types = m.getParameterTypes();
 
Class<?> type = field.getType();
 
if (type.isAssignableFrom(types[0])) continue;
 
} else if (obj instanceof List) {
 
List<Method> list = (List<Method>) obj;
 
Iterator<Method> iter = list.iterator();
 
boolean found = false;
 
while (iter.hasNext()) {
 
Method m = iter.next();
 
Class<?>[] types = m.getParameterTypes();
 
Class<?> type = field.getType();
 
if (type.isAssignableFrom(types[0])) {
 
found = true;
 
break;
}
}
 
if (found) continue;
}
}
 
fields.put(name, field);
 
}
}
 
public static boolean checkPrimitives(Class<? extends Object> target, Class<? extends Object> source) {
 
if (target.equals(int.class) && source.equals(Integer.class)) return true;
 
if (target.equals(boolean.class) && source.equals(Boolean.class)) return true;
 
if (target.equals(byte.class) && source.equals(Byte.class)) return true;
 
if (target.equals(short.class) && source.equals(Short.class)) return true;
 
if (target.equals(char.class) && source.equals(Character.class)) return true;
 
if (target.equals(long.class) && source.equals(Long.class)) return true;
 
if (target.equals(float.class) && source.equals(Float.class)) return true;
 
if (target.equals(double.class) && source.equals(Double.class)) return true;
 
return false;
 
}
 
public static Object tryToConvert(Object source, Class<? extends Object> targetType) {
 
return tryToConvert(source, targetType, false);
}
 
public static Object tryToConvert(Object source, Class<?> targetType, boolean tryNumber) {
 
String value = null;
 
if (source instanceof String) {
 
value = (String) source;
 
} else if (tryNumber && source instanceof Number) {
 
value = source.toString();
 
} else {
 
return null;
}
 
Object newValue = null;
 
String className = targetType.getName();
 
if (className.equals("int") || className.equals("java.lang.Integer")) {
int x = -1;
try {
x = Integer.parseInt(value);
} catch (Exception e) {
return null;
}
newValue = new Integer(x);
} else if (className.equals("short") || className.equals("java.lang.Short")) {
short x = -1;
try {
x = Short.parseShort(value);
} catch (Exception e) {
return null;
}
newValue = new Short(x);
 
} else if (className.equals("char") || className.equals("java.lang.Character")) {
 
if (value.length() != 1) {
return null;
}
 
newValue = new Character(value.charAt(0));
 
} else if (className.equals("long") || className.equals("java.lang.Long")) {
long x = -1;
try {
x = Long.parseLong(value);
} catch (Exception e) {
return null;
}
newValue = new Long(x);
} else if (className.equals("float") || className.equals("java.lang.Float")) {
float x = -1;
try {
x = Float.parseFloat(value);
} catch (Exception e) {
return null;
}
newValue = new Float(x);
} else if (className.equals("double") || className.equals("java.lang.Double")) {
double x = -1;
try {
x = Double.parseDouble(value);
} catch (Exception e) {
return null;
}
newValue = new Double(x);
} else if (className.equals("boolean") || className.equals("java.lang.Boolean")) {
try {
int x = Integer.parseInt(value);
if (x == 1) {
newValue = Boolean.TRUE;
} else if (x == 0) {
newValue = Boolean.FALSE;
} else {
return null;
}
} catch (Exception e) {
if (value.equalsIgnoreCase("true") || value.equals("on")) {
newValue = Boolean.TRUE;
} else if (value.equalsIgnoreCase("false")) {
newValue = Boolean.FALSE;
} else {
return null;
}
}
} else if (targetType.isEnum()) {
 
try {
Class k = (Class) targetType; // not sure how to avoid this raw type!
 
newValue = Enum.valueOf(k, value);
 
} catch (Exception e) {
 
return null;
}
 
}
 
return newValue;
 
}
 
public static Object shouldConvertToNull(Object value, Class<? extends Object> targetType) {
 
if (targetType.equals(String.class)) {
 
return value;
 
} else if (targetType.isPrimitive()) {
 
return value;
}
 
return null;
}
 
public static Class<? extends Object> getPrimitiveFrom(Object w) {
if (w instanceof Boolean) {
return Boolean.TYPE;
} else if (w instanceof Byte) {
return Byte.TYPE;
} else if (w instanceof Short) {
return Short.TYPE;
} else if (w instanceof Character) {
return Character.TYPE;
} else if (w instanceof Integer) {
return Integer.TYPE;
} else if (w instanceof Long) {
return Long.TYPE;
} else if (w instanceof Float) {
return Float.TYPE;
} else if (w instanceof Double) {
return Double.TYPE;
}
return null;
}
 
public static Class<? extends Object> getPrimitiveFrom(Class<? extends Object> klass) {
 
String s = klass.getName();
 
if (s.equals("java.lang.Boolean")) {
return Boolean.TYPE;
} else if (s.equals("java.lang.Byte")) {
return Byte.TYPE;
} else if (s.equals("java.lang.Short")) {
return Short.TYPE;
} else if (s.equals("java.lang.Character")) {
return Character.TYPE;
} else if (s.equals("java.lang.Integer")) {
return Integer.TYPE;
} else if (s.equals("java.lang.Long")) {
return Long.TYPE;
} else if (s.equals("java.lang.Float")) {
return Float.TYPE;
} else if (s.equals("java.lang.Double")) {
return Double.TYPE;
}
return null;
}
 
public static Field getField(Object target, String name) {
return getField(target.getClass(), name);
}
 
public static Field getField(Class<? extends Object> target, String name) {
Field fields[] = target.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
if (name.equals(fields[i].getName())) {
return fields[i];
}
}
return null;
}
 
public static Method findMethodToGet(Class<? extends Object> target, String name) {
 
StringBuffer sb = new StringBuffer(128);
 
sb.append("get").append(name.substring(0, 1).toUpperCase());
 
if (name.length() > 1) sb.append(name.substring(1));
 
try {
 
return target.getMethod(sb.toString(), (Class[]) null);
 
} catch (Exception e) {
 
}
 
sb.setLength(0);
 
sb.append("is").append(name.substring(0, 1).toUpperCase());
 
if (name.length() > 1) {
 
sb.append(name.substring(1));
}
 
try {
 
return target.getMethod(sb.toString(), (Class[]) null);
 
} catch (Exception e) {
 
}
 
return null;
}
 
public static Method findMethodToInject(Class<? extends Object> target, String name, Class<? extends Object> source) {
 
StringBuffer sb = new StringBuffer(128);
 
sb.append("set").append(name.substring(0, 1).toUpperCase());
 
if (name.length() > 1) sb.append(name.substring(1));
 
String methodName = sb.toString();
 
Method m = null;
 
try {
 
m = FindMethod.getMethod(target, methodName, new Class[] { source });
 
} catch (Exception e) {
}
 
if (m == null) {
 
Class<? extends Object> primitive = getPrimitiveFrom(source);
 
if (primitive != null) {
 
try {
 
m = target.getMethod(methodName, new Class[] { primitive });
 
} catch (Exception e) {
}
 
}
}
 
if (m != null) {
m.setAccessible(true);
}
 
return m;
 
}
 
public static Field findFieldToInject(Class<? extends Object> target, String name, Class<? extends Object> source) {
 
Field f = getField(target, name);
 
if (f != null) {
 
Class<?> type = f.getType();
 
if (type.isAssignableFrom(source) || checkPrimitives(type, source)) {
 
f.setAccessible(true);
 
return f;
}
 
}
 
return null;
}
 
private static final boolean isBlank(Object value) {
 
if (value != null && value instanceof String) {
 
String s = ((String) value).trim();
 
if (s.length() == 0) return true;
}
 
return false;
}
 
public static boolean inject(Method m, Object target, Object value, boolean tryToConvert, boolean tryingToConvertBoolean) throws Exception {
 
Class<?> type = m.getParameterTypes()[0];
 
if (tryingToConvertBoolean) {
 
if (value == null && (type.equals(Boolean.class) || type.equals(boolean.class))) {
 
value = Boolean.FALSE;
 
} else {
 
// if trying to convert boolean, convert or don't do anything...
 
return false;
 
}
}
 
if (value == null
|| (type.isAssignableFrom(value.getClass()) || checkPrimitives(type, value.getClass()) || (tryToConvert && ((isBlank(value) && (value = shouldConvertToNull(value,
type)) == null) || (value = tryToConvert(value, type)) != null)))) {
 
try {
 
m.invoke(target, new Object[] { value });
 
return true;
 
} catch (Exception e) {
 
System.err.println("Error injecting by method: " + value + " in " + target + " thru " + m);
 
e.printStackTrace();
 
throw e;
 
}
}
 
return false;
 
}
 
public static boolean hasDefaultConstructor(Class<? extends Object> klass) {
 
try {
 
return klass.getConstructor((Class[]) null) != null;
 
} catch (Exception e) {
 
return false;
}
}
 
/**
* Extract the value of a property of a bean!
*
* @param bean
* the target bean
* @param nameProperty
* the property name
* @return they value as String. The method toString is always called to every property!
* @throws Exception
*/
public static String getProperty(Object bean, String nameProperty) throws Exception {
 
if (nameProperty == null || nameProperty.equals("")) return null;
 
String methodName = getter(nameProperty);
 
Class<? extends Object> clazz = bean.getClass();
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == 0) {
Object value = method.invoke(bean, (Object[]) null);
if (value == null) return null;
return value.toString();
}
}
 
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if (field.getName().equals(nameProperty)) {
Object value = field.get(bean);
if (value == null) return null;
return value.toString();
}
}
 
return null;
}
 
private static String getter(String name) {
StringBuilder sb = new StringBuilder(name.length() + 3);
 
sb.append("get").append(name.substring(0, 1).toUpperCase());
 
if (name.length() > 1) sb.append(name.substring(1));
return sb.toString();
}
 
public static void beanToMap(Object bean, Map<String, String> map) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if (bean != null) {
 
for (Method method : bean.getClass().getMethods()) {
String name = method.getName();
 
if (name.length() > 3 && name.startsWith("get") && !name.equals("getClass") && method.getParameterTypes().length == 0) {
 
method.setAccessible(true);
Object value = method.invoke(bean, new Object[0]);
map.put(name, value.toString());
}
}
}
}
public static interface Provider {
public Object get(String key);
public boolean hasValue(String key);
}
 
public static void getObject(Object target, Provider provider, boolean tryField, String prefix, boolean tryToConvert, boolean convertBoolean, boolean allowRecursion)
throws Exception {
 
Class<? extends Object> targetClass = target.getClass();
 
Map<String, Object> setters, fields;
 
// see if we have these in cache...
 
synchronized (settersMaps) {
 
setters = settersMaps.get(targetClass);
 
fields = fieldsMaps.get(targetClass);
 
}
 
// if not in cache, prepare maps for injection...
 
if (setters == null) {
 
setters = new HashMap<String, Object>();
 
fields = null;
 
if (tryField) {
 
fields = new HashMap<String, Object>();
 
}
 
prepareForInjection(targetClass, setters, fields);
 
synchronized (settersMaps) {
 
settersMaps.put(targetClass, setters);
 
fieldsMaps.put(targetClass, fields);
 
}
}
 
Iterator<String> iter = setters.keySet().iterator();
 
while (iter.hasNext()) {
 
String var = iter.next();
 
boolean hasValue = provider.hasValue(var);
 
Object value = provider.get(var);
 
boolean tryingToConvertBoolean = false;
 
if (value == null && !hasValue) {
 
if (!convertBoolean) {
 
continue;
 
} else {
 
tryingToConvertBoolean = true;
}
 
}
 
// if (value == null) continue;
 
Object obj = setters.get(var);
 
// we may have a list of overloaded methods...
 
List<Method> list = null;
 
Method m = null;
 
if (obj instanceof List) {
 
list = (List<Method>) obj;
 
} else {
 
m = (Method) setters.get(var);
 
}
 
if (m != null) {
 
if (!inject(m, target, value, tryToConvert, tryingToConvertBoolean) && allowRecursion) {
 
// i did not inject... how about a VO object for this
// setter?
 
Class<?> type = m.getParameterTypes()[0];
 
if (!type.getName().startsWith("java.") && !type.isPrimitive() && hasDefaultConstructor(type)) {
 
Object param = type.newInstance();
 
InjectionUtils.getObject(param, provider, true, prefix, true, true, false); // no
// recursion...
 
inject(m, target, param, false, false);
}
}
 
} else {
 
Iterator<Method> it = list.iterator();
 
boolean injected = false;
 
while (it.hasNext()) {
 
m = it.next();
 
if (inject(m, target, value, tryToConvert, tryingToConvertBoolean)) {
 
injected = true;
 
break;
}
}
 
if (!injected && allowRecursion) {
 
// i could not inject anything... how about a VO object for
// this setter...
 
it = list.iterator();
 
while (it.hasNext()) {
 
m = (Method) it.next();
 
Class<?> type = m.getParameterTypes()[0];
 
if (!type.getName().startsWith("java.") && !type.isPrimitive() && hasDefaultConstructor(type)) {
 
Object param = type.newInstance();
 
InjectionUtils.getObject(param, provider, true, prefix, true, true, false); // no
// recursion...
 
if (inject(m, target, param, false, false)) {
 
break; // done...
}
}
}
}
}
}
 
if (fields != null) {
 
iter = fields.keySet().iterator();
 
while (iter.hasNext()) {
 
String var = iter.next();
 
boolean hasValue = provider.hasValue(var);
 
Object value = provider.get(var);
 
Field f = (Field) fields.get(var);
 
Class<?> type = f.getType();
 
// If there is no value in the action input, assume false for
// booleans...
// (checkboxes and radio buttons are not send when not
// marked...)
 
if (convertBoolean && value == null && !hasValue) {
 
if (type.equals(Boolean.class) || type.equals(boolean.class)) {
 
value = Boolean.FALSE;
}
 
}
 
if (value == null && !hasValue) continue;
 
// if (value == null) continue;
 
if (value == null
|| (type.isAssignableFrom(value.getClass()) || checkPrimitives(type, value.getClass()) || (tryToConvert && ((isBlank(value) && (value = shouldConvertToNull(
value, type)) == null) || (value = tryToConvert(value, type)) != null)))) {
 
try {
 
f.set(target, value);
 
} catch (Exception e) {
 
System.err.println("Error injecting by field: " + value + " in " + target);
 
e.printStackTrace();
 
throw e;
 
}
}
}
}
}
}
/tags/menta-container-0.9.3/src/main/java/org/mentacontainer/Dependency.java
New file
0,0 → 1,43
package org.mentacontainer;
 
import java.lang.reflect.Method;
 
/**
* A dependency used to setup auto-wiring based on name (target) and type. You also provide the source which is
* the name of a component configured in the container that will be injected as a dependency.
*
* @author sergio.oliveira.jr@gmail.com
*/
public interface Dependency {
/**
* The target, in other words, the name of the property which depends on something.
*
* @return The name of the property that needs to receive a dependency
*/
public String getTarget();
/**
* The type, in other words, the type of the property which depends on something.
*
* @return The type of the property that needs to receive a dependency
*/
public Class<? extends Object> getType();
/**
* The source component that will be used to fulfill the dependency, in other words,
* a component with this name will be fetched from the container and inserted in the target.
*
* @return The name of the component from the container that will fulfill the dependency
*/
public String getSource();
/**
* Check whether the given class has this dependency, in other words, whether it has a property
* with the name <i>'target'</i> and the type <i>'type'</i>.
*
* @param targetClass The class to be checked for this dependency
* @return A method, in this case a setter, that can be used to insert the dependency, or null if the class does not have this dependency
*/
public Method check(Class<? extends Object> targetClass);
}
/tags/menta-container-0.9.3/pom.xml
New file
0,0 → 1,166
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<properties>
<build.final.name>mentacontainer</build.final.name>
<svn.url>svn://saoj-la.dyndns.org/mentacontainer/trunk</svn.url>
<svn.tags>svn://saoj-la.dyndns.org/mentacontainer/tags</svn.tags>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<modelVersion>4.0.0</modelVersion>
<groupId>me.soliveirajr</groupId>
<artifactId>menta-container</artifactId>
<version>0.9.3</version>
<packaging>jar</packaging>
<description>A IoC container as simple and pragmatic as it can get with programmatic configuration through a Fluent API.</description>
 
<name>MentaContainer</name>
<url>http://maven.apache.org</url>
<licenses>
<license>
<name>GNU Lesser General Public License (LGPL), Version 2.1</name>
<url>http://www.fsf.org/licensing/licenses/lgpl.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>3</version>
</parent>
<scm>
<developerConnection>scm:svn:svn://saoj-la.dyndns.org/mentacontainer/tags/menta-container-0.9.3</developerConnection>
<url>svn://saoj-la.dyndns.org/mentacontainer/tags/menta-container-0.9.3</url>
<connection>scm:svn:svn://saoj-la.dyndns.org/mentacontainer/tags/menta-container-0.9.3</connection>
</scm>
<reporting>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.7</version>
<configuration>
...
</configuration>
</plugin>
</plugins>
</reporting>
<profiles>
<profile>
<id>release-sign-artifacts</id>
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<!-- distributionManagement>
<repository>
<id>nexus-releases</id>
<name>Nexus Release Repository</name>
<url>http://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${build.final.name}</finalName>
<plugins>
<!-- plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.0</version>
<configuration>
<tagBase>${svn.tags}</tagBase>
<connectionUrl>scm:svn:${svn.url}</connectionUrl>
</configuration>
</plugin>
</plugins>
</build>
</project>
/tags/menta-container-0.9.3/readme.txt
New file
0,0 → 1,2
MentaContainer 2010
 
/tags/menta-container-0.9.3
Property changes:
Added: svn:ignore
+ target
.classpath
.project
.settings