Получение и использование удаленных данных JSON - PullRequest
3 голосов
/ 02 апреля 2011

Я работаю над небольшим приложением и использую 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 ... Есть идеи, указатели?

Ответы [ 5 ]

13 голосов
/ 02 апреля 2011

Вы можете взглянуть на GWT AutoBean framework .

AutoBean позволяет сериализовать и десериализовать строку JSON из простого объекта Java и обратно.

Для меня этот каркас стал необходимым:

  • Код чище, чем с объектами JSNI (собственный интерфейс JavaScript)
  • Нет зависимости от Framework, не поддерживаемого Google (например, 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);
}

Позже вы можете сериализовать или десериализовать строку 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();
}

// (...)

Первое сообщение о переполнении стека (!): Надеюсь, это поможет:)

5 голосов
/ 02 апреля 2011
  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);
      }
    }
    
5 голосов
/ 02 апреля 2011

Обычно описываемый вами рабочий процесс состоит из четырех этапов:

  1. Сделать запрос
  2. Получить текст в формате JSON
  3. Разобрать JSON в объектах JavaScript
  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"
0 голосов
/ 02 апреля 2011

На самом деле вам не нужно анализировать 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

0 голосов
/ 02 апреля 2011

Использование eval обычно опасно и может привести к всевозможным странным действиям, если сервер возвращает недопустимый JSON (обратите внимание, что необходимо, чтобы верхний элемент JSON был массивом, если вы просто используете eval(jsonStr)!).Поэтому я бы заставил сервер вернуть очень простой результат, такой как

[ "hello" ]

, и посмотрел бы, если ошибка все еще возникает или вы можете получить лучшую трассировку стека.

Примечание: IПредположим, что сервер доступен по тому же протоколу URL + порт +, что и ваша страница хоста GWT (в противном случае RequestBuilder не будет работать в любом случае из-за той же политики происхождения).

...