You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@labs.apache.org by si...@apache.org on 2011/11/03 18:18:22 UTC

svn commit: r1197228 - in /labs/magma/trunk/foundation-beans/src: main/java/org/apache/magma/beans/ test/java/org/apache/magma/beans/

Author: simoneg
Date: Thu Nov  3 17:18:21 2011
New Revision: 1197228

URL: http://svn.apache.org/viewvc?rev=1197228&view=rev
Log:
Support for inspection of methods

Modified:
    labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanData.java
    labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/PropertyInfo.java
    labs/magma/trunk/foundation-beans/src/test/java/org/apache/magma/beans/BeanDataTest.java
    labs/magma/trunk/foundation-beans/src/test/java/org/apache/magma/beans/DummyBean.java

Modified: labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanData.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanData.java?rev=1197228&r1=1197227&r2=1197228&view=diff
==============================================================================
--- labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanData.java (original)
+++ labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/BeanData.java Thu Nov  3 17:18:21 2011
@@ -21,8 +21,12 @@ import java.beans.IntrospectionException
 import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -69,6 +73,8 @@ public class BeanData {
 	 * Properties of the class.
 	 */
 	private Map<String, PropertyInfo> properties = new HashMap<String, PropertyInfo>();
+	private Map<String, List<MethodInfo>> instanceMethods = new HashMap<String, List<MethodInfo>>();
+	private Map<String, List<MethodInfo>> staticMethods = new HashMap<String, List<MethodInfo>>();
 
 	/**
 	 * Builds a new {@link BeanData} for the given class, performing inspection.
@@ -85,13 +91,38 @@ public class BeanData {
 			} catch (IntrospectionException e) {
 				throw new IllegalStateException("Error analyzing bean " + clazz, e);
 			}
+			Set<Method> doneMethods = new HashSet<Method>();
 			PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
 			for (PropertyDescriptor desc : descriptors) {
 				RunningContext.get().push(desc.getName());
 				try {
-					PropertyInfo info = new PropertyInfo();
-					info.init(desc, clazz);
+					PropertyInfo info = new PropertyInfo(clazz);
+					info.init(desc,clazz);
 					properties.put(info.getName(), info);
+					doneMethods.add(desc.getReadMethod());
+					doneMethods.add(desc.getWriteMethod());
+				} finally {
+					RunningContext.get().popString();				
+				}
+			}
+			
+			Method[] methods = clazz.getMethods();
+			for (Method method : methods) {
+				if (doneMethods.contains(method)) continue;
+				if (method.isBridge() || method.isSynthetic()) continue;
+				if (method.getDeclaringClass().equals(Object.class)) continue;
+				RunningContext.get().push(method.getName());
+				try {
+					MethodInfo info = new MethodInfo(clazz);
+					info.init(method, clazz);
+					Map<String, List<MethodInfo>> tgt = info.isStatic() ? staticMethods : instanceMethods;
+					List<MethodInfo> list = tgt.get(info.getName());
+					if (list == null) {
+						list = new ArrayList<MethodInfo>();
+						tgt.put(info.getName(), list);
+					}
+					list.add(info);
+					doneMethods.add(method);
 				} finally {
 					RunningContext.get().popString();				
 				}
@@ -110,6 +141,14 @@ public class BeanData {
 	}
 	
 	/**
+	 * Fetches all properties,.
+	 * @return a set of properties
+	 */
+	public Collection<PropertyInfo> getProperties() {
+		return Collections.unmodifiableCollection(properties.values());
+	}
+	
+	/**
 	 * Fetches a single property.
 	 * @param name the name of the property to fetch.
 	 * @return a {@link PropertyInfo} describing the required property, or null if not found.
@@ -145,5 +184,69 @@ public class BeanData {
 		return this.getProperty(name);
 	}
 
+	/**
+	 * @return All the names of instance methods
+	 */
+	public Set<String> getInstanceMethodNames() {
+		return Collections.unmodifiableSet(instanceMethods.keySet());
+	}
+	
+	/**
+	 * @return All the names of static methods
+	 */
+	public Set<String> getStaticMethodNames() {
+		return Collections.unmodifiableSet(staticMethods.keySet());
+	}
+	
+	/**
+	 * Fetches an instance method
+	 * @param name The name of the method
+	 * @return One or more (if method is overloaded) {@link MethodInfo}s describing the method.
+	 */
+	public List<MethodInfo> getInstanceMethod(String name) {
+		List<MethodInfo> list = instanceMethods.get(name);
+		if (list == null) return null;
+		return Collections.unmodifiableList(list);
+	}
+	
+	/**
+	 * Fetches a static method
+	 * @param name The name of the method
+	 * @return One or more (if method is overloaded) {@link MethodInfo}s describing the method.
+	 */
+	public List<MethodInfo> getStaticMethod(String name) {
+		List<MethodInfo> list = staticMethods.get(name);
+		if (list == null) return null;
+		return Collections.unmodifiableList(list);
+	}
+	
+	
+	public MethodInfo findInstanceMethod(String name, Class... parameters) {
+		return findMethod(false, name, parameters);
+	}
+	
+	public MethodInfo findStaticMethod(String name, Class... parameters) {
+		return findMethod(true, name, parameters);
+	}
+
+	public MethodInfo findMethod(boolean stat, String name, Class... parameters) {
+		Map<String, List<MethodInfo>> tgt = stat ? staticMethods : instanceMethods;
+		List<MethodInfo> list = stat ? getStaticMethod(name) : getInstanceMethod(name);
+		if (list == null || list.size() == 0) return null;
+		for (MethodInfo methodInfo : list) {
+			if (methodInfo.matchesParameters(parameters)) return methodInfo;
+		}
+		return null;
+	}
+	
+	public MethodInfo findMethodWithParameters(boolean stat, String name, Object... parameters) {
+		Class[] classes = new Class[parameters.length];
+		for (int i = 0; i < parameters.length; i++) {
+			if (parameters[i] != null) {
+				classes[i] = parameters[i].getClass();
+			} 
+		}
+		return findMethod(stat, name, classes);
+	}
 	
 }

Modified: labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/PropertyInfo.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/PropertyInfo.java?rev=1197228&r1=1197227&r2=1197228&view=diff
==============================================================================
--- labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/PropertyInfo.java (original)
+++ labs/magma/trunk/foundation-beans/src/main/java/org/apache/magma/beans/PropertyInfo.java Thu Nov  3 17:18:21 2011
@@ -23,7 +23,6 @@ import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import org.apache.commons.beanutils.PropertyUtils;
 import org.apache.magma.basics.MagmaException;
@@ -42,19 +41,13 @@ import org.apache.magma.conversion.Prope
  *
  * @author Simone Gianni <si...@apache.org>
  */
-public class PropertyInfo implements Cloneable {
+public class PropertyInfo extends BeanMemberInfo implements Cloneable {
+
+	@SuppressWarnings("rawtypes")
+	public PropertyInfo(Class beanClass) {
+		super(beanClass);
+	}
 
-	/**
-	 * Name of the property.
-	 */
-	private String name;
-	
-	/**
-	 * Type of the property
-	 */
-	@SuppressWarnings("unchecked")
-	private Class type;
-	
 	/**
 	 * When {@link Consider} is used, this is the underlying type
 	 */
@@ -68,12 +61,6 @@ public class PropertyInfo implements Clo
 	private GenericConverter underlyingConverter;
 	
 	/**
-	 * Class of the bean this property is found on
-	 */
-	@SuppressWarnings("unchecked")
-	private Class beanClass;
-	
-	/**
 	 * Whether the property is readable
 	 */
 	private boolean readable;
@@ -89,48 +76,11 @@ public class PropertyInfo implements Clo
 	private boolean underlyingWriteable;
 	
 	/**
-	 * Whether the property represents a collection (this includes {@link List}, {@link Set} and arrays, but not maps or tables).
-	 */
-	private boolean isCollection;
-
-	/**
-	 * The type of elements contained in the collection (could be Object if it's not possible to deduce it)
-	 */
-	@SuppressWarnings("unchecked")
-	private Class collectionClass;
-
-	
-	/**
-	 * Whether the property represents a map (this includes {@link Map} and tables).
-	 */
-	private boolean isMap;
-	
-
-	/**
-	 * The type of keys in the map (could be Object if it's not possible to deduce it)
-	 */
-	private Class mapKeyClass;
-	/**
-	 * The type of values in the map (could be Object if it's not possible to deduce it)
-	 */	
-	private Class mapValueClass;
-	
-	/**
 	 * If content of this property is rendered as a string, the maximum size of this string.
 	 */
 	private int maxStringSize = -1;
 
 	/**
-	 * If the type is a basic type, that is a primitive type, a wrapper, one of java.math numbers, or Date.
-	 */
-	private boolean isBasicType;
-
-	/**
-	 * If the type is an enum.
-	 */
-	private boolean isEnum;
-	
-	/**
 	 * Another PropertyInfo representing the underlying property, without conversion or hiding. Could be the same instance
 	 * if there is no conversion nor hiding to handle.
 	 */
@@ -170,48 +120,22 @@ public class PropertyInfo implements Clo
 	public void setWriteable(boolean writeable) {
 		this.writeable = writeable;
 	}
-
-	/**
-	 * @return the name of the property.
-	 */		
-	public String getName() {
-		return name;
-	}
-	
-	/**
-	 * @return the type of the property.
-	 */
-	@SuppressWarnings("unchecked")
-	public Class getType() {
-		return type;
-	}
 	
 	/**
-	 * @return true if the type is a basic type, that is a primitive type, a wrapper, one of java.math numbers or Date.
-	 */
-	public boolean isBasicType() {
-		return this.isBasicType;
-	}
-
-	/**
-	 * @return true if the type is an {@link Enum}.
-	 */
-	public boolean isEnum() {
-		return this.isEnum;
-	}
-
-	/**
 	 * Initializes this class, parsing the {@link PropertyDescriptor} and eventually annotations found on the getter or setter methods.
 	 * 
 	 * This is the method to hook to when implementing additional parsing, like validation and conversion does.
 	 * 
+	 * NOTE: the beanClass parameter is currently ignored. It is here only because a lot of aspects matches that signature. It will
+	 * be removed when all aspects hooking here can be safely refactored.
+	 * 
 	 * @param descriptor the {@link PropertyDescriptor} of the property.
-	 * @param beanClass the class of the bean containing the property.
+	 * @param beanClass IGNORED the class of the bean containing the property.
 	 */
+	// TODO remove beanClass parameter when a way to force aspect matching is found
 	@SuppressWarnings("unchecked")
 	public void init(PropertyDescriptor descriptor, Class beanClass) {
 		this.descriptor = descriptor;
-		this.beanClass = beanClass;
 		this.name = descriptor.getName();
 		readMethod = descriptor.getReadMethod();
 		writeMethod = descriptor.getWriteMethod();
@@ -262,40 +186,11 @@ public class PropertyInfo implements Clo
 		}
 		
 		if (this.type != null) {
-			this.isCollection = Collection.class.isAssignableFrom(this.type);
-			this.isMap = Map.class.isAssignableFrom(this.type);
-			if (this.isCollection) {
-				if (readable) {
-					GenericClass returnType = GenericClass.forReturnType(readMethod);
-					if (!returnType.getBaseClass().equals(this.type)) 
-						returnType = GenericClass.forClass(this.type);
-					// It must have an add method
-					List<MethodDef> methods = returnType.findMethods("add", new Class<?>[] {null});
-					// It must have a single parameter of the type of the collection
-					this.collectionClass = methods.get(0).getParameterTypes()[0].getBaseClass();
-				}				
-			} else if (this.isMap) {
-				if (readable) {
-					GenericClass returnType = GenericClass.forReturnType(readMethod);
-					if (!returnType.getBaseClass().equals(this.type)) 
-						returnType = GenericClass.forClass(this.type);
-					// It must have a put method
-					List<MethodDef> methods = returnType.findMethods("put", new Class<?>[] {null, null});
-					// It must have a single parameter of the type of the collection
-					MethodDef putmethod = methods.get(0);
-					GenericClass[] parameterTypes = putmethod.getParameterTypes();
-					this.mapKeyClass = parameterTypes[0].getBaseClass();
-					this.mapValueClass = parameterTypes[1].getBaseClass();
-				}								
-			} else {
-				this.isBasicType = 
-					this.type.isPrimitive() ||
-					this.type.getName().startsWith("java.lang") ||
-					this.type.getName().startsWith("java.math") ||
-					Date.class.isAssignableFrom(this.type);
-				this.isEnum = Enum.class.isAssignableFrom(this.type);
-			} 
-		}		
+			GenericClass gc = null;
+			if (readable) gc = GenericClass.forReturnType(readMethod);
+			super.initType(this.type, gc);
+		}
+		
 	}
 	
 	protected void initAsUnderlying(PropertyInfo sup) {
@@ -316,52 +211,6 @@ public class PropertyInfo implements Clo
     }
     
     /**
-     * @return Whether the property represents a collection (this includes {@link List}, {@link Set} and arrays, but not maps or tables).
-     */
-	public boolean isCollection() {
-		return isCollection;
-	}
-	
-	/**
-	 * @param isCollection Whether the property represents a collection.
-	 */
-	public void setCollection(boolean isCollection) {
-		this.isCollection = isCollection;
-	}
-	
-	/**
-	 * @return The type of elements contained in the collection (could be Object if it's not possible to deduce it)
-	 */
-	@SuppressWarnings("unchecked")
-	public Class getCollectionClass() {
-		return collectionClass;
-	}
-	
-	/**
-	 * @param collectionClass The type of elements contained in the collection (could be Object if it's not possible to deduce it)
-	 */	
-	@SuppressWarnings("unchecked")
-	public void setCollectionClass(Class collectionClass) {
-		this.collectionClass = collectionClass;
-	}
-	
-	/**
-	 * @return Class of the bean this property is found on
-	 */
-	@SuppressWarnings("unchecked")
-	public Class getBeanClass() {
-		return beanClass;
-	}
-	
-	/**
-	 * @param beanClass Class of the bean this property is found on
-	 */
-	@SuppressWarnings("unchecked")
-	public void setBeanClass(Class beanClass) {
-		this.beanClass = beanClass;
-	}
-	
-	/**
 	 * @return If content of this property is rendered as a string, the maximum size of this string.
 	 */
 	public int getMaximumStringSize() {
@@ -439,27 +288,6 @@ public class PropertyInfo implements Clo
 	}
 	
 	/**
-     * @return Whether the property represents a map (this includes {@link Map} and tables).
-	 */
-	public boolean isMap() {
-		return isMap;
-	}
-	
-	/**
-	 * @return the Class of the keys in the map if this property {@link #isMap} and if it's possible to determine its generics.
-	 */
-	public Class getMapKeyClass() {
-		return mapKeyClass;
-	}
-	
-	/**
-	 * @return the Class of the values in the map if this property {@link #isMap} and if it's possible to determine its generics.
-	 */	
-	public Class getMapValueClass() {
-		return mapValueClass;
-	}
-	
-	/**
 	 * Set the given value for this property on the given bean. Value will be converted to underlying if applicable.
 	 * @param bean The bean to set the property to
 	 * @param val The value to set, it will be converted to the underlying type.
@@ -501,7 +329,7 @@ public class PropertyInfo implements Clo
 			if (this.underlyingType == null && this.underlyingWriteable == this.writeable) {
 				this.underlyingProperty = this;
 			} else {
-				PropertyInfo np = new PropertyInfo();
+				PropertyInfo np = new PropertyInfo(this.beanClass);
 				np.initAsUnderlying(this);
 				this.underlyingProperty = np;
 			}

Modified: labs/magma/trunk/foundation-beans/src/test/java/org/apache/magma/beans/BeanDataTest.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/foundation-beans/src/test/java/org/apache/magma/beans/BeanDataTest.java?rev=1197228&r1=1197227&r2=1197228&view=diff
==============================================================================
--- labs/magma/trunk/foundation-beans/src/test/java/org/apache/magma/beans/BeanDataTest.java (original)
+++ labs/magma/trunk/foundation-beans/src/test/java/org/apache/magma/beans/BeanDataTest.java Thu Nov  3 17:18:21 2011
@@ -20,6 +20,7 @@ import static org.junit.Assert.*;
 import static org.hamcrest.CoreMatchers.*;
 
 import java.util.Date;
+import java.util.List;
 import java.util.Set;
 
 import org.junit.Before;
@@ -118,4 +119,72 @@ public class BeanDataTest {
 		assertEquals(String.class, property.getType());
 	}
 	
+	@Test
+	public void methodsInBean() throws Exception {
+		DummyBean dummy = new DummyBean();
+		BeanData bd = dummy.beanData();
+		
+		Set<String> instanceMethodNames = bd.getInstanceMethodNames();
+		System.out.println(instanceMethodNames);
+		assertEquals(4, instanceMethodNames.size());
+		
+		List<MethodInfo> methods = bd.getInstanceMethod("computeA");
+		assertEquals(1, methods.size());
+		MethodInfo methodInfo = methods.get(0);
+		assertEquals(0,methodInfo.getParameters().length);
+		assertEquals(String.class,methodInfo.getType());
+		
+		methods = bd.getInstanceMethod("alterPrivString");
+		assertEquals(3, methods.size());
+	}
+	
+	@Test
+	public void staticMethodsInBean() throws Exception {
+		DummyBean dummy = new DummyBean();
+		BeanData bd = dummy.beanData();
+
+		Set<String> staticMethodNames = bd.getStaticMethodNames();
+		assertEquals(1, staticMethodNames.size());
+		
+		List<MethodInfo> staticMethod = bd.getStaticMethod("computeMyName");
+		assertEquals(2,staticMethod.size());
+		
+		assertEquals(String.class, staticMethod.get(0).getType());
+	}
+	
+	@Test
+	public void findMethods() throws Exception {
+		DummyBean dummy = new DummyBean();
+		BeanData bd = dummy.beanData();
+		
+		MethodInfo methodInfo = bd.findInstanceMethod("alterPrivString", Integer.TYPE);
+		assertNotNull(methodInfo);
+		assertEquals("alterPrivString", methodInfo.getName());
+		assertEquals(Void.TYPE, methodInfo.getType());
+		
+		MethodInfo methodInfo2 = bd.findInstanceMethod("alterPrivString", String.class);
+		assertNotSame(methodInfo, methodInfo2);
+		
+		methodInfo2 = bd.findInstanceMethod("alterPrivString");
+		assertNotSame(methodInfo, methodInfo2);
+		assertEquals(1, methodInfo2.getExceptions().length);
+		
+	}
+	
+	@Test
+	public void invokeMethods() throws Exception {
+		DummyBean dummy = new DummyBean();
+		BeanData bd = dummy.beanData();
+		
+		MethodInfo methodInfo2 = bd.findInstanceMethod("alterPrivString", String.class);
+		methodInfo2.invoke(dummy, "TestInvoke");
+		
+		assertEquals("TestInvoke", dummy.getPrivString());
+		
+		
+		methodInfo2 = bd.findInstanceMethod("computeA");
+		Object ret = methodInfo2.invoke(dummy);
+		assertEquals("a", ret);
+	}
+	
 }

Modified: labs/magma/trunk/foundation-beans/src/test/java/org/apache/magma/beans/DummyBean.java
URL: http://svn.apache.org/viewvc/labs/magma/trunk/foundation-beans/src/test/java/org/apache/magma/beans/DummyBean.java?rev=1197228&r1=1197227&r2=1197228&view=diff
==============================================================================
--- labs/magma/trunk/foundation-beans/src/test/java/org/apache/magma/beans/DummyBean.java (original)
+++ labs/magma/trunk/foundation-beans/src/test/java/org/apache/magma/beans/DummyBean.java Thu Nov  3 17:18:21 2011
@@ -16,6 +16,7 @@
  */
 package org.apache.magma.beans;
 
+import java.io.IOException;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -75,4 +76,30 @@ public class DummyBean {
 		this.aMap = aMap;
 	}
 	
+	
+	/* Testing methods */
+	
+	public String computeA() {
+		return "a";
+	}
+	
+	public void alterPrivString() throws IOException {
+		this.setPrivString("altered");
+	}
+	
+	public void alterPrivString(String val) {
+		this.setPrivString(val);		
+	}
+	
+	public void alterPrivString(int val) {
+		this.setPrivString(Integer.toString(val));
+	}
+	
+	public static String computeMyName() {
+		return "MyName";
+	}
+	
+	public static String computeMyName(int val) {
+		return "MyName" + val;
+	}
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@labs.apache.org
For additional commands, e-mail: commits-help@labs.apache.org