2011-04-01 168 views
3

我正在研究一个小应用程序并使用GWT构建它。 我刚刚尝试向远程服务器发出请求,该远程服务器将返回响应为JSON。 我试过使用覆盖类型的概念,但我无法得到它的工作。我一直在改变代码,所以它离开了Google GWT教程离开的地方。获取和使用远程JSON数据

JavaScriptObject json; 
    public JavaScriptObject executeQuery(String query) { 
     String url = "http://api.domain.com?client_id=xxxx&query="; 
     RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, 
       URL.encode(url + query)); 
     try { 
      @SuppressWarnings("unused") 
      Request request = builder.sendRequest(null, new RequestCallback() { 
       public void onError(Request request, Throwable exception) { 
        // violation, etc.) 
       } 

       public void onResponseReceived(Request request, 
         Response response) { 
        if (200 == response.getStatusCode()) { 
         // Process the response in response.getText() 
         json =parseJson(response.getText()); 
        } else { 

        } 
       } 
      }); 
     } catch (RequestException e) { 
      // Couldn't connect to server 
     } 
     return json; 
    } 

    public static native JavaScriptObject parseJson(String jsonStr) /*-{ 
     return eval(jsonStr); 
     ; 
    }-*/; 

在Chrome的调试器,我得到umbrellaexception,无法看到堆栈跟踪和GWT调试器的NoSuchMethodError死...任何想法,指针?

+0

你能举个例子对象的你希望通过JSON接受? – Wesley 2011-04-01 22:06:09

+0

{“matching_results”:165958,“videos”:[{“video_id”:“50953524”,“title”:“Wyclef Jean以Akon为特色”}]}我从第一位开始,返回的数据。因为它的块很大而切碎 – zcourts 2011-04-01 23:54:07

回答

5
  1. 使用JsonUtils#safeEval()来评估JSON字符串,而不是直接调用eval()
  2. 更重要的是,不要尝试使用return通过异步调用的结果(如RequestBuilder#sendRequest()回呼叫者 - 使用回调:

    public void executeQuery(String query, 
             final AsyncCallback<JavaScriptObject> callback) 
    { 
        ... 
        try { 
        builder.sendRequest(null, new RequestCallback() { 
         public void onError(Request request, Throwable caught) { 
         callback.onFailure(caught); 
         } 
    
         public void onResponseReceived(Request request, Response response) { 
         if (Response.SC_OK == response.getStatusCode()) { 
          try { 
          callback.onSuccess(JsonUtils.safeEval(response.getText())); 
          } catch (IllegalArgumentException iax) { 
          callback.onFailure(iax); 
          } 
         } else { 
          // Better to use a typed exception here to indicate the specific 
          // cause of the failure. 
          callback.onFailure(new Exception("Bad return code.")); 
         } 
         } 
        }); 
        } catch (RequestException e) { 
        callback.onFailure(e); 
        } 
    } 
    
+0

+1好点! – 2011-04-01 22:06:49

+0

+1最大的错误实际上是试图返回结果,而不是使用回调... – zcourts 2011-04-01 22:37:17

+0

谢谢,修复它。 – 2012-05-17 17:02:26

0

使用eval一般是危险的,可能会导致各种奇怪的行为,如果服务器返回无效JSON(注意,这是必要的,该JSON顶层元素是一个数组,如果你只是使用eval(jsonStr)!)。所以我想使服务器返回一个非常简单的结果一样

[ "hello" ] 

看看,如果仍然出现错误,或者如果你能得到一个更好的堆栈跟踪。

注:我假设,该服务器是相同的URL +端口+协议为您的GWT主机页面下可达(否则,RequestBuilder不会无论如何,由于同源策略的工作。)

+1

顶级JSON元素可以是一个数组(表示为'[...]')或一个对象('{...}') – 2011-04-01 21:52:36

+0

我试过了到parseJson()和response.getText()返回一个格式正确的JSON字符串...我会用什么替代eval() – zcourts 2011-04-01 21:55:39

+0

@Jason:这也是我过去常常相信的原因,在最上层的工作是,该eval假设'{'是代码块的开始,然后当遇到对象中的第一个标签时,它会用'(SyntaxError):invalid label'抱怨 – 2011-04-01 21:57:23

5

一般情况下,你的工作流程说明包括以下四个步骤:

  1. 使请求
  2. 收到JSON文本
  3. 解析JavaScript中的JSON对象
  4. 使用覆盖式

这听起来像你已经有了步骤1和2正常工作,说明这些JavaScript对象。

解析JSON

JSONParser.parseStrict会做很好。您将返回一个JSONValue对象。

这将允许您避免使用自定义本机方法,并且还会确保它在解析JSON时阻止任意代码执行。如果您的JSON有效负载是可信的并且您想要原始速度,请使用JSONParser.parseLenient。无论哪种情况,您都不需要编写自己的解析器方法。

比方说,你希望下面的JSON:

{ 
    "name": "Bob Jones", 
    "occupations": [ 
    "Igloo renovations contractor", 
    "Cesium clock cleaner" 
    ] 
} 

既然你知道了JSON描述了一个对象,你可以告诉你希望得到一个JavaScriptObjectJSONValue

String jsonText = makeRequestAndGetJsonText(); // assume you've already made request 
JSONValue jsonValue = JSONParser.parseStrict(jsonText); 
JSONObject jsonObject = jsonValue.isObject(); // assert that this is an object 
if (jsonObject == null) { 
    // uh oh, it wasn't an object after 
    // do error handling here 
    throw new RuntimeException("JSON payload did not describe an object"); 
} 

描述为覆盖型

现在你知道你的JSON描述了一个对象,你可以得到该对象并描述它在一个JavaScript类的条款。假设你有这样的覆盖类型:

class Person { 
    String getName() /*-{ 
    return this.name; 
    }-*/; 
    JsArray getOccupations() /*-{ 
    return this.occupations; 
    }-*/; 
} 

您可以通过执行铸造让你的新JavaScript对象符合这个Java类:

Person person = jsonObject.getJavaScriptObject().cast(); 
String name = person.getName(); // name is "Bob Jones" 
+0

+1,结合你和杰森的答案取得进展 – zcourts 2011-04-01 22:49:56

0

你其实并不需要解析JSON,你可以使用本机JSNI对象(JavaScript的本地接口)。

下面是一个例子,我从最近的一个项目基本上拉做你正在做同样的事情:

public class Person extends JavaScriptObject{ 
    // Overlay types always have protected, zero argument constructors. 
    protected Person(){} 

    // JSNI methods to get stock data 
    public final native String getName() /*-{ return this.name; }-*/; 
    public final native String getOccupation() /*-{ return this.occupation; }-*/; 

    // Non-JSNI methods below 
} 

,然后检索它像这样:

/** 
    * Convert the string of JSON into JavaScript object. 
    * 
    */ 
    private final native JsArray<Person> asArrayOfPollData(String json) /*-{ 
    return eval(json); 
    }-*/; 

private void retrievePeopleList(){ 

     errorMsgLabel.setVisible(false); 

     String url = JSON_URL; 
     url = URL.encode(url); 

     RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, url); 

     try{ 
      @SuppressWarnings("unused") 
      Request request = builder.sendRequest(null, new RequestCallback() { 
      @Override 
      public void onResponseReceived(Request req, Response resp) { 
       if(resp.getStatusCode() == 200){ 
        JsArray<Person> jsonPeople = asArrayOfPeopleData(resp.getText()); 
        populatePeopleTable(people); 
       } 
       else{ 
        displayError("Couldn't retrieve JSON (" + resp.getStatusText() + ")"); 
       } 
      } 

      @Override 
      public void onError(Request req, Throwable arg1) { 
       System.out.println("couldn't retrieve JSON"); 
       displayError("Couldn't retrieve JSON"); 
      } 
     }); 
     } catch(RequestException e) { 
      System.out.println("couldn't retrieve JSON"); 
      displayError("Couldn't retrieve JSON"); 
     } 
    } 

所以基本上你铸造将响应作为JSON对象的阵列。好东西。

此处了解详情:http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsJSNI.html

12

你可以看下到GWT AutoBean framework

AutoBean让你序列化和往返于普通Java对象序列化JSON字符串。

对我来说,这个框架变得至关重要:

  • 代码比用JSNI对象(JavaScript的本地接口)
  • 有框架无扶养不是由谷歌(如RestyGWT)支持

清洁您只需定义与吸气剂和吸附剂的接口:

// Declare any bean-like interface with matching getters and setters, 
// no base type is necessary 
interface Person { 
    Address getAddress(); 
    String getName(); 
    void setName(String name): 
    void setAddress(Address a); 
} 

interface Address { 
    String getZipcode(); 
    void setZipcode(String zipCode); 
} 

以后可以序列或使用工厂(See documentation)反序列化JSON字符串:

// (...) 

String serializeToJson(Person person) { 
    // Retrieve the AutoBean controller 
    AutoBean<Person> bean = AutoBeanUtils.getAutoBean(person); 

    return AutoBeanCodex.encode(bean).getPayload(); 
} 

Person deserializeFromJson(String json) { 
    AutoBean<Person> bean = AutoBeanCodex.decode(myFactory, Person.class, json); 
    return bean.as(); 
} 

// (...) 

第一篇文章上堆栈溢出(!):我希望这帮助:)