Hi,
I am new to JXPath but it looks great, thanks for
all your hard work. I have just been playing around with it a little as I would
like to use it in a new project that I am working on. I wanted to implement a
generic Factory to create objects and I ran into a small snag. I just wanted to
run this by you. My GenericFactory (attached) is a bit rough around the
edges but it automatically creates properties using reflection to find the
appropriate set method on the parent object, and then instantiates an instance
of the appropriate class (parameter type). This works fine for straight beans
but using the same method for sequences causes a problem because atm it is not
possible to determine whether or not the target property is a sequence or not.
If you can determine that you are creating a sequence then it is possible (in
some circumstances) to determine the type of the objects to be added to the
newly created sequence, and to add them during the construction of the sequence
property. This won't work for generic Collections, but it will work for custom
sequences that implement List, which is what I am using (Castor based beans).
By changing line 178 in
org.apache.commons.jxpath.ri.model.beans.PropertyPointer.java
from
int inx = (index ==
WHOLE_COLLECTION ? 0 : index);
to
int inx = (index ==
WHOLE_COLLECTION ? -1 : index);
I am now able to determine whether or not the
target property for construction is a sequence and is accessed using
an index and I can therefore, in the factory, create the required number of
objects. Previously, it was impossible to tell the difference between /myList
and /myList[1] because the index passed to the Factory in both cases is
0.
So I can now execute calls like:
context.createPathAndSetValue("/myList[2]/name",
"harry");
Even though myList is null to start with, the
GenericFactory can determine that myList is a sequence and it can create 2
objects to add into it after creating and sequence and assigning it to the root
context.
Anyway, I don't think this change should negatively
effect anyone and so I thought that maybe you could add it to the main tree. If
it's not possible, then no problem, I can maintain my own version. I guess a
change like this could potentially cause problems if the Factory coding was a
bit "lazy".
Anyway, once agin, thanks for this kewl
tool.
Warm regards,
Adam Chesney.
=====================================================
Tel: (+44) 117 908 1254 (Direct) Mobile (+44) 7780 962 961 email: [EMAIL PROTECTED] This communication is intended solely for the addressee and is confidential. If you are not the intended recipient, any disclosure, copying, distribution or any action taken or omitted to be taken in reliance on it, is prohibited and may be unlawful. Although this e-mail and any attachments are believed to be free of any virus, or any other defect which might affect any computer or IT system into which they are received and opened, it is the responsibility of the recipient to ensure that they are virus free and no responsibility is accepted by Multicom Products Limited for any loss or damage arising in any way from receipt or use thereof. |
package test; import org.apache.commons.jxpath.*; import java.lang.reflect.*;
/** * <p>Title: </p> * <p>Description: </p> * <p>Copyright: Copyright (c) 2003</p> * <p>Company: </p> * @author Adam J Chesney * @version 1.0 */ public class GenericFactory extends AbstractFactory { public boolean createObject(JXPathContext context, Pointer pointer, Object parent, String name, int index) { try { // grab the parents class Class parent_cls = parent.getClass(); // grab the list of methods for the parent class Method[] methods = parent_cls.getMethods(); // iterate backwards through the methods until we find the first // 'set' or 'add' method which matches the name property and that has just // one parameter for (int i = methods.length-1; i > -1; i--) { String mName = methods[i].getName(); if ( mName.startsWith("set") || mName.startsWith("add") ) { if ( mName.substring(3).equals( name.substring(0,1).toUpperCase() + name.substring(1) ) ) { if ( methods[i].getParameterTypes().length == 1 ) { // we found a matching method, so we grab the class of the parameter Class target_cls = methods[i].getParameterTypes()[0]; // create new one (must have a null constructor) Object obj = target_cls.newInstance(); // invoke the add or set method with the new property on the parent methods[i].invoke( parent, new Object[]{obj} ); // if the index is 0 or greater then this must be a sequence if ( index > -1 ) { // grab the methods of the property Method[] meth = target_cls.getMethods(); // again iterate backwards through the methods looking for the first // add method with one parameter // note: we iterate backwards becuase we are more likely to encounter // a specialized bean method sooner for (int j = meth.length-1; j >-1; j--) { String mn = meth[j].getName(); if (mn.startsWith("add") && meth[j].getParameterTypes().length == 1 ) { // found an add method, so we grab the parameter type Class new_cls = meth[j].getParameterTypes()[0]; for (int k = 0; k <= index; k++) { // and we add enough new objects to the collection to satisfy the index meth[j].invoke( obj, new Object[]{new_cls.newInstance()} ); } break; } } } return true; } } } } } catch (Exception e1) { e1.printStackTrace(); } return false; } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]