如何让Jersey为String类型调用GSON MessageBodyHandler?
问题:如何让Jersey为String类型调用GSON处理器并正确处理数据?
项目背景
我创建了一个用于测试Jersey + GSON的简单项目,实现了GsonMessageBodyHandler implements MessageBodyReader<Object>, MessageBodyWriter<Object>,并在readFrom和writeTo方法中添加System.out.println语句,用于检查该处理器是否被调用。
处理器核心代码:
@Override public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { Type jsonType = Collection.class.isAssignableFrom(type) ? genericType : type; Object o; try (Reader jsonReader = new InputStreamReader(entityStream, StandardCharsets.UTF_8)) { o = gson.fromJson(jsonReader, jsonType); } System.out.println("GsonMessageBodyHandler.readFrom() -= " + o + " =-"); return o; } @Override public void writeTo(Object o, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { Type jsonType = Collection.class.isAssignableFrom(type) ? genericType : type; try (OutputStreamWriter writer = new OutputStreamWriter(entityStream, StandardCharsets.UTF_8)) { gson.toJson(o, jsonType, writer); } System.out.println("GsonMessageBodyHandler.writeTo() -= " + o + " =- " + gson.toJson(o, jsonType)); }
资源类实现
编写了一个资源类,包含两个接口:一个使用String类型作为输入和响应,另一个使用自定义对象作为输入和响应。
资源类代码:
@Path("/hello") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public class HelloResource { @Path("/str") @POST public Response helloStr(String name) { System.out.println("Got hello string request [" + name + "]"); String msg = "Hello " + name + "!"; return Response.ok().entity(msg).build(); } @Path("/obj") @POST public Response helloStr(User user) { System.out.println("Got hello object request [" + user + "]"); Message msg = new Message("Hello " + user.name() + "!"); return Response.ok().entity(msg).build(); } }
前端测试代码
制作了带有简单表单的网页,通过以下JavaScript测试这些接口:
function doIt(isSendString) { const name = document.getElementById('name').value; const opts = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(isSendString ? name : {name: name}) } fetch('ws/hello/' + (isSendString ? 'str' : 'obj'), opts).then(response => { if (response.ok) { response.json().then(rs => { const msg = isSendString ? rs : rs.message; alert('Got: ' + msg); }).catch(e => { console.log(response, e); alert('Error parsing data'); }); } else { console.log(response); alert('Error fetching data'); } }); return false; }
测试结果
/str接口(String类型)异常情况
- 浏览器网络面板显示:请求内容为
"Ricardo Almeida",响应内容为Hello "Ricardo Almeida"!,而非预期的"Hello Ricardo Almeida!"或'Hello Ricardo Almeida!' - 服务器端仅打印资源类中的日志,未打印GSON处理器的日志,且接收的字符串包含双引号:
Got hello string request ["Ricardo Almeida"]
/obj接口(自定义对象)正常情况
- 浏览器网络面板显示:请求内容为
{"name":"Ricardo Almeida"},响应内容为{"message": "Hello Ricardo Almeida!"} - 服务器端打印了预期的三条日志(GSON处理器的readFrom、资源类、GSON处理器的writeTo):
GsonMessageBodyHandler.readFrom() -= User[name=Ricardo Almeida] =- Got hello object request [User[name=Ricardo Almeida]] GsonMessageBodyHandler.writeTo() -= Message[message=Hello Ricardo Almeida!] =- {"message":"Hello Ricardo Almeida!"}
提问
如何让Jersey为String类型调用GSON处理器并正确处理数据?
内容的提问来源于stack exchange,提问作者Ricardo Almeida
相关产品推荐
相关产品推荐

