/tags/MentaContainer-0.0.3/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); |
} |
} |
/tags/MentaContainer-0.0.3/src/main/java/org/mentacontainer/impl/Component.java |
---|
New file |
0,0 → 1,193 |
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.util.FindMethod; |
class Component { |
private 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; |
private final boolean singleton; |
public Component(Class<? extends Object> klass, boolean singleton) { |
this.klass = klass; |
this.singleton = singleton; |
} |
public boolean isSingleton() { return singleton; } |
public void addProperty(String name, Object value) { |
if (props == null) { |
props = new HashMap<String, Object>(); |
cache = new HashMap<String, Method>(); |
} |
props.put(name, value); |
} |
public void addInitValue(Object value) { |
if (initValues == null) { |
initValues = new LinkedList<Object>(); |
} |
initValues.add(value); |
} |
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) throws InstantiationException { |
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 InstantiationException("Error trying to set a property with reflection: " + name); |
} |
} |
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 Object getInstance() throws InstantiationException { |
Object obj = null; |
if (initValues != null && initValues.size() > 0) { |
if (constructor == null) { |
try { |
constructor = klass.getConstructor(getClasses(initValues)); |
} catch(Exception e) { |
throw new InstantiationException("Cannot find a constructor for class: " + klass); |
} |
} |
try { |
obj = constructor.newInstance(getValues(initValues)); |
} catch(Exception e) { |
throw new InstantiationException("Cannot create instance from constructor: " + constructor); |
} |
} else { |
try { |
obj = klass.newInstance(); |
} catch(Exception e) { |
throw new InstantiationException("Cannot create instance from class: " + klass); |
} |
} |
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 obj; |
} |
} |
/tags/MentaContainer-0.0.3/src/main/java/org/mentacontainer/impl/MentaContainer.java |
---|
New file |
0,0 → 1,171 |
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.Container; |
import org.mentacontainer.util.InjectionUtils; |
public class MentaContainer implements Container { |
private Map<String, Component> beans = new HashMap<String, Component>(); |
private Map<String, Object> singletons = new HashMap<String, Object>(); |
private Set<Dependency> dependencies = new HashSet<Dependency>(); |
public Object get(String key) { |
if (!beans.containsKey(key)) throw new RuntimeException("Container does not have this bean set: " + key); |
Component c = beans.get(key); |
Object target = null; |
try { |
if (c.isSingleton()) { |
if (singletons.containsKey(key)) { |
target = singletons.get(key); |
return target; |
} else { |
target = c.getInstance(); |
singletons.put(key, target); |
} |
} else { |
target = c.getInstance(); |
} |
if (target != null) { |
for (Dependency d : dependencies) { |
// has dependency ? |
Method m = d.getMethod(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.getDependencyClass().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 target; // return target nicely with all the dependencies |
// injected |
} catch (Exception e) { |
throw new RuntimeException(e); |
} |
} |
public Container ioc(String key, Class<? extends Object> klass, boolean singleton) { |
if (beans.containsKey(key)) throw new RuntimeException("Container already set for the bean key: " + key); |
Component c = new Component(klass, singleton); |
beans.put(key, c); |
return this; |
} |
public Container ioc(String key, Class<? extends Object> klass) { |
return ioc(key, klass, false); |
} |
public Container autowire(String property, Class<? extends Object> klass, String source) { |
Dependency d = new Dependency(property, klass, source); |
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; |
} |
public Container autowire(String property, Class<? extends Object> klass) { |
return autowire(property, klass, property); |
} |
public Container init(String key, Object value) { |
if (!beans.containsKey(key)) throw new RuntimeException("Container does not have this bean set: " + key); |
Component c = beans.get(key); |
c.addInitValue(value); |
return this; |
} |
public Container set(String key, String name, Object value) { |
if (!beans.containsKey(key)) throw new RuntimeException("Container does not have this bean set: " + key); |
Component c = beans.get(key); |
c.addProperty(name, value); |
return this; |
} |
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); |
} |
} |
/tags/MentaContainer-0.0.3/src/main/java/org/mentacontainer/impl/Dependency.java |
---|
New file |
0,0 → 1,105 |
package org.mentacontainer.impl; |
import java.lang.reflect.Method; |
import java.util.HashMap; |
import java.util.Map; |
import org.mentacontainer.util.InjectionUtils; |
public class Dependency { |
private final String target; |
private String source; |
private final Class<? extends Object> klass; |
private Map<String, Method> cache = new HashMap<String, Method>(); |
public Dependency(String target, Class<? extends Object> klass, String source) { |
this.klass = klass; |
this.target = target; |
this.source = source; |
} |
public Dependency(String target, Class<? extends Object> klass) { |
this(target, klass, target); |
} |
public String getTarget() { |
return target; |
} |
public String getSource() { |
return source; |
} |
public Class<? extends Object> getDependencyClass() { |
return klass; |
} |
public int hashCode() { |
return klass.hashCode() * 62 + target.hashCode() * 31 + source.hashCode(); |
} |
public boolean equals(Object obj) { |
if (!(obj instanceof Dependency)) return false; |
Dependency d = (Dependency) obj; |
if (!d.klass.equals(this.klass)) return false; |
return true; |
} |
public Method getMethod(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/MentaContainer-0.0.3/src/main/java/org/mentacontainer/Container.java |
---|
New file |
0,0 → 1,117 |
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> Singleton</li> |
* <li> Injection</li> |
* </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 Object 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 singleton A boolean to indicate if this bean will be a singleton. |
* @return The container itself. (Fluent API) |
*/ |
public Container ioc(String key, Class<? extends Object> klass, boolean singleton); |
/** |
* Same as {@link #ioc(String, Class<? extends Object>, singleton)} except that it assumes |
* singleton is false. |
* |
* @param key |
* @param klass |
* @return The container itself. (Fluent API) |
*/ |
public Container ioc(String key, Class<?extends Object> klass); |
/** |
* Configure a bean dependency to be auto-wired by the container. The dependency should be |
* an interface otherwise an exception is thrown. It works like that: |
* |
* 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 an interface, not an implementation, defining 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 Container autowire(String property, Class<? extends Object> klass, String source); |
/** |
* Same as {@link #get(String)} except that it passes the property name as 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 Container autowire(String property, Class<? extends Object> klass); |
/** |
* Add a constructor parameter that will be used by the container to instantiate the bean. The container keeps the order of the parameters |
* in case this method gets called more than once for the same bean, in other words, it assumes that the bean constructor takes more than |
* one parameter. |
* |
* @param key The key representing the bean to return. The name of the bean in the container. |
* @param obj The constructor parameter value. |
* @return The container itself. (Fluent API) |
*/ |
public Container init(String key, Object obj); |
/** |
* Add a property that will be injected by the container in the bean it instantiates. To be not confused with auto-wiring. Here we are just passing |
* static values to be injected in the bean. Auto-wiring wires anything because it is based on interfaces and NOT on implementations. |
* |
* @param key The key representing the bean to return. The name of the bean in the container. |
* @param name The name of the bean property (bean must provide a property setter) |
* @param obj The value of the property that will be injected. |
* @return The container itself. (Fluent API) |
*/ |
public Container set(String key, String name, Object obj); |
/** |
* 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) 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); |
} |
/tags/MentaContainer-0.0.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/MentaContainer-0.0.3/src/main/java/org/mentacontainer/util/InjectionUtils.java |
---|
New file |
0,0 → 1,848 |
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; |
import org.mentacontainer.Container; |
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; // don't |
// choose a |
// field when |
// we already |
// have |
// a |
// method... |
} 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; // don't choose a field when we already |
// have |
// a method... |
} |
} |
fields.put(name, field); |
} |
} |
public static boolean checkPrimitives(Class 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 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 { |
newValue = Enum.valueOf(targetType, 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 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 getPrimitiveFrom(Class 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 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 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; |
} |
} |
/* |
* This method takes setUsername and returns username. |
* |
* If we have a prefix, then it returns prefix.username. |
*/ |
private static String adjustName(String name, String prefix) { |
StringBuilder sb; |
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())); |
} 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())); |
} else { |
throw new IllegalArgumentException("Cannot adjust method: " + name); |
} |
if (prefix != null) { |
StringBuffer sb2 = new StringBuffer(128); |
return sb2.append(prefix).append(PREFIX_SEPARATOR).append(sb.toString()).toString(); |
} |
return sb.toString(); |
} |
/** |
* 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 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; |
} |
} |
} |
} |
} |
} |
/tags/MentaContainer-0.0.3/pom.xml |
---|
New file |
0,0 → 1,69 |
<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"> |
<modelVersion>4.0.0</modelVersion> |
<groupId>org.mentacontainer</groupId> |
<artifactId>MentaContainer</artifactId> |
<version>0.0.3</version> |
<packaging>jar</packaging> |
<name>MentaContainer</name> |
<url>http://maven.apache.org</url> |
<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> |
<scm> |
<developerConnection>scm:svn:svn://saoj-la.dyndns.org/mentacontainer/tags/MentaContainer-0.0.3</developerConnection> |
<url>svn://saoj-la.dyndns.org/mentacontainer/tags/MentaContainer-0.0.3</url> |
<connection>scm:svn:svn://saoj-la.dyndns.org/mentacontainer/tags/MentaContainer-0.0.3</connection> |
</scm> |
<distributionManagement> |
<!-- Publish the versioned releases here --> |
<repository> |
<id>repo</id> |
<name>Nexus</name> |
<url>dav:http://nexus.vineetmanohar.com/nexus/content/repositories/</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-compiler-plugin</artifactId> |
<version>2.0.2</version> |
<configuration> |
<source>1.6</source> |
<target>1.6</target> |
</configuration> |
</plugin> |
<plugin> |
<artifactId>maven-javadoc-plugin</artifactId> |
<version>2.7</version> |
<configuration /> |
</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/MentaContainer-0.0.3/readme.txt |
---|
New file |
0,0 → 1,2 |
MentaContainer 2010 |
/MentaContainer-0.0.3 |
---|
Property changes: |
Added: svn:ignore |
+ target |
.classpath |
.project |
.settings |