Как уже предлагалось, изменение @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;
}