2011-04-01 90 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(); 
} 

// (...) 

第一篇文章上堆棧溢出(!):我希望這幫助:)