Google Web Toolkit Deferred Binding Issue
Posted
by snctln
on Stack Overflow
See other posts from Stack Overflow
or by snctln
Published on 2010-04-16T18:39:18Z
Indexed on
2010/04/16
18:43 UTC
Read the original article
Hit count: 345
I developed a web app using GWT about 2 years ago, since then the application has evolved. In its current state it relies on fetching a single XML file and parsing the information from it. Overall this works great. A requirement of this app is that it needs to be able to be ran from the filesystem (file:///..) as well as the traditional model of running from a webserver (http://...)
Fetching this file from a webserver works exactly as expected using a RequestBuilder object. When running the app from the filesystem Firefox, Opera, Safari, and Chrome all behave as expected. When running the app from the filesystem using IE7 or IE8 the RequestBuilder.send() call fails, the information about the error suggests that there is a problem accessing the file due to violating the same origin policy. The app worked as expected in IE6 but not in IE7 or IE8.
So I looked at the source code of RequestBuilder.java and saw that the actual request was being executed with an XMLHttpRequest GWT object. So I looked at the source code for XMLHttpRequest.java and found out some information.
Here is the code (starts at line 83 in XMLHttpRequest.java)
public static native XMLHttpRequest create() /*-{
if ($wnd.XMLHttpRequest) {
return new XMLHttpRequest();
} else {
try {
return new ActiveXObject('MSXML2.XMLHTTP.3.0');
} catch (e) {
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
}-*/;
So basically if an XMLHttpRequest cannot be created (like in IE6 because it is not available) an ActiveXObject is used instead.
I read up a little bit more on the IE implementation of XMLHttpRequest, and it appears that it is only supported for interacting with files on a webserver.
I found a setting in IE8 (Tools->Internet Options->Advanced->Security->Enable native XMLHTTP support), when I uncheck this box my app works. I assume this is because I am more of less telling IE to not use their implementation of XmlHttpRequest, so GWT just uses an ActiveXObject because it doesn't think the native XmlHttpRequest is available.
This fixes the problem, but is hardly a long term solution.
I can currently catch a failed send request and verify that it was trying to fetch the XML file from the filesystem using normal GWT. What I would like to do in this case is catch the IE7 and IE8 case and have them use a ActiveXObject instead of a native XmlHttpRequest object.
There was a posting on the GWT google group that had a supposed solution for this problem (link). Looking at it I can tell that it was created for an older version of GWT. I am using the latest release and think that this is more or less what I would like to do (use GWT deferred binding to detect a specific browser type and run my own implementation of XMLHttpRequest.java in place of the built in GWT implementation).
Here is the code that I am trying to use
package com.mycompany.myapp.client;
import com.google.gwt.xhr.client.XMLHttpRequest;
public class XMLHttpRequestIE7or8 extends XMLHttpRequest
{
// commented out the "override" so that eclipse and the ant build script don't throw errors
//@Override
public static native XMLHttpRequest create()
/*-{
try
{
return new ActiveXObject('MSXML2.XMLHTTP.3.0');
}
catch (e)
{
return new ActiveXObject("Microsoft.XMLHTTP");
}
}-*/;
// have an empty protected constructor so the ant build script doesn't throw errors
// the actual XMLHttpRequest constructor is empty as well so this shouldn't cause any problems
protected XMLHttpRequestIE7or8()
{
}
};
And here are the lines that I added to my module xml
<replace-with class="com.mycompany.myapp.client.XMLHttpRequestIE7or8">
<when-type-is class="com.google.gwt.xhr.client.XMLHttpRequest"/>
<any>
<when-property-is name="user.agent" value="ie7" />
<when-property-is name="user.agent" value="ie8" />
</any>
</replace-with>
From what I can tell this should work, but my code never runs.
Does anyone have any idea of what I am doing wrong?
Should I not do this via deferred binding and just use native javascript when I catch the fail case instead?
Is there a different way of approaching this problem that I have not mentioned?
All replies are welcome.
© Stack Overflow or respective owner