You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by jo...@apache.org on 2013/10/14 19:36:24 UTC

svn commit: r1531989 - in /cayenne/main/trunk/framework/cayenne-core-unpublished/src: main/java/org/apache/cayenne/exp/ main/java/org/apache/cayenne/reflect/ test/java/org/apache/cayenne/exp/ test/java/org/apache/cayenne/reflect/

Author: johnthuss
Date: Mon Oct 14 17:36:24 2013
New Revision: 1531989

URL: http://svn.apache.org/r1531989
Log:
Add getFrom and setIn methods to Property for accessing object state via reflection; Implement equals and hashCode

Tweak the behavior of PropertyUtils.setProperty to match the behavior of PropertyUtils.getProperty when
nulls are encountered along a nested path - now the exception behavior is symmetric.

Modified:
    cayenne/main/trunk/framework/cayenne-core-unpublished/src/main/java/org/apache/cayenne/exp/Property.java
    cayenne/main/trunk/framework/cayenne-core-unpublished/src/main/java/org/apache/cayenne/reflect/PropertyUtils.java
    cayenne/main/trunk/framework/cayenne-core-unpublished/src/test/java/org/apache/cayenne/exp/PropertyTest.java
    cayenne/main/trunk/framework/cayenne-core-unpublished/src/test/java/org/apache/cayenne/reflect/TestJavaBean.java

Modified: cayenne/main/trunk/framework/cayenne-core-unpublished/src/main/java/org/apache/cayenne/exp/Property.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-core-unpublished/src/main/java/org/apache/cayenne/exp/Property.java?rev=1531989&r1=1531988&r2=1531989&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-core-unpublished/src/main/java/org/apache/cayenne/exp/Property.java (original)
+++ cayenne/main/trunk/framework/cayenne-core-unpublished/src/main/java/org/apache/cayenne/exp/Property.java Mon Oct 14 17:36:24 2013
@@ -26,6 +26,7 @@ import org.apache.cayenne.exp.parser.AST
 import org.apache.cayenne.query.Ordering;
 import org.apache.cayenne.query.PrefetchTreeNode;
 import org.apache.cayenne.query.SortOrder;
+import org.apache.cayenne.reflect.PropertyUtils;
 
 /**
  * <p>
@@ -65,6 +66,16 @@ public class Property<E> {
     public String getName() {
         return name;
     }
+    
+	@Override
+	public int hashCode() {
+		return getName().hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		return obj instanceof Property && ((Property<?>)obj).getName().equals(getName());
+	}
 
     /**
      * @return Constructs a property path by appending the argument to the
@@ -377,4 +388,43 @@ public class Property<E> {
         return node;
     }
 
+    /**
+     * Extracts property value from an object using JavaBean-compatible introspection with one addition -
+     * a property can be a dot-separated property name path.
+     */
+    @SuppressWarnings("unchecked")
+    public E getFrom(Object bean) {
+    	return (E)PropertyUtils.getProperty(bean, getName());
+    }
+
+    /**
+     * Extracts property value from a collection of objects using JavaBean-compatible introspection with one addition -
+     * a property can be a dot-separated property name path.
+     */
+    public List<E> getFromAll(Collection<?> beans) {
+    	List<E> result = new ArrayList<E>(beans.size());
+    	for (Object bean : beans) {
+    		result.add(getFrom(bean));
+    	}
+    	return result;
+    }
+    
+    /**
+     * Sets a property value in 'obj' using JavaBean-compatible introspection with one addition -
+     * a property can be a dot-separated property name path.
+     */
+	public void setIn(Object bean, E value) {
+    	PropertyUtils.setProperty(bean, getName(), value);
+    }
+
+    /**
+     * Sets a property value in a collection of objects using JavaBean-compatible introspection with one addition -
+     * a property can be a dot-separated property name path.
+     */
+	public void setInAll(Collection<?> beans, E value) {
+    	for (Object bean : beans) {
+    		setIn(bean, value);
+    	}
+    }
+
 }
\ No newline at end of file

Modified: cayenne/main/trunk/framework/cayenne-core-unpublished/src/main/java/org/apache/cayenne/reflect/PropertyUtils.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-core-unpublished/src/main/java/org/apache/cayenne/reflect/PropertyUtils.java?rev=1531989&r1=1531988&r2=1531989&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-core-unpublished/src/main/java/org/apache/cayenne/reflect/PropertyUtils.java (original)
+++ cayenne/main/trunk/framework/cayenne-core-unpublished/src/main/java/org/apache/cayenne/reflect/PropertyUtils.java Mon Oct 14 17:36:24 2013
@@ -151,11 +151,16 @@ public class PropertyUtils {
         if (dot > 0) {
             lastSegment = nestedPropertyName.substring(dot + 1);
             String pathSegment = nestedPropertyName.substring(0, dot);
-            object = getProperty(object, pathSegment);
+            Object intermediateObject = getProperty(object, pathSegment);
 
-            if (object == null) {
-                throw new IllegalArgumentException(
-                        "Null object at the end of the segment '" + pathSegment + "'");
+            if (intermediateObject == null) {
+                throw new UnresolvablePathException(
+                        "Null value in the middle of the path, failed on "
+                                + pathSegment
+                                + " from "
+                                + object);
+            } else {
+            	object = intermediateObject;
             }
         }
         else {

Modified: cayenne/main/trunk/framework/cayenne-core-unpublished/src/test/java/org/apache/cayenne/exp/PropertyTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-core-unpublished/src/test/java/org/apache/cayenne/exp/PropertyTest.java?rev=1531989&r1=1531988&r2=1531989&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-core-unpublished/src/test/java/org/apache/cayenne/exp/PropertyTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-core-unpublished/src/test/java/org/apache/cayenne/exp/PropertyTest.java Mon Oct 14 17:36:24 2013
@@ -19,9 +19,14 @@
 package org.apache.cayenne.exp;
 
 import java.util.Arrays;
+import java.util.List;
 
 import junit.framework.TestCase;
 
+import org.apache.cayenne.reflect.TestJavaBean;
+import org.apache.cayenne.reflect.UnresolvablePathException;
+import org.apache.cayenne.util.Util;
+
 public class PropertyTest extends TestCase {
 
     public void testIn() {
@@ -36,4 +41,109 @@ public class PropertyTest extends TestCa
         Expression e3 = p.in(Arrays.asList("a", "b"));
         assertEquals("x.y in (\"a\", \"b\")", e3.toString());
     }
+    
+    public void testGetFrom() {
+    	TestJavaBean bean = new TestJavaBean();
+    	bean.setIntField(7);
+    	final Property<Integer> INT_FIELD = new Property<Integer>("intField");
+    	assertEquals(Integer.valueOf(7), INT_FIELD.getFrom(bean));
+    }
+    
+    public void testGetFromNestedProperty() {
+    	TestJavaBean bean = new TestJavaBean();
+    	TestJavaBean nestedBean = new TestJavaBean();
+    	nestedBean.setIntField(7);
+    	bean.setObjectField(nestedBean);
+    	final Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<Integer>("objectField.intField");
+    	assertEquals(Integer.valueOf(7), OBJECT_FIELD_INT_FIELD.getFrom(bean));
+    }
+    
+    public void testGetFromNestedNull() {
+    	TestJavaBean bean = new TestJavaBean();
+    	bean.setObjectField(null);
+    	final Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<Integer>("objectField.intField");
+    	try {
+    		OBJECT_FIELD_INT_FIELD.getFrom(bean);
+    		fail();
+    	} catch (Exception e) {
+    		Throwable rootException = Util.unwindException(e);
+    		if (!(rootException instanceof UnresolvablePathException)) {
+    			fail();
+    		}
+    	}
+    }
+    
+    public void testGetFromAll() {
+    	TestJavaBean bean = new TestJavaBean();
+    	bean.setIntField(7);
+    	
+    	TestJavaBean bean2 = new TestJavaBean();
+    	bean2.setIntField(8);
+    	
+    	List<TestJavaBean> beans = Arrays.asList(bean, bean2);
+
+    	final Property<Integer> INT_FIELD = new Property<Integer>("intField");
+    	assertEquals(Arrays.asList(7, 8), INT_FIELD.getFromAll(beans));
+    }
+    
+    public void testSetIn() {
+    	TestJavaBean bean = new TestJavaBean();
+    	final Property<Integer> INT_FIELD = new Property<Integer>("intField");
+    	INT_FIELD.setIn(bean, 7);
+    	assertEquals(7, bean.getIntField());
+    }
+    
+    public void testSetInNestedProperty() {
+    	TestJavaBean bean = new TestJavaBean();
+    	bean.setObjectField(new TestJavaBean());
+    	
+    	final Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<Integer>("objectField.intField");
+
+    	OBJECT_FIELD_INT_FIELD.setIn(bean, 7);
+    	assertEquals(7, ((TestJavaBean)bean.getObjectField()).getIntField());
+    }
+    
+    public void testSetInNestedNull() {
+    	TestJavaBean bean = new TestJavaBean();
+    	bean.setObjectField(null);
+    	final Property<Integer> OBJECT_FIELD_INT_FIELD = new Property<Integer>("objectField.intField");
+    	try {
+    		OBJECT_FIELD_INT_FIELD.setIn(bean, 7);
+    		fail();
+    	} catch (Exception e) {
+    		Throwable rootException = Util.unwindException(e);
+    		if (!(rootException instanceof UnresolvablePathException)) {
+    			fail();
+    		}
+    	}
+    }
+    
+    public void testSetInAll() {
+    	TestJavaBean bean = new TestJavaBean();
+    	TestJavaBean bean2 = new TestJavaBean();
+    	List<TestJavaBean> beans = Arrays.asList(bean, bean2);
+
+    	final Property<Integer> INT_FIELD = new Property<Integer>("intField");
+    	INT_FIELD.setInAll(beans, 7);
+    	assertEquals(7, bean.getIntField());
+    	assertEquals(7, bean2.getIntField());
+    }
+    
+    public void testEquals() {
+    	final Property<Integer> INT_FIELD = new Property<Integer>("intField");
+    	final Property<Integer> INT_FIELD2 = new Property<Integer>("intField");
+
+    	assertTrue(INT_FIELD != INT_FIELD2);
+    	assertTrue(INT_FIELD.equals(INT_FIELD2));
+    }
+    
+    public void testHashCode() {
+    	final Property<Integer> INT_FIELD  = new Property<Integer>("intField");
+    	final Property<Integer> INT_FIELD2 = new Property<Integer>("intField");
+    	final Property<Long> LONG_FIELD = new Property<Long>("longField");
+
+    	assertTrue(INT_FIELD.hashCode() == INT_FIELD2.hashCode());
+    	assertTrue(INT_FIELD.hashCode() != LONG_FIELD.hashCode());
+    }
+    
 }

Modified: cayenne/main/trunk/framework/cayenne-core-unpublished/src/test/java/org/apache/cayenne/reflect/TestJavaBean.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-core-unpublished/src/test/java/org/apache/cayenne/reflect/TestJavaBean.java?rev=1531989&r1=1531988&r2=1531989&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-core-unpublished/src/test/java/org/apache/cayenne/reflect/TestJavaBean.java (original)
+++ cayenne/main/trunk/framework/cayenne-core-unpublished/src/test/java/org/apache/cayenne/reflect/TestJavaBean.java Mon Oct 14 17:36:24 2013
@@ -22,6 +22,8 @@ package org.apache.cayenne.reflect;
 import java.sql.Timestamp;
 import java.util.Date;
 
+import org.apache.cayenne.util.ToStringBuilder;
+
 public class TestJavaBean extends Object {
 
     protected String stringField;
@@ -172,4 +174,12 @@ public class TestJavaBean extends Object
 	public void setDoubleField(double doubleField) {
 		this.doubleField = doubleField;
 	}
+	
+	@Override
+	public String toString() {
+		return new ToStringBuilder(this)
+			.append("intField", getIntField())
+			.append("objectField", getObjectField())
+			.toString();
+	}
 }