获取和使用远程JSON数据

时间:2011-04-01 20:28:45

标签: json gwt javascript-objects

我正在开发一个小应用程序并使用GWT来构建它。 我刚尝试向远程服务器发出请求,该服务器将以JSON的形式返回响应。 我尝试过使用叠加类型概念,但我无法使用它。我一直在改变代码,所以它与谷歌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的调试器中,我得到了umbrellaexception,无法看到堆栈跟踪,GWT调试器因NoSuchMethodError而崩溃......任何想法,指针?

5 个答案:

答案 0 :(得分:13)

您可以查看GWT AutoBean framework

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

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

  • 代码比JSNI对象(JavaScript Native Interface)更清晰
  • 不支持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上的第一篇文章(!):我希望这有帮助:)

答案 1 :(得分:5)

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

答案 2 :(得分:5)

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

  1. 提出请求
  2. 接收JSON文字
  3. 在JavaScript对象中解析JSON
  4. 使用叠加类型描述这些JavaScript对象
  5. 听起来你已经让步骤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"
    

答案 3 :(得分:0)

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

eval(jsonStr)

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

注意:我认为服务器可以在与GWT主机页面相同的URL +端口+协议下访问(否则,由于同源策略,RequestBuilder无法正常工作。)

答案 4 :(得分:0)

您实际上不需要解析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