Jersey: JSON and StringMessageProvider clash, application/json methods generate invalid JSON

为君一笑 提交于 2020-01-01 19:33:42

问题


I have a jax-rs web services on jetty+jersey and tried different JSON message providers (e.g. Jackson and Gson). With all of them POJO <-> JSON works just fine but methods like this:

@GET
@Path("test")
@Produces(MediaType.APPLICATION_JSON)
public String test() {
    return "This string should be \"quoted\" by message writer";
}

produce string

This string should be "quoted" by message writer

which is of course not a valid JSON and causes browser's ajax calls to fail. I expect it to be

"This string should be \"quoted\" by message writer"

The reason for such magic is StringMessageProvider (one of the internal jersey providers for basic types) which have / Produce/Consume annotation. And I don't want to hack into jersey internal providers. I want to force jersey to use JSON provider in first place?

Any ideas?


回答1:


So, after reading jersey docs & some debuging it turned out that:

  • yes, custom message readers/writers have higher priority, but
  • after selecting "suitable" providers (starting from correct one), jersey sort them via custom comparation, that first checks 'type' distance

So, having method return type 'String' and JSON message provider MIME type wildcard (/), it checks first StringMessageProvider (default jersey provider for build-in type) by comparing distances String-String < String-Object.

The problem solved by adding non-generic custom message provider, e.g.:

public class StringProvider extends GsonProvider<String> {
    public StringProvider() {}
}

(where GsonProvider implements MessageBodyReader<T>, MessageBodyWriter<T>).

After this returned string was escaped to be a correct JSON and recognized by browsers' ajax call handlers.




回答2:


The JSON that you are generating is invalid (you may want to validate it with JSONLint).

So, a valid JSON can be:

{"msg":"This string should be \"quoted\" by message writer"}

["This string should be \"quoted\" by message writer"]

The Java code for each JSON:

@GET
@Path("test")
@Produces(MediaType.APPLICATION_JSON)
public Map<String, String> test() {
    Map<String, String> map = new HashMap<String, String>();
    map.put("msg", "This string should be \"quoted\" by message writer");
    return map;
}

@GET
@Path("test")
@Produces(MediaType.APPLICATION_JSON)
public Map<String, String> test() {
    return Arrays.asList("This string should be \"quoted\" by message writer");
}

NOTE: I'm using RESTEasy 3.0.8 with Jackson 2.4.1



来源:https://stackoverflow.com/questions/25311472/jersey-json-and-stringmessageprovider-clash-application-json-methods-generate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!