Jak już sugeruje, zmieniając @Consumes
Content-Type do text/plain
będzie działać, ale nie wydaje się słuszne z punktu widzenia REST API.
Wyobraź sobie, że twój klient musi POST JSON do swojego API, ale musi określić nagłówek Content-Type jako text/plain
. To nie jest czyste w mojej opinii. Mówiąc prościej, jeśli twój interfejs API akceptuje JSON, wówczas nagłówek żądania powinien określać Content-Type: application/json
.
Aby zaakceptować JSON, ale serializować go do obiektu String
, a nie POJO, można zaimplementować niestandardowe MessageBodyReader. Zrobienie tego w ten sposób jest równie proste i nie musisz iść na kompromis w sprawie specyfikacji interfejsu API.
Warto przeczytać dokumenty dla MessageBodyReader, dzięki czemu wiesz dokładnie, jak to działa. To jak to zrobiłem:
Krok 1. Wdrożenie zwyczaj 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);
}
}
Podstawowa koncepcja powyżej jest sprawdzenie, czy oczekuje się, że strumień wejściowy być konwertowane do String
(określony przez Type genericType
).Jeśli tak, po prostu obsadź JSON w podanym type
(który będzie String
). Jeśli oczekiwanym typem jest POJO, użyj biblioteki JSON (np. Jackson lub GSON), aby przekształcić ją w obiekt POJO.
Krok 2. powiązać MessageBodyReader
To zależy od tego, co ramy używasz. Uważam, że Guice i Jersey dobrze ze sobą współpracują. Oto jak wiążę moich MessageBodyReader w Guice:
W moim JerseyServletModule wiążę czytelnik jak tak -
bind(CustomJsonReader.class).in(Scopes.SINGLETON);
Powyższy CustomJsonReader
będzie deserializowania ładunki JSON język POJOs jak również, jeśli chcesz po prostu surowy Obiekty JSON, String
.
Zaletą zrobienia tego w ten sposób jest zaakceptowanie Content-Type: application/json
. Innymi słowy, obsługi żądania można ustawić zużywają JSON, co wydaje się właściwe:
@POST
@Path("/stuff")
@Consumes("application/json")
public void doStuff(String json) {
/* do stuff with the json string */
return;
}
Mam do czynienia z podobnym problemem. czy istnieje jakieś rozwiązanie do korzystania z niskiego poziomu dostępu do JSONObject? – Jugi