MentaContainer

Compare Revisions

Regard whitespace Rev 3 → Rev 4

/trunk/src/test/java/org/mentacontainer/impl/MentaContainerTest.java
New file
0,0 → 1,103
package org.mentacontainer.impl;
 
import junit.framework.Assert;
 
import org.junit.Test;
import org.mentacontainer.Container;
 
public class MentaContainerTest {
@Test
public void testSimpleGet() {
Container c = new MentaContainer();
c.ioc("myStr", String.class);
Assert.assertEquals("", c.get("myStr"));
String s1 = (String) c.get("myStr");
String s2 = (String) 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);
c.init("myStr", "hello");
Assert.assertEquals("hello", c.get("myStr"));
String s1 = (String) c.get("myStr");
String s2 = (String) c.get("myStr");
Assert.assertTrue(s1 != s2);
Assert.assertTrue(s1.equals(s2));
c.ioc("anotherStr", String.class);
c.init("anotherStr", "hi");
String s3 = (String) 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, true);
c.init("myStr", "hello");
Assert.assertEquals("hello", c.get("myStr"));
String s1 = (String) c.get("myStr");
String s2 = (String) c.get("myStr");
Assert.assertTrue(s1 == s2);
Assert.assertTrue(s1.equals(s2));
}
@Test(expected = RuntimeException.class)
public void testAddingComponentTwice() {
Container c = new MentaContainer();
c.ioc("myStr", String.class).ioc("myStr", String.class);
}
@Test(expected = RuntimeException.class)
public void testSettingWiringTwice() {
Container c = new MentaContainer();
c.autowire("myThread", Runnable.class);
c.autowire("myThread", Runnable.class);
}
@Test(expected = RuntimeException.class)
public void testAddingWiringNoInterface() {
Container c = new MentaContainer();
c.autowire("myThread", Thread.class);
}
}
/trunk/src/main/java/org/mentacontainer/impl/MentaContainer.java
7,6 → 7,7
import java.util.Set;
 
import org.mentacontainer.Container;
import org.mentacontainer.util.InjectionUtils;
 
public class MentaContainer implements Container {
56,19 → 57,12
if (m != null) {
boolean hasAlreadyReceived = d.hasAlreadyReceived(target);
// has already received the dependency?
if (!hasAlreadyReceived) {
String sourceKey = d.getSource();
// get dependency from action input
if (sourceKey.equals(key)) {
// cannot depend on itself...
// also avoid recusive StackOverflow...
// also avoid recursive StackOverflow...
continue;
78,39 → 72,30
boolean isAssignable = source != null && d.getDependencyClass().isAssignableFrom(source.getClass());
// check if we can find the dependency and if it is assignable to the target dependency
// check if we can find the dependency and if it is
// assignable to the target dependency
if (isAssignable) {
try {
// inject
m.invoke(target, source);
// flag it has received
d.setAlreadyReceived(target);
} catch(Exception e) {
throw new RuntimeException("Cannot inject dependency: method = " + (m != null ? m.getName() : "NULL") + " / source = "
+ (source != null ? source : "NULL") + " / target = " + target, e);
throw new RuntimeException("AutoWiringFilter cannot inject dependency: method = " + (m != null ? m.getName() : "NULL") + " / source = " + (source != null ? source : "NULL") + " / target = " + target, e);
}
}
}
}
}
}
 
return target; // return target nicely with all the dependencies injected
return target; // return target nicely with all the dependencies
// injected
} catch(Exception e) {
throw new RuntimeException(e);
139,6 → 124,8
if (dependencies.contains(d)) throw new RuntimeException("Dependency is already set: " + property);
if (!klass.isInterface()) throw new RuntimeException("Dependency must be an interface!");
 
dependencies.add(d);
return this;
170,8 → 157,15
return this;
}
 
public Container populate(Object bean) {
// TODO Auto-generated method stub
return null;
public Container populate(Object bean) throws Exception {
 
InjectionUtils.getObject(bean, this, false, null, true, false, true);
return this;
}
public boolean contains(String key) {
return beans.containsKey(key);
}
}
/trunk/src/main/java/org/mentacontainer/impl/Dependency.java
17,8 → 17,6
private Map<String, Method> cache = new HashMap<String, Method>();
private Map<Object, Object> received = new WeakHashMap<Object, Object>();
public Dependency(String target, Class<? extends Object> klass, String source) {
this.klass = klass;
105,30 → 103,4
 
return null;
}
/*
* Check if this object has already received the dependency, because we don't want to
* inject every time. Injecting just once is the correct behavior.
*/
public boolean hasAlreadyReceived(Object target) {
 
synchronized(received) {
 
return received.containsKey(target);
 
}
}
/*
* Flag that this object has already received the dependency.
*/
public void setAlreadyReceived(Object target) {
 
synchronized(received) {
 
received.put(target, null);
 
}
}
 
}
/trunk/src/main/java/org/mentacontainer/Container.java
105,5 → 105,13
* @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 Container populate(Object bean) throws Exception;
/**
* Check whether the container is configured to provide a bean with name 'key'.
*
* @param key The key representing the bean inside the container.
* @return true if the container contains this bean.
*/
public boolean contains(String key);
}
/trunk/src/main/java/org/mentacontainer/util/InjectionUtils.java
3,14 → 3,14
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
 
import org.mentacontainer.Container;
 
public class InjectionUtils {
 
/**
27,8 → 27,7
 
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) {
public static void prepareForInjection(Class<? extends Object> klass, Map<String, Object> setters, Map<String, Object> fields) {
 
StringBuffer sb = new StringBuffer(32);
 
42,8 → 41,7
 
Class[] types = m.getParameterTypes();
 
if (name.startsWith("set") && name.length() > 3
&& types.length == 1) {
if (name.startsWith("set") && name.length() > 3 && types.length == 1) {
 
String var = name.substring(3);
 
94,8 → 92,7
}
}
 
if (fields == null)
return;
if (fields == null) return;
 
Field[] f = klass.getDeclaredFields();
 
119,9 → 116,13
 
Class type = field.getType();
 
if (type.isAssignableFrom(types[0]))
continue; // don't choose a field when we already have
// a method...
if (type.isAssignableFrom(types[0])) continue; // don't
// choose a
// field when
// we already
// have
// a
// method...
 
} else if (obj instanceof List) {
 
147,8 → 148,8
}
}
 
if (found)
continue; // don't choose a field when we already have
if (found) continue; // don't choose a field when we already
// have
// a method...
 
}
159,45 → 160,34
}
}
 
public static boolean checkPrimitives(Class target,
Class<? extends Object> source) {
public static boolean checkPrimitives(Class target, Class<? extends Object> source) {
 
if (target.equals(int.class) && source.equals(Integer.class))
return true;
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(boolean.class) && source.equals(Boolean.class)) return true;
 
if (target.equals(byte.class) && source.equals(Byte.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(short.class) && source.equals(Short.class)) return true;
 
if (target.equals(char.class) && source.equals(Character.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(long.class) && source.equals(Long.class)) return true;
 
if (target.equals(float.class) && source.equals(Float.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;
if (target.equals(double.class) && source.equals(Double.class)) return true;
 
return false;
 
}
 
public static Object tryToConvert(Object source, Class targetType,
Locale loc) {
public static Object tryToConvert(Object source, Class targetType) {
 
return tryToConvert(source, targetType, loc, false);
return tryToConvert(source, targetType, false);
}
 
public static Object tryToConvert(Object source, Class targetType,
Locale loc, boolean tryNumber) {
public static Object tryToConvert(Object source, Class targetType, boolean tryNumber) {
 
String value = null;
 
226,8 → 216,7
return null;
}
newValue = new Integer(x);
} else if (className.equals("short")
|| className.equals("java.lang.Short")) {
} else if (className.equals("short") || className.equals("java.lang.Short")) {
short x = -1;
try {
x = Short.parseShort(value);
236,8 → 225,7
}
newValue = new Short(x);
 
} else if (className.equals("char")
|| className.equals("java.lang.Character")) {
} else if (className.equals("char") || className.equals("java.lang.Character")) {
 
if (value.length() != 1) {
return null;
245,8 → 233,7
 
newValue = new Character(value.charAt(0));
 
} else if (className.equals("long")
|| className.equals("java.lang.Long")) {
} else if (className.equals("long") || className.equals("java.lang.Long")) {
long x = -1;
try {
x = Long.parseLong(value);
254,8 → 241,7
return null;
}
newValue = new Long(x);
} else if (className.equals("float")
|| className.equals("java.lang.Float")) {
} else if (className.equals("float") || className.equals("java.lang.Float")) {
float x = -1;
try {
x = Float.parseFloat(value);
263,8 → 249,7
return null;
}
newValue = new Float(x);
} else if (className.equals("double")
|| className.equals("java.lang.Double")) {
} else if (className.equals("double") || className.equals("java.lang.Double")) {
double x = -1;
try {
x = Double.parseDouble(value);
272,8 → 257,7
return null;
}
newValue = new Double(x);
} else if (className.equals("boolean")
|| className.equals("java.lang.Boolean")) {
} else if (className.equals("boolean") || className.equals("java.lang.Boolean")) {
try {
int x = Integer.parseInt(value);
if (x == 1) {
292,15 → 276,6
return null;
}
}
} else if (className.equals("java.util.Date") && loc != null) {
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, loc); // change
// this.
df.setLenient(false);
try {
newValue = df.parse(value);
} catch (Exception e) {
return null;
}
} else if (targetType.isEnum()) {
 
try {
318,8 → 293,7
 
}
 
public static Object shouldConvertToNull(Object value,
Class<? extends Object> targetType) {
public static Object shouldConvertToNull(Object value, Class<? extends Object> targetType) {
 
if (targetType.equals(String.class)) {
 
392,15 → 366,13
return null;
}
 
public static Method findMethodToGet(Class<? extends Object> target,
String name) {
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));
if (name.length() > 1) sb.append(name.substring(1));
 
try {
 
430,15 → 402,13
return null;
}
 
public static Method findMethodToInject(Class<? extends Object> target,
String name, Class source) {
public static Method findMethodToInject(Class<? extends Object> target, String name, Class source) {
 
StringBuffer sb = new StringBuffer(128);
 
sb.append("set").append(name.substring(0, 1).toUpperCase());
 
if (name.length() > 1)
sb.append(name.substring(1));
if (name.length() > 1) sb.append(name.substring(1));
 
String methodName = sb.toString();
 
446,8 → 416,7
 
try {
 
m = FindMethod
.getMethod(target, methodName, new Class[] { source });
m = FindMethod.getMethod(target, methodName, new Class[] { source });
 
} catch (Exception e) {
}
476,8 → 445,7
 
}
 
public static Field findFieldToInject(Class<? extends Object> target,
String name, Class<? extends Object> source) {
public static Field findFieldToInject(Class<? extends Object> target, String name, Class<? extends Object> source) {
 
Field f = getField(target, name);
 
503,16 → 471,13
 
String s = ((String) value).trim();
 
if (s.length() == 0)
return true;
if (s.length() == 0) return true;
}
 
return false;
}
 
public static boolean inject(Method m, Object target, Object value,
Locale loc, boolean tryToConvert, boolean tryingToConvertBoolean)
throws Exception {
public static boolean inject(Method m, Object target, Object value, boolean tryToConvert, boolean tryingToConvertBoolean) throws Exception {
 
Class<?> type = m.getParameterTypes()[0];
 
532,10 → 497,8
}
 
if (value == null
|| (type.isAssignableFrom(value.getClass())
|| checkPrimitives(type, value.getClass()) || (tryToConvert && ((isBlank(value) && (value = shouldConvertToNull(
value, type)) == null) || (value = tryToConvert(value,
type, loc)) != null)))) {
|| (type.isAssignableFrom(value.getClass()) || checkPrimitives(type, value.getClass()) || (tryToConvert && ((isBlank(value) && (value = shouldConvertToNull(value,
type)) == null) || (value = tryToConvert(value, type)) != null)))) {
 
try {
 
545,8 → 508,7
 
} catch (Exception e) {
 
System.err.println("Error injecting by method: " + value
+ " in " + target + " thru " + m);
System.err.println("Error injecting by method: " + value + " in " + target + " thru " + m);
 
e.printStackTrace();
 
580,20 → 542,17
 
StringBuilder sb;
 
if (name.length() >= 4
&& (name.startsWith("get") || name.startsWith("set"))) {
if (name.length() >= 4 && (name.startsWith("get") || name.startsWith("set"))) {
 
sb = new StringBuilder(name.length() - 3);
sb.append(name.substring(3, 4).toLowerCase());
if (name.length() > 4)
sb.append(name.substring(4, name.length()));
if (name.length() > 4) sb.append(name.substring(4, name.length()));
 
} else if (name.length() >= 3 && name.startsWith("is")) {
 
sb = new StringBuilder(name.length() - 2);
sb.append(name.substring(2, 3).toLowerCase());
if (name.length() > 3)
sb.append(name.substring(3, name.length()));
if (name.length() > 3) sb.append(name.substring(3, name.length()));
 
} else {
 
604,8 → 563,7
 
StringBuffer sb2 = new StringBuffer(128);
 
return sb2.append(prefix).append(PREFIX_SEPARATOR).append(
sb.toString()).toString();
return sb2.append(prefix).append(PREFIX_SEPARATOR).append(sb.toString()).toString();
 
}
 
623,22 → 581,18
* every property!
* @throws Exception
*/
public static String getProperty(Object bean, String nameProperty)
throws Exception {
public static String getProperty(Object bean, String nameProperty) throws Exception {
 
if (nameProperty == null || nameProperty.equals(""))
return null;
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) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == 0) {
Object value = method.invoke(bean, (Object[]) null);
if (value == null)
return null;
if (value == null) return null;
return value.toString();
}
}
648,8 → 602,7
field.setAccessible(true);
if (field.getName().equals(nameProperty)) {
Object value = field.get(bean);
if (value == null)
return null;
if (value == null) return null;
return value.toString();
}
}
662,22 → 615,17
 
sb.append("get").append(name.substring(0, 1).toUpperCase());
 
if (name.length() > 1)
sb.append(name.substring(1));
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 {
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) {
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]);
687,4 → 635,214
}
}
 
public static void getObject(Object target, Container container, 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 = container.contains(var);
 
Object value = container.contains(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 list = null;
 
Method m = null;
 
if (obj instanceof List) {
 
list = (List) 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, container, true, prefix, true, true, false); // no
// recursion...
 
inject(m, target, param, false, false);
}
}
 
} else {
 
Iterator it = list.iterator();
 
boolean injected = false;
 
while (it.hasNext()) {
 
m = (Method) 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, container, 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 = container.contains(var);
 
Object value = container.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;
 
}
}
}
}
}
}
/trunk/pom.xml
18,7 → 18,7
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>