Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    No point for XPath Expression

    Hi good folks,

    I've encountered a problem with a databound dynamic form that has me, quite frankly, stumped.

    For the sake of simplicity; let's say I have basic Order and User object. The Order object has a createdBy property which of type User, like so:

    Code:
    public class Order
    {
    
    private User createdBy;
    
    public void setCreatedBy(User user)
    {
    this.createdBy = user;
    }
    
    public User getCreatedBy()
    {
    return this.createdBy;
    }
    }
    User has a userId of type String; like so:

    Code:
    public class User
    {
    private String userId
    
    public void setUserId(String id)
    {
    this userId=id;
    }
    
    public String getUserId()
    {
    return userId;
    }
    }
    In my Order datasource mapping file, I render the userId through an xPath expression;i.e.:

    Code:
    	<field name="createdById" type="text" title="Created By" valueXPath="createdBy/userId" required="true"/>

    This works fine when I for instance display an order in a ListGrid. The user id of the user that created the order is rendered properly; so I know the datasource mapping is working.

    However, when I try to now SAVE an instance of Order back to the server-side DAO object; I get the following order:

    Code:
    21:27:13,082  WARN Reflection:364 - Failed to convert Map arg to bean of type: com.acmecorp.shared.mode
    l.Order - because bean population via DataTools.setProperties() threw the following Exception: org.apache.commons.jxp
    ath.JXPathNotFoundException: No pointer for xpath: createdBy/userId
    21:27:13,083  WARN Reflection:364 - Exception occurred attempting to map arguments: org.apache.commons.jxpath.JXPathNotF
    oundException: No pointer for xpath: createdBy/userId in org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.getPoin
    ter(JXPathContextReferenceImpl.java:468)
    21:27:13,083  WARN RequestContext:369 - dsRequest.execute() failed: 
    java.lang.Exception: Unable to assign a required or optional argument to slot #2 taking type: com.acmecorp.shared.model.Order of method:
    
    public final com.isomorphic.datasource.DSResponse $Proxy12.add(com.isomorphic.datasource.DSRequest,com.acmecorp.shared.model.Order) throws java.lang.Exception
    
    No remaining optional arguments match this type and all required arguments passed by the client have already been assign
    ed.
    
    
    	at com.isomorphic.base.Reflection.adaptArgsAndInvoke(Reflection.java:869)
    	at com.isomorphic.datasource.DataSourceDMI.execute(DataSourceDMI.java:483)
    	at com.isomorphic.datasource.DataSourceDMI.execute(DataSourceDMI.java:63)
    	at com.isomorphic.datasource.DSRequest.execute(DSRequest.java:1247)
    	at com.isomorphic.servlet.IDACall.handleDSRequest(IDACall.java:155)
    	at com.isomorphic.servlet.IDACall.processRequest(IDACall.java:106)
    	at com.isomorphic.servlet.IDACall.doPost(IDACall.java:54)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    	at com.isomorphic.servlet.BaseServlet.service(BaseServlet.java:152)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
    	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
    	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
    	at java.lang.Thread.run(Thread.java:619)
    Any ideas? I can't figure out for the life of me why this is failing.

    #2
    Full DS file for the sake of completeness:

    Code:
    <DataSource
    	ID="Order"
    	serverType="generic">
    	<fields>
    		<field name="id" type="sequence" hidden="false" primaryKey="true"/>
    		<field name="title" type="text" title="Title" length="255" required="true"/>
    		<field name="type" type="enum" title="Type" length="20" required="true"/>
    		<field name="status" type="enum" title="Status" length="20" required="true"/>
    		<field name="requestedDate" type="date" title="Request Date" required="true"/>
    		<field name="closedDate" type="date" title="Closed Date"/>
    		<field name="accountId" type="int" title="Account" valueXPath="account/id" required="true"/>
    		<field name="accountName" type="text" title="Account" valueXPath="account/company"/>
    		<field name="csaId" type="int" title="CSA" valueXPath="csa/id"/>
    		<field name="csaName" type="text" title="CSA" valueXPath="concat(csa/account/username, ':', csa/id)"/>
    		<field name="createdById" type="text" title="Created By" valueXPath="createdBy/userId" required="true"/>
    		<field name="createdByName" type="text" title="Created By" valueXPath="concat(createdBy/firstName, ' ', createdBy/lastName)"/>
    		<field name="assignedToId" type="text" title="Assigned To" valueXPath="assignedTo/userId"/>
    		<field name="assignedToName" type="text" title="Assigned To" valueXPath="concat(assignedTo/firstName, ' ', assignedTo/lastName)"/>
    		
    	</fields>
    	
    	 <serverObject lookupStyle="spring" bean="orderDAO"/>
    	 
    </DataSource>

    Comment


      #3
      Hello SiccoNaets,

      From everything you've shown, and from exactly analogous sample in the Showcase, this is fine. The only thing we can suggest is a strange interaction between Spring and JXPath, so you might try upgrading both of these libraries in your project? If you can create a standalone test case that involves just changing one of the Pro/EE sample projects, we can take a look.

      Comment


        #4
        Thanks for the response Isomorphic. The version of Spring I'm using is "3.0.0.RELEASE". The version of JXPath I'm using is "1.3". What versions does the showcase use? I can try switching to those and see if that makes the error go away.

        I'm surprised the Spring version would even play a role in this - I wouldn't think Spring really played a role in this part of the datasource marshalling/unmarshalling process (other than helping to find the DAO)...

        Comment


          #5
          The Showcase is using the same versions of those .jars that you find in your SDK.

          The reason we suspect Spring is because of the $Proxy in the classname in part of your server log. Spring has wrapped your object in a dynamically generated proxy, and this may interfere with JXPath's ability to retrieve properties.

          Comment


            #6
            Aah, gotcha. That makes sense, actually.

            That being said, I don't think the Spring version matters; what was generating the proxy object was my actual spring configuration:

            <bean id="orderDAO" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
            <property name="transactionManager" ref="transactionManager"/>
            <property name="target" ref="orderDAOTarget"/>
            <property name="transactionAttributes">
            <props>
            <prop key="fetch">PROPAGATION_REQUIRED</prop>
            <prop key="add">PROPAGATION_REQUIRED</prop>
            <prop key="update">PROPAGATION_REQUIRED</prop>
            <prop key="remove">PROPAGATION_REQUIRED</prop>
            </props>
            </property>
            </bean>

            <bean id="orderDAOTarget" class="com.acmecorp.server.dao.orderDAOImpl">
            <property name="sessionFactory" ref="sessionFactory"/>
            </bean>
            (just following the examples from the Showcase on how to wrap Spring transactions around the actual DAO calls).

            So I changed the DataSource configuration to directly call the orderDAOImpl class. Of course, this means I get lazy initialization exceptions on fetch; but I can fix that later.

            Spring is now giving JXPath the actual OrderDAOImpl object (no more references to $Proxy) but the error remains. So it's gotta be something else:

            14:34:33,085 WARN Reflection:364 - Failed to convert Map arg to bean of type: com.acmecorp.shared.mode
            l.Order - because bean population via DataTools.setProperties() threw the following Exception: org.apache.commons.jxp
            ath.JXPathNotFoundException: No pointer for xpath: createdBy/userId
            14:34:33,086 WARN Reflection:364 - Exception occurred attempting to map arguments: org.apache.commons.jxpath.JXPathNotF
            oundException: No pointer for xpath: createdBy/userId in org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.getPoin
            ter(JXPathContextReferenceImpl.java:468)
            14:34:33,086 WARN RequestContext:369 - dsRequest.execute() failed:
            java.lang.Exception: Unable to assign a required or optional argument to slot #2 taking type: com.thinkingphones.acmecorp.shared.model.Order of method:

            public com.isomorphic.datasource.DSResponse com.acmecorp.server.dao.OrderDAOImpl.add(com.isomorphic.
            datasource.DSRequest,com.acmecorp.shared.model.Order) throws java.lang.Exception

            No remaining optional arguments match this type and all required arguments passed by the client have already been assign
            ed.


            at com.isomorphic.base.Reflection.adaptArgsAndInvoke(Reflection.java:869)
            at com.isomorphic.datasource.DataSourceDMI.execute(DataSourceDMI.java:483)
            at com.isomorphic.datasource.DataSourceDMI.execute(DataSourceDMI.java:63)
            at com.isomorphic.datasource.DSRequest.execute(DSRequest.java:1247)
            at com.isomorphic.servlet.IDACall.handleDSRequest(IDACall.java:155)
            at com.isomorphic.servlet.IDACall.processRequest(IDACall.java:106)
            at com.isomorphic.servlet.IDACall.doPost(IDACall.java:54)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
            at com.isomorphic.servlet.BaseServlet.service(BaseServlet.java:152)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
            at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
            at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
            at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
            at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
            at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
            at java.lang.Thread.run(Thread.java:619)
            14:34:33,087 DEBUG RPCManager:406 - Content type for RPC transaction: text/plain; charset=UTF-8
            14:34:33,088 DEBUG RPCManager:406 - non-DMI response, dropExtraFields: false

            Comment


              #7
              Does User have a zero-argument public constructor? It needs one if it's going to be auto-created.

              Does the problem go away if you hand-create the User subobject before calling setProperties()?

              What's happening with your other valueXPaths? Are any succeeding on write (eg csa/id, which is earlier)?

              Do you still get a failure if you remove all valueXPaths except this one?

              Comment


                #8
                Hi Isomorphic,

                regarding your questions:

                1) Yes, user has a zero-argument public constructor:

                Code:
                public class User implements java.io.Serializable {
                
                	private String userId;
                	private String firstName;
                	private String lastName;
                	
                	public User()
                	{
                		
                	}
                
                
                	public String getUserId() {
                		return this.userId;
                	}
                
                	public void setUserId(String userId) {
                		this.userId = userId;
                	}
                
                	public String getFirstName() {
                		return this.firstName;
                	}
                
                	public void setFirstName(String firstName) {
                		this.firstName = firstName;
                	}
                
                	public String getLastName() {
                		return this.lastName;
                	}
                
                	public void setLastName(String lastName) {
                		this.lastName = lastName;
                	}
                
                }
                2) I'm not sure how to hand-create the user sub-object prior to calling setProperties - isn't that method calling taking place inside propriatary isomorphic code? I.e. inside com.isomorphic.base.Reflection.adaptArgsAndInvoke (according to the stack-trace).

                3) I removed the createdBy/userId; csa/id (and any of the others that had a valueXPath in the datasource definition) failed with the same error

                4) If I remove all properties with valueXPath definitions from the datasource; the object gets submitted fine to the DAO and is persisted through to Hibernate (after removing non-null constraints in the HBM mapping files and on the database, of course).

                Comment


                  #9
                  2) don't declare an Order as an argument to your DMI method, instead, use new Order(), setCreatedBy(new User()) and then call DataTools.setProperties() on the Order passing dsRequest.getValues(). This simulates what DMI does when there is an Order argument, except you are pre-creating the User object.

                  3) can you clarify - all instances of valueXPath fail for you with similar messages, or is it just this one field?

                  Comment


                    #10
                    Understood.

                    Ok, so I changed my method signature on the DAO object to this:

                    Code:
                    public DSResponse add(DSRequest dsRequest) throws Exception
                    {
                    Order order = new Order();
                    order.setAccount(new Account());
                    order.setCsa(new CSA());
                    order.setCreatedBy(new User());
                    DataTools.setProperties(dsRequest.getValues(), order);
                    
                    //rest of code to persist to Hibernate
                    }
                    Doing that fixes the JXPath problem - the object is correctly created and populated and passed to Hibernate. Of course, Hibernate now complains that Account, CSA and User are unsaved-transient-instances (which makes sense; since these are basically new accounts, csa's and users without ids). So I obviously need to change the code so that instead of creating a new account/csa/userid; it loads the right objects from hibernate, stuffs those in the new Order and then persists the order back to the database. But that's something I can fix later.

                    Thanks Isomorphic! And yeah, all the instances of valueXPath were failing on add(); not use createdBy(); but I suspect this will fix it.

                    Comment


                      #11
                      Good to hear you have an approach. If you can create a standalone test case for the failing valueXPath we can look into why that case fails while the Address case in the Showcase works - this would save you some extra steps.

                      Comment


                        #12
                        Thanks, I'll see what I can rig up in terms of a trimmed down example. It might take a few days; I'll post here again when I have it.

                        Comment


                          #13
                          I'm doing something similar to what SiccoNaets is doing at http://forums.smartclient.com/showthread.php?p=45741

                          The documentation here says setProperties automatically creates the inner beans: http://www.smartclient.com/smartgwtee/server/javadoc/com/isomorphic/util/DataTools.html#setProperties(java.util.Map, java.lang.Object, com.isomorphic.datasource.DataSource).

                          However, despite the above, it looks like we need to create the inner beans and set them in the parent bean ourselves.

                          So in my server-side DMI's add(), I instantiate and manually set my bean's inner beans like SiccoNaets then call the following...
                          Code:
                          DataTools.setProperties(dsRequest.getValues(), beanWithInnerBeans, DataSource.forName("myDMI"));
                          However, it says it can't set the properties giving the following...
                          Code:
                          DataTools - setProperties: couldn't set:
                          [INFO] {
                          [INFO]     name:"No such property"
                          [INFO] }
                          In the above, the name field is in the inner bean (see ds.xml file below).

                          I'm not sure but I'm guessing for each field, setProperties() parses the XPath from the DataSource argument to know which bean member to set. Am I doing this correctly or is there some other mechanism to set inner beans.

                          So to clarify my two problems:
                          1) Inner bean assignment does not work with XPath attributes in data source definition files
                          2) setProperties does not automatically create inner beans

                          By the way, I'm using SmartGWT EE 2.3 running on a Jetty container.

                          Here is part of my data source ds.xml file...

                          Code:
                          <DataSource
                              ID="myDMI"
                              serverType="generic"
                              >
                              <fields>
                                  <field name="id"
                                         type="sequence"
                                         hidden="true"
                                         primaryKey="true"
                                         valueXPath="common/id/id"/>
                                  <field name="name"
                                         type="text"
                                         title="Name"
                                         length="128"
                                         required="true"
                                         valueXPath="common/name/name"/>
                          
                          ...[more inner bean fields]...
                          Any help would be most appreciated. Thanks!

                          Comment


                            #14
                            1. use DataSource.setProperties(), not DataTools.setProperties()

                            2. be sure all inner beans have zero argument public constructors that will not throw exceptions

                            Comment


                              #15
                              1) Thanks for the advice!

                              2) Looks like it's not creating the inner beans...

                              When I ran the code manually creating the inner beans, it works great but when I took out that code, it gave me this error...

                              Code:
                              org.apache.commons.jxpath.JXPathNotFoundException: No pointer for xpath: common/name/name
                              	at org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.getPointer(JXPathContextReferenceImpl.java:468)
                              	at org.apache.commons.jxpath.ri.JXPathContextReferenceImpl.getPointer(JXPathContextReferenceImpl.java:452)
                              	at com.isomorphic.datasource.DataSource.setProperties(DataSource.java:884)
                              	at project.MyDMI.add(MyDMI.java:42)
                              	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                              	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                              	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                              	at java.lang.reflect.Method.invoke(Method.java:597)
                              	at com.isomorphic.base.Reflection.adaptArgsAndInvoke(Reflection.java:879)
                              	at com.isomorphic.datasource.DataSourceDMI.execute(DataSourceDMI.java:553)
                              	at com.isomorphic.datasource.DataSourceDMI.execute(DataSourceDMI.java:63)
                              	at com.isomorphic.datasource.DSRequest.execute(DSRequest.java:1379)
                              	at com.isomorphic.servlet.IDACall.handleDSRequest(IDACall.java:155)
                              	at com.isomorphic.servlet.IDACall.processRequest(IDACall.java:106)
                              	at com.isomorphic.servlet.IDACall.doPost(IDACall.java:54)
                              	at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
                              	at com.isomorphic.servlet.BaseServlet.service(BaseServlet.java:152)
                              	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
                              	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
                              	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1097)
                              	at com.google.inject.servlet.FilterChainInvocation.doFilter(FilterChainInvocation.java:67)
                              	at com.google.inject.servlet.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:122)
                              	at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:110)
                              	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1088)
                              	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
                              	at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
                              	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
                              	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:729)
                              	at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
                              	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
                              	at org.mortbay.jetty.handler.RequestLogHandler.handle(RequestLogHandler.java:49)
                              	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
                              	at org.mortbay.jetty.Server.handle(Server.java:324)
                              	at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
                              	at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:843)
                              	at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:647)
                              	at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
                              	at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
                              	at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
                              	at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)

                              Comment

                              Working...
                              X