Использование объекта JSON в службе Джерси
Я искал свой приступ, пытаясь выяснить, как это сделать: у меня есть служба REST Джерси. Запрос, который вызывает службу REST, содержит объект JSON. Мой вопрос: с помощью метода метода POST, как я могу получить доступ к JSON, который находится в теле запроса HTTP?
Приветствуются любые советы, трюки, указатели на образец кода.
Спасибо...
- Стив
Ответы
Ответ 1
Я не уверен, как вы могли бы получить строку 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 будет создан на основе объекта POSTed JSON.
@Path("/resource")
public class MyResource
{
@POST
public put(C c)
{
doSomething(c.A);
doSomethingElse(c.B);
}
}
Ответ 2
Как уже было сказано, изменение @Consumes
Content-Type на text/plain
будет работать, но это не похоже на точку зрения REST API.
Представьте, что ваш клиент имеет POST 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 (например, Jackson или 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;
}
Ответ 3
Джерси поддерживает низкоуровневый доступ к анализируемому JSONObject с использованием типов JTONObject и JSONArray типа Jettison.
<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;
}
Подробнее см. документацию Джерси.
Ответ 4
Это дает вам доступ к исходному сообщению.
@POST
@Path("/")
@Consumes("text/plain")
@Produces(MediaType.APPLICATION_JSON)
public String processRequset(String pData) {
// do some stuff,
return someJson;
}
Ответ 5
Отправить/POST форму /HTTP.POST с параметром с JSON в качестве значения.
@QueryParam jsonString
public desolveJson (jsonString)