【问题标题】:Getting and using remote JSON data获取和使用远程 JSON 数据
【发布时间】:2011-04-01 20:28:44
【问题描述】:

我正在开发一个小应用程序并使用 GWT 来构建它。 我刚刚尝试向远程服务器发出请求,该服务器将以 JSON 形式返回响应。 我试过使用覆盖类型的概念,但我无法让它工作。我一直在更改代码,所以它与 Google GWT 教程的位置有点偏离。

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 的调试器中,我得到了雨伞异常,无法看到堆栈跟踪,并且 GWT 调试器因 NoSuchMethodError 而死...有什么想法,指针吗?

【问题讨论】:

  • 您能否举例说明您希望通过 JSON 接收的对象?
  • {"matching_results":165958,"videos":[{"video_id":"50953524","title":"Wyclef Jean features Akon"}]}从返回的实际数据到“}]}。因为它是一个巨大的块,所以将其切碎

标签: json gwt javascript-objects


【解决方案1】:

你可以看看GWT AutoBean framework

AutoBean 允许您从普通旧 Java 对象序列化和反序列化 JSON 字符串。

对我来说,这个框架变得必不可少:

  • 代码比使用 JSNI 对象(JavaScript 原生接口)更简洁
  • 不依赖于 Google 不支持的框架(如 RestyGWT)

您只需使用 getter 和 setter 定义接口:

// 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();
}

// (...)

关于 Stack Overflow 的第一篇文章(!):希望对您有所帮助 :)

【讨论】:

    【解决方案2】:
    1. 使用JsonUtils#safeEval() 评估JSON 字符串,而不是直接调用eval()
    2. 更重要的是,不要尝试将异步调用的结果(例如 RequestBuilder#sendRequest() 使用 return 传回给调用者 - 使用回调:

      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);
        }
      }
      

    【讨论】:

    • +1 最大的错误实际上是试图返回结果而不是使用回调......
    【解决方案3】:

    您所描述的工作流程通常包括四个步骤:

    1. 提出请求
    2. 接收 JSON 文本
    3. 解析 JavaScript 对象中的 JSON
    4. 使用覆盖类型描述这些 JavaScript 对象

    听起来您已经让第 1 步和第 2 步正常工作了。

    解析 JSON

    JSONParser.parseStrict 会做得很好。您将收到一个 JSONValue 对象。

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

    假设您期待以下 JSON:

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

    由于您知道 JSON 描述了一个对象,因此您可以告诉 JSONValue 您希望得到一个 JavaScriptObject

    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"
    

    【讨论】:

      【解决方案4】:

      使用eval 通常很危险,并且可能导致各种奇怪的行为,如果服务器返回无效的 JSON(请注意,如果您仅使用 eval(jsonStr),则 JSON 顶部元素是一个数组是必要的!)。所以我会让服务器返回一个非常简单的结果,比如

      [ "hello" ]
      

      看看,错误是否仍然存在,或者您是否可以获得更好的堆栈跟踪。

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

      【讨论】:

      • 顶级 JSON 元素可以是数组(用[ ... ] 表示)或对象({ ... })。
      • 我尝试不调用 parseJson() 并且 response.getText() 返回格式正确的 JSON 字符串...我将使用什么来替代 eval()
      • @Jason:这也是我曾经相信的。对象不能在顶层工作的原因是 eval 假定 { 是代码块的开始。然后它在遇到对象中的第一个标签时会抱怨(SyntaxError): invalid label
      • 这就是为什么,当使用eval() 从 JSON 字符串创建对象时,应该将字符串括在括号中(json.org/js.html):eval("(" + jsonString + ")"); 这表示使用时正确的做法GWT是将字符串传递给JsonUtils#safeEval(),而不是直接调用eval()
      【解决方案5】:

      其实你不需要解析 JSON,可以使用原生的 JSNI 对象(JavaScript Native Interface)。

      这是我从最近的一个项目中提取的一个示例,它与您正在做的事情基本相同:

      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

      【讨论】:

        猜你喜欢
        • 2021-05-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-12
        • 1970-01-01
        相关资源
        最近更新 更多