Announcement

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

    Grouped grids with record.toMap

    Using record.toMap() on a grouped map (or a tree) can crash the browser due to infinite recursion. After performing some operation it seems that the record itself contains a reference to the Tree and when calling record.toMap it starts going infinitely.

    After the stackoverflow the browser also doesn't recover.

    This was tested on the latest 4.0 nightly, with Firefox 26.0 on GWT 2.5.1.

    If you want I can provide a similar example with a TreeGrid.



    Code:
    package com.genohm.slims.client.gui;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.google.gwt.core.client.GWT;
    import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
    import com.google.gwt.user.client.Timer;
    import com.smartgwt.client.core.Function;
    import com.smartgwt.client.data.DataSource;
    import com.smartgwt.client.data.Record;
    import com.smartgwt.client.widgets.grid.ListGrid;
    import com.smartgwt.client.widgets.grid.events.DataArrivedEvent;
    import com.smartgwt.client.widgets.grid.events.DataArrivedHandler;
    
    public class TestGroupGrid implements EntryPoint {
    
    	private Record selectThis;
    	
    	@Override
    	public void onModuleLoad() {
    		DataSource.load("Unit", new Function() { //Load datasource (we use dynamic datasources)
    			@Override
    			public void execute() {
    				DataSource ds = DataSource.get("Unit");
    				
    				final ListGrid listGrid = new ListGrid();
    				listGrid.setGroupByField("unit_abbreviation");
    				listGrid.setDataSource(ds);
    				listGrid.setAutoFetchData(true);
    				
    				listGrid.addDataArrivedHandler(new DataArrivedHandler() {
    					@Override
    					public void onDataArrived(DataArrivedEvent event) {
    						listGrid.getGroupTree();
    						if (selectThis != null) {
    							//reselect the record we need to select
    							listGrid.selectRecord(listGrid.getRecordIndex(selectThis));
    							
    							//This will destroy everything!
    							System.err.println(selectThis.toMap());
    							
    						} else {
    							//select the first record (skip the group row)
    							listGrid.selectRecord(1);
    						}
    					}
    				});
    				
    				//trigger a refresh 
    				new Timer() {
    					@Override
    					public void run() {
    						//keep the selected record after refresh
    						selectThis = listGrid.getSelectedRecord();
    						
    						listGrid.invalidateCache();
    						listGrid.fetchData();
    					}
    				}.schedule(2000);
    
    				listGrid.draw();
    				
    			}
    		}, false);
    		
    		GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
    			@Override
    			public void onUncaughtException(Throwable e) {
    				e.printStackTrace();
    			}
    		});
    	}
    
    }
    A safer print of selectThis:
    Code:
    key: unit_type value: SCALAR
    key: unit_fk_dimension value: 1
    key: unit_pk value: 1
    key: unit_createdOn value: Fri Dec 20 2013 12:18:03 GMT+0100 (CET)
    key: unit_abbreviation value:  
    key: groupParentId value: null
    key: _groupTree_isc_ListGrid_0 value: [object Object] <= I think this causes the record to refer to itself ultimately, causing infinite recursion for record.toMap()
    key: $42c value: isc_ListGrid_0_groupTree_isc_OID_0
    key: _autoAssignedName value: true
    key: name value: 0_1
    key: _cachedLength_isc_ListGrid_0_groupTree_isc_OID_0 value: 1
    key: isFolder value: null
    key: _selection_3 value: false
    The exception: (trimmed)
    Code:
    java.lang.StackOverflowError
    	at com.google.gwt.dev.util.log.AbstractTreeLogger.causedBySpecialError(AbstractTreeLogger.java:330)
    	at com.google.gwt.dev.util.log.AbstractTreeLogger.log(AbstractTreeLogger.java:205)
    	at com.google.gwt.core.ext.TreeLogger.log(TreeLogger.java:281)
    	at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:143)
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:571)
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:279)
    	at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
    	at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
    	at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:242)
    	at sun.reflect.GeneratedMethodAccessor107.invoke(Unknown Source)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    	at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
    	at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
    	at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
    	at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:338)
    	at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:219)
    	at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:571)
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:279)
    	at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
    	at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
    	at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:242)
    	at sun.reflect.GeneratedMethodAccessor107.invoke(Unknown Source)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    	at java.lang.reflect.Method.invoke(Method.java:597)
    ....
    Last edited by RubenSimoens; 10 Jan 2014, 08:31.

    #2
    This method is not safe to call on arbitrary data structures that contain loops (like Trees, with their parent<->child links), and we don't plan to make it safe for that purpose (would add overhead and complexity). Use DataSource.copyRecord() first if you want to obtain a Map of just data for the declared DataSource fields.

    Comment

    Working...
    X