Announcement

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

    RestDatasource treats schema attributes as data

    Hi,

    I have a list that is populated through a RestDatasource. An example of the XML that the server returns on a GET request:

    Code:
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <response>
      <endRow>1</endRow>
      <startRow>0</startRow>
      <status>0</status>
      <totalRows>2</totalRows>
      <data>
        <record xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="basicGameType">
         <description>Description 1</description>
         <id>340</id>
       </record>
       <record xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="basicGameType">
         <description>Description 2</description>
         <id>395</id>
       </record>
      </data>
    </response>
    Notice the xmlns:xsi and the xsi:type attributes added to the records.

    This data is displayed correctly in the ListGrid. When I click on a row in the grid, the user is allowed to edit the data in a separate form. This also works fine by calling listGrid.edit(event.getRecord()).

    However, when I save the edited record, the response sent back to the server looks like this:

    Code:
    <request>
        <data>
            <basicGameType>
                <description>New description</description>
                <xmlns:xsi>http://www.w3.org/2001/XMLSchema-instance</xmlns:xsi>
                <xsi:type>basicGameType</xsi:type>
                <id>340</id>
                <showPrizeTable>false</showPrizeTable>
            </basicGameType>
        </data>
        <oldValues>
            <description>Description 1</description>
            <xmlns:xsi>http://www.w3.org/2001/XMLSchema-instance</xmlns:xsi>
            <xsi:type>basicGameType</xsi:type>
            <id>340</id>
            <showPrizeTable>false</showPrizeTable>
        </oldValues>
        <dataSource>basicGameType</dataSource>
        <operationType>update</operationType>
        <operationId></operationId>
        <startRow></startRow>
        <endRow></endRow>
        <sortBy></sortBy>
        <textMatchStyle></textMatchStyle>
        <componentId>isc_OID_12</componentId>
    </request>
    Notice that the attributes now are nodes for each record:
    Code:
                 
    <xmlns:xsi>http://www.w3.org/2001/XMLSchema-instance</xmlns:xsi>
    <xsi:type>basicGameType</xsi:type>
    This makes my server side code break, as JAXB is unable to find matching javabean properties for these nodes. Is there any way to not make SmartGWT add these schema related attributes as nodes in the corresponding response?

    Thanks
    Rolf

    #2
    setSendExtraFields(false) to limit the data to only declared fields.

    Comment


      #3
      Thanks.

      However, I have some other extra fields I want to send back to the server. (In my actual code, the form has an associated ListGrid. This Grid is populated from the Form by calling grid.setData.

      Also, when using setSendExtraFields, the oldValues section of the xml still contains fields for xsi:type and xmlns:xsl.

      Is there a way to explicitly remove fields by name?

      Rolf
      Last edited by rolgon; 24 Sep 2009, 01:00.

      Comment


        #4
        An override of transformRequest() allows you to do whatever pre-processing you want client-side.

        Comment


          #5
          Thanks.

          I've written an override of transformRequest that removes all attributes containing colon from the request.

          However, I could not find any way to remove an attribute from the record in request.getData(). So I created a new record instead and added all attributes that I'm interested in.

          Like this:
          Code:
          	//Remove xsi:type and xmlns:xsi attributes from the original data
          	Record[] data = Record.convertToRecordArray(request.getData());;
          	Record newRec = new Record();
          	Record rec = data[0]
             	   String[] attr = rec.getAttributes();
             	   for(String a:attr) {
          		if(a.indexOf(':') == -1) {
          			newRec.setAttribute(a, rec.getAttributeAsObject(a));
          		}
          	}
          
                request.setData(newRec.getJsObj());
          The call to rec.getAttributeAsObject(a) makes the client fail for some reason. If I replace this with rec.getAttribute(a) it works fine except for the attributes that I have that are arrays of other attributes(I then get [Object], [Object] instead of xml). For those getAttributeAsObject works, but not for all.

          So, any idea why getAttributeAsObject fails? And, is there any better way to do this? I just want to remove attributes from the request that contains colon(":")

          Thanks
          Rolf
          Last edited by rolgon; 24 Sep 2009, 22:19.

          Comment


            #6
            How did you get this to work at all..

            I assume that you're using Jersey / JAXB to build Rest XML.. Even with your output, I don't get any data to display, it only works if I remove the

            Code:
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="basicGameType"
            The list grid populates with --'s, it's empty.

            I've set this property on the grid

            Code:
            clientGrid.setEmptyCellValue("--");

            Comment


              #7
              Hi,

              Yes, I'm using Jersey/JAXB.

              To be clear, I had a list grid that was populated from a backend using JAXB/Jersey. In some cases, the XML returned by Jersey contains type information as attributes in the xml(xsi:type etc). (Typically when using @XmlSeeAlso). My listgrid was displayed successfully.

              But, in the next step, I wanted to update a record in the received list grid. When I send the data back to my backend, the xsi:type etc attributes are now records, which makes Jersey/JAXB very unhappy. So, my fix was to remove these attributes from all update/save requests from my rest datasources.

              However, the approach described earlier by me did not work 100%, so I did this by creating a native javascript method that removes attributes from the request object.

              My datasource then contains the following code:
              Code:
                   public static native void deleteElement(JavaScriptObject elem, String attr) /*-{
              		delete elem[attr]
              	}-*/;
              	
              	/**
              	 * Removes xsi:type and xmlns:xsi attributes from request 
              	 */
              	public Object transformRequest(DSRequest request) {
              		if(request.getOperationType() == DSOperationType.UPDATE || request.getOperationType() == DSOperationType.ADD) {
              			Record[] data = Record.convertToRecordArray(request.getData());;
              			Record rec = data[0];
              			deleteElement(rec.getJsObj(), "xsi:type");
              			deleteElement(rec.getJsObj(), "xmlns:xsi");
              
              			JavaScriptObject oldData = request.getAttributeAsJavaScriptObject("oldValues");
              			deleteElement(oldData, "xsi:type");
              			deleteElement(oldData, "xmlns:xsi");
              		}
              		return super.transformRequest(request);
              	}
              This seems to do the job. I no longer gets the xsi:type etc fields sent to my Jasper/JAXB backend, and my backend is able to parse the update/save requests successfully.

              Comment


                #8
                Another update to this problem.

                Although the solution above solved my problem for some of my updates/saves, I got new problems with other Rest GET queries containing these xsi:type attributes. Although the client according to the log got the expected result, it went into a infinite loop where it retrieved the same data from the backend every second or so.

                So, to fix the problem alltogether, I created a servlet filter instead that removed the xml attributes(xsi:... and xlmns:..) from all responses from the server side.

                Something like this:
                Code:
                	public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
                		if(response instanceof HttpServletResponse) {
                			StringWrapper wrapper = new StringWrapper((HttpServletResponse) response);
                			chain.doFilter(request, wrapper);
                			String responseString = wrapper.toString();
                			String newString = responseString.replaceAll("xmlns:xsi=\"[^\"]*\"", "");
                			newString = newString.replaceAll("xsi:type=\"[^\"]*\"", "");
                			response.getWriter().print(newString);
                
                		}
                	}
                StringWrapper is a HttpServletResponseWrapper implementation that saves the result from the filter chain so that the filter can remove the unneccesary attributes from the resulting XML.

                Hopefully, this is helpful for others using Jersey/Jaxb for the SmartGwt backend

                Comment

                Working...
                X