Использование объекта JSON в сервисе Джерси - PullRequest
33 голосов
/ 02 ноября 2009

Я погуглил, пытаясь выяснить, как это сделать: у меня есть служба REST в Джерси. Запрос, который вызывает службу REST, содержит объект JSON. Мой вопрос заключается в том, как из реализации метода POST Джерси, как я могу получить доступ к JSON, который находится в теле HTTP-запроса?

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

Спасибо ...

- Стив

Ответы [ 5 ]

15 голосов
/ 07 февраля 2013

Как уже предлагалось, изменение @Consumes Content-Type на text/plain будет работать, но это не выглядит правильным с точки зрения REST API.

Представьте, что ваш клиент должен отправить JSON в ваш API, но ему нужно указать заголовок Content-Type как text/plain. Это не чисто на мой взгляд. Проще говоря, если ваш API принимает JSON, тогда в заголовке запроса должно быть указано Content-Type: application/json.

Чтобы принять JSON, но сериализовать его в объект String, а не в POJO, вы можете реализовать пользовательский MessageBodyReader . Делать это так же просто, и вам не придется идти на компромисс со своей спецификацией API.

Стоит прочитать документы для MessageBodyReader , чтобы вы точно знали, как это работает. Вот как я это сделал:

Шаг 1. Реализация пользовательского MessageBodyReader

@Provider
@Consumes("application/json")
public class CustomJsonReader<T> implements MessageBodyReader<T> {
  @Override
  public boolean isReadable(Class<?> type, Type genericType,
      Annotation[] annotations,MediaType mediaType) {
    return true;
  }

  @Override
  public T readFrom(Class<T> type, Type genericType, Annotation[] annotations,
      MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
      InputStream entityStream) throws IOException, WebApplicationException {

    /* Copy the input stream to String. Do this however you like.
     * Here I use Commons IOUtils.
     */
    StringWriter writer = new StringWriter();
    IOUtils.copy(entityStream, writer, "UTF-8");
    String json = writer.toString();

    /* if the input stream is expected to be deserialized into a String,
     * then just cast it
     */
    if (String.class == genericType)
      return type.cast(json);

    /* Otherwise, deserialize the JSON into a POJO type.
     * You can use whatever JSON library you want, here's
     * a simply example using GSON.
     */
    return new Gson().fromJson(json, genericType);
  }
}

Основная концепция, приведенная выше, заключается в проверке того, ожидается ли преобразование входного потока в String (задано Type genericType). Если это так, просто приведите JSON в указанный type (который будет String). Если ожидаемый тип является каким-либо POJO, то используйте библиотеку JSON (например, Джексона или GSON), чтобы десериализовать его в POJO.

Шаг 2. Свяжите свой MessageBodyReader

Это зависит от того, какую платформу вы используете. Я считаю, что Гайс и Джерси хорошо работают вместе. Вот как я связываю свой MessageBodyReader в Guice:

В моем JerseyServletModule Я привязываю читателя так -

bind(CustomJsonReader.class).in(Scopes.SINGLETON);

Приведенный выше CustomJsonReader десериализует полезные нагрузки JSON в POJO, а также, если вам просто нужен необработанный JSON, String объекты.

Преимущество такого способа состоит в том, что он примет Content-Type: application/json. Другими словами, ваш обработчик запросов может быть настроен на использование JSON, что кажется правильным:

@POST
@Path("/stuff")
@Consumes("application/json") 
public void doStuff(String json) {
  /* do stuff with the json string */
  return;
}
12 голосов
/ 26 апреля 2013

Jersey поддерживает низкоуровневый доступ к проанализированному JSONObject с использованием типов Jettison JSONObject и JSONArray.

<dependency>
    <groupId>org.codehaus.jettison</groupId>
    <artifactId>jettison</artifactId>
    <version>1.3.8</version>
</dependency>

Например:

{
  "A": "a value",
  "B": "another value"
}


@POST
@Path("/")
@Consumes(MediaType.APPLICATION_JSON) 
public void doStuff(JSONObject json) {
  /* extract data values using DOM-like API */
  String a = json.optString("A");
  Strong b = json.optString("B");
  return;
}

См. документацию на Джерси для дополнительных примеров.

12 голосов
/ 02 ноября 2009

Я не уверен, как вы поступите с самой строкой JSON, но вы наверняка можете получить данные, которые в ней содержатся, следующим образом:

Определите JAXB-аннотированный Java-класс (C), имеющий ту же структуру, что и объект JSON, передаваемый по запросу.

например. для сообщения JSON:

{
  "A": "a value",
  "B": "another value"
}

Используйте что-то вроде:

@XmlAccessorType(XmlAccessType.FIELD)
public class C
{
  public String A;
  public String B;
}

Затем вы можете определить метод в своем классе ресурсов с параметром типа C. Когда Джерси вызовет ваш метод, объект JAXB будет создан на основе объекта JSON POSTed.

@Path("/resource")
public class MyResource
{
  @POST
  public put(C c)
  {
     doSomething(c.A);
     doSomethingElse(c.B);
  }
}
7 голосов
/ 12 июня 2012

Это дает вам доступ к необработанному сообщению.

@POST
@Path("/")
@Consumes("text/plain") 
@Produces(MediaType.APPLICATION_JSON)
public String processRequset(String pData) {
    // do some stuff, 
    return someJson;
}
0 голосов
/ 02 ноября 2009

Отправить / POST форму / HTTP.POST с параметром с JSON в качестве значения.

@ QueryParam jsonString

public desolveJson (jsonString)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...