You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2010/11/09 04:05:31 UTC
svn commit: r1032829 - in /cayenne/main/trunk: docs/doc/src/main/resources/
framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/
Author: aadamchik
Date: Tue Nov 9 03:05:30 2010
New Revision: 1032829
URL: http://svn.apache.org/viewvc?rev=1032829&view=rev
Log:
CAY-1403 Method "readNestedProperty" Should Resolve Through Iterative Invocations onto DataObject and Not Complete Within Cayenne.readNestedProperty
* Porting 3.0 patch by Andrew Lindesay, with a 3.1 twist - a code to switch as needed between
overridable CayenneDataObject implementation of readnestedProperty and static Cayenne implementation
Modified:
cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/Cayenne.java
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneDataObject.java
Modified: cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt?rev=1032829&r1=1032828&r2=1032829&view=diff
==============================================================================
--- cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt (original)
+++ cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt Tue Nov 9 03:05:30 2010
@@ -75,6 +75,7 @@ CAY-1500 MySQL JDBC Batching
Bug Fixes Since 3.0.1:
+CAY-1403 Method "readNestedProperty" Should Resolve Through Iterative Invocations onto DataObject and Not Complete Within Cayenne.readNestedProperty
CAY-1484 Flattened attribute queries are incorrectly generated
CAY-1485 Memory information for about dialog
CAY-1488 OutOfMemory when selecting "Remove Foreign Keys Mapped as Object Attributes"
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/Cayenne.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/Cayenne.java?rev=1032829&r1=1032828&r2=1032829&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/Cayenne.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/Cayenne.java Tue Nov 9 03:05:30 2010
@@ -24,7 +24,6 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.StringTokenizer;
import org.apache.cayenne.map.DbEntity;
import org.apache.cayenne.map.ObjEntity;
@@ -112,159 +111,125 @@ public final class Cayenne {
* </p>
* <ul>
* <li>Read this object property:<br>
- * <code>String name = (String)CayenneUtils.readNestedProperty(artist, "name");</code>
- * <br>
+ * <code>String name = (String)Cayenne.readNestedProperty(artist, "name");</code><br>
* <br>
* </li>
* <li>Read an object related to this object:<br>
- * <code>Gallery g = (Gallery)CayenneUtils.readNestedProperty(paintingInfo, "toPainting.toGallery");</code>
+ * <code>Gallery g = (Gallery)Cayenne.readNestedProperty(paintingInfo, "toPainting.toGallery");</code>
* <br>
* <br>
* </li>
* <li>Read a property of an object related to this object: <br>
- * <code>String name = (String)CayenneUtils.readNestedProperty(painting, "toArtist.artistName");</code>
+ * <code>String name = (String)Cayenne.readNestedProperty(painting, "toArtist.artistName");</code>
* <br>
* <br>
* </li>
* <li>Read to-many relationship list:<br>
- * <code>List exhibits = (List)CayenneUtils.readNestedProperty(painting, "toGallery.exhibitArray");</code>
+ * <code>List exhibits = (List)Cayenne.readNestedProperty(painting, "toGallery.exhibitArray");</code>
* <br>
* <br>
* </li>
* <li>Read to-many relationship in the middle of the path:<br>
- * <code>List<String> names = (List<String>)CayenneUtils.readNestedProperty(artist, "paintingArray.paintingName");</code>
+ * <code>List<String> names = (List<String>)Cayenne.readNestedProperty(artist, "paintingArray.paintingName");</code>
* <br>
* <br>
* </li>
* </ul>
*/
- public static Object readNestedProperty(Persistent p, String path) {
- return readNestedProperty(p, path, tokenizePath(path), 0, 0);
- }
+ public static Object readNestedProperty(Object o, String path) {
- /**
- * Recursively resolves nested property path
- */
- private static Object readNestedProperty(
- Persistent p,
- String path,
- String[] tokenizedPath,
- int tokenIndex,
- int pathIndex) {
+ if (o == null) {
+ return null;
+ }
+ else if (o instanceof DataObject) {
+ return ((DataObject) o).readNestedProperty(path);
+ }
+ else if (o instanceof Collection<?>) {
- Object property = readSimpleProperty(p, tokenizedPath[tokenIndex]);
+ // This allows people to put @size at the end of a property
+ // path and be able to find out the size of a relationship.
- if (tokenIndex == tokenizedPath.length - 1) { // last component
- return property;
- }
+ Collection<?> collection = (Collection<?>) o;
- pathIndex += tokenizedPath[tokenIndex].length() + 1;
- if (property == null) {
- return null;
- }
- else if (property instanceof Persistent) {
- return readNestedProperty(
- (Persistent) property,
- path,
- tokenizedPath,
- tokenIndex + 1,
- tokenIndex);
- }
- else if (property instanceof Collection) {
-
- Collection<?> collection = (Collection) property;
-
- if (tokenIndex < tokenizedPath.length - 1) {
- if (tokenizedPath[tokenIndex + 1].equals(PROPERTY_COLLECTION_SIZE)) {
- return collection.size();
- }
+ if (path.equals(PROPERTY_COLLECTION_SIZE)) {
+ return collection.size();
}
// Support for collection property in the middle of the path
- Collection<Object> result = property instanceof List
+ Collection<Object> result = o instanceof List<?>
? new ArrayList<Object>()
: new HashSet<Object>();
- for (Object object : collection) {
- if (object instanceof CayenneDataObject) {
- Object tail = readNestedProperty(
- (CayenneDataObject) object,
- path,
- tokenizedPath,
- tokenIndex + 1,
- tokenIndex);
+ for (Object item : collection) {
+ if (item instanceof DataObject) {
+ DataObject cdo = (DataObject) item;
+ Object rest = cdo.readNestedProperty(path);
- if (tail instanceof Collection) {
+ if (rest instanceof Collection<?>) {
// We don't want nested collections. E.g.
- // readNestedProperty("paintingArray.paintingTitle")
- // should return List<String>
- result.addAll((Collection<?>) tail);
+ // readNestedProperty("paintingArray.paintingTitle") should return
+ // List<String>
+ result.addAll((Collection<?>) rest);
}
else {
- result.add(tail);
+ result.add(rest);
}
}
}
+
return result;
}
- else {
- // read the rest of the path via introspection
- return PropertyUtils.getProperty(property, path.substring(pathIndex));
- }
- }
- private static final String[] tokenizePath(String path) {
- if (path == null) {
- throw new NullPointerException("Null property path.");
+ if ((null == path) || (0 == path.length())) {
+ throw new IllegalArgumentException(
+ "the path must be supplied in order to lookup a nested property");
}
- if (path.length() == 0) {
- throw new IllegalArgumentException("Empty property path.");
+ int dotIndex = path.indexOf('.');
+
+ if (0 == dotIndex) {
+ throw new IllegalArgumentException(
+ "the path is invalid because it starts with a period character");
}
- // take a shortcut for simple properties
- if (!path.contains(".")) {
- return new String[] {
- path
- };
+ if (dotIndex == path.length() - 1) {
+ throw new IllegalArgumentException(
+ "the path is invalid because it ends with a period character");
}
- StringTokenizer tokens = new StringTokenizer(path, ".");
- int length = tokens.countTokens();
- String[] tokenized = new String[length];
- for (int i = 0; i < length; i++) {
- String temp = tokens.nextToken();
- if (temp.endsWith("+")) {
- tokenized[i] = temp.substring(0, temp.length() - 1);
- }
- else {
- tokenized[i] = temp;
- }
+ if (-1 == dotIndex) {
+ return readSimpleProperty(o, path);
}
- return tokenized;
- }
- private static final Object readSimpleProperty(Persistent p, String propertyName) {
- Property property = getProperty(p, propertyName);
+ String path0 = path.substring(0, dotIndex);
+ String pathRemainder = path.substring(dotIndex + 1);
- if (property != null) {
- // side effect - resolves HOLLOW object
- return property.readProperty(p);
- }
+ // this is copied from the old code where the placement of a plus
+ // character at the end of a segment of a property path would
+ // simply strip out the plus. I am not entirely sure why this is
+ // done. See unit test 'testReadNestedPropertyToManyInMiddle1'.
- // handling non-persistent property
- Object result = null;
- if (p instanceof DataObject) {
- result = ((DataObject) p).readPropertyDirectly(propertyName);
+ if ('+' == path0.charAt(path0.length() - 1)) {
+ path0 = path0.substring(0, path0.length() - 1);
}
- if (result != null) {
- return result;
+ Object property = readSimpleProperty(o, path0);
+ return readNestedProperty(property, pathRemainder);
+ }
+
+ private static final Object readSimpleProperty(Object o, String propertyName) {
+ if (o instanceof Persistent) {
+
+ Property property = getProperty((Persistent) o, propertyName);
+
+ if (property != null) {
+ return property.readProperty(o);
+ }
}
- // there is still a change to return a property via introspection
- return PropertyUtils.getProperty(p, propertyName);
+ // handling non-persistent property
+ return PropertyUtils.getProperty(o, propertyName);
}
/**
Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneDataObject.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneDataObject.java?rev=1032829&r1=1032828&r2=1032829&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneDataObject.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/CayenneDataObject.java Tue Nov 9 03:05:30 2010
@@ -37,6 +37,7 @@ import org.apache.cayenne.map.EntityReso
import org.apache.cayenne.map.ObjAttribute;
import org.apache.cayenne.map.ObjEntity;
import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.reflect.PropertyUtils;
import org.apache.cayenne.validation.BeanValidationFailure;
import org.apache.cayenne.validation.ValidationFailure;
import org.apache.cayenne.validation.ValidationResult;
@@ -108,7 +109,65 @@ public class CayenneDataObject extends P
* @since 1.0.5
*/
public Object readNestedProperty(String path) {
- return Cayenne.readNestedProperty(this, path);
+
+ if ((null == path) || (0 == path.length())) {
+ throw new IllegalArgumentException(
+ "the path must be supplied in order to lookup a nested property");
+ }
+
+ int dotIndex = path.indexOf('.');
+
+ if (0 == dotIndex) {
+ throw new IllegalArgumentException(
+ "the path is invalid because it starts with a period character");
+ }
+
+ if (dotIndex == path.length() - 1) {
+ throw new IllegalArgumentException(
+ "the path is invalid because it ends with a period character");
+ }
+
+ if (-1 == dotIndex) {
+ return readSimpleProperty(path);
+ }
+
+ String path0 = path.substring(0, dotIndex);
+ String pathRemainder = path.substring(dotIndex + 1);
+
+ // this is copied from the old code where the placement of a plus
+ // character at the end of a segment of a property path would
+ // simply strip out the plus. I am not entirely sure why this is
+ // done. See unit test 'testReadNestedPropertyToManyInMiddle1'.
+
+ if ('+' == path0.charAt(path0.length() - 1)) {
+ path0 = path0.substring(0, path0.length() - 1);
+ }
+
+ Object property = readSimpleProperty(path0);
+
+ if (property == null) {
+ return null;
+ }
+ else if (property instanceof DataObject) {
+ return ((DataObject) property).readNestedProperty(pathRemainder);
+ }
+ else {
+ return Cayenne.readNestedProperty(property, pathRemainder);
+ }
+ }
+
+ private final Object readSimpleProperty(String property) {
+
+ // side effect - resolves HOLLOW object
+ Object object = readProperty(property);
+
+ // if a null value is returned, there is still a chance to
+ // find a non-persistent property via reflection
+ if (object == null && !values.containsKey(property)) {
+ object = PropertyUtils.getProperty(this, property);
+ }
+
+ return object;
}
public Object readProperty(String propertyName) {