【问题标题】:Can't Deserialize JSON in Java Servlet无法在 Java Servlet 中反序列化 JSON
【发布时间】:2014-08-30 21:43:08
【问题描述】:

我的端点无法理解传入的 JSON。

这里是终点:

import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.hibernate.Query;
import org.hibernate.Session;
import org.json.JSONObject;
...

@POST
@Path("/{department}/{team}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response handleJSON(JSONObject json , @PathParam("department") String department, @PathParam("team") String team){ 

    MyObj myObj = new MyObj();

    myObj.setDepartment(department);
    myObj.setTeam(team);
    myObj.setPlatform(json.optString("platform"));

    saveObj(myObj);

  return Response.ok(true).build();

}

我正在使用 Postman 发布包含“平台”键/值的 JSON,标题:Content-Type as application/json

但我得到了这个例外:com.owlike.genson.JsonBindingException: Could not deserialize to type class org.json.JSONObject

看起来问题与:Illegal character at row 0 and column 1 expected { but read '-' !

但我很确定 Postman 应该发送有效的 JSON...

这里有更多的堆栈跟踪:

09-Jul-2014 10:30:00.017 SEVERE [http-nio-8080-exec-4] com.sun.jersey.spi.container.ContainerResponse.logException Mapped exception to response: 500 (Internal Server Error)
 javax.ws.rs.WebApplicationException: com.owlike.genson.JsonBindingException: Could not deserialize to type class org.json.JSONObject
    at com.owlike.genson.ext.jaxrs.GensonJsonConverter.readFrom(GensonJsonConverter.java:127)
    at com.sun.jersey.spi.container.ContainerRequest.getEntity(ContainerRequest.java:474)
    at com.sun.jersey.server.impl.model.method.dispatch.EntityParamDispatchProvider$EntityInjectable.getValue(EntityParamDispatchProvider.java:123)
    at com.sun.jersey.server.impl.inject.InjectableValuesProvider.getInjectableValues(InjectableValuesProvider.java:46)
    at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$EntityParamInInvoker.getParams(AbstractResourceMethodDispatchProvider.java:153)
    at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:203)
    at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
    at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
    at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
    at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
    at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
    at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
    at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469)
    at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)
    at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:526)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1078)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:655)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:744)
Caused by: com.owlike.genson.JsonBindingException: Could not deserialize to type class org.json.JSONObject
    at com.owlike.genson.Genson.deserialize(Genson.java:391)
    at com.owlike.genson.ext.jaxrs.GensonJsonConverter.readFrom(GensonJsonConverter.java:125)
    ... 41 more
Caused by: com.owlike.genson.stream.JsonStreamException: Illegal character at row 0 and column 1 expected { but read '-' !
    at com.owlike.genson.stream.JsonReader.newWrongTokenException(JsonReader.java:949)
    at com.owlike.genson.stream.JsonReader.begin(JsonReader.java:425)
    at com.owlike.genson.stream.JsonReader.beginObject(JsonReader.java:157)
    at com.owlike.genson.reflect.BeanDescriptor.deserialize(BeanDescriptor.java:101)
    at com.owlike.genson.reflect.BeanDescriptor.deserialize(BeanDescriptor.java:90)
    at com.owlike.genson.convert.BeanViewConverter.deserialize(BeanViewConverter.java:102)
    at com.owlike.genson.convert.NullConverter$NullConverterWrapper.deserialize(NullConverter.java:56)
    at com.owlike.genson.Genson.deserialize(Genson.java:389)
    ... 42 more

【问题讨论】:

  • 您能否与telerik.com/fiddler 核对您发布的内容并根据调查结果更新您的问题。
  • 是的,请拦截和/或记录请求并找到您的http请求JSON对象的内容,以便我们进一步分析。如果您使用的是 Chrome 或 Firefox,您应该能够分别使用开发人员工具或 firebug 来完成。

标签: java json rest servlets jersey


【解决方案1】:

这可能不是一个理想的解决方案,但我确实认为它可以工作。

希望您已经拥有 Jackson JSON 依赖项...

你可以在这里找到它:http://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core

我会尝试以下代码:

@POST
@Path("/{department}/{team}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response handleJSON(String json, @PathParam("department") String department,       @PathParam("team") String team){ 

    ObjectMapper mapper = new ObjectMapper();
    JsonNode node = mapper.readValue(json, JsonNode.class);

    MyObj myObj = new MyObj();

    myObj.setDepartment(department);
    myObj.setTeam(team);

    if (node.get("platform") != null) {
        myObj.setPlatform(node.get("platform").textValue());
    }

    saveObj(myObj);

    return Response.ok(true).build();

}

请注意,我要求您的 WS 框架将 JSON 作为字符串传递给我并自己处理。 也许它不理想,但应该可以。

干杯!

【讨论】:

  • 我刚刚读到您正在使用 Gensen,您可以更新代码以使用 Gensen,但我可以看到您可能希望与您的 WS 框架进行更紧密的集成。无论如何祝你好运!
  • ObjectMapper 是线程安全的,应该只构造一次......只是想指出这一点
【解决方案2】:

我不知道您使用的是哪个 JSON 序列化器,但很可能是 JettisonJackson。据我所知,他们不支持直接转换 org.json.JSONObject 的实例。更常见的方法是简单地使用自定义 Java Bean:

public class Foo implements Serializable {

    private String platform;

    // getters + setters

}

@POST
@Path("/{department}/{team}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response handleJson(Foo foo, @PathParam("department") String department, @PathParam("team") String team) {
    ...
    myObj.setPlatform(foo.getPlatform());
    ...
}

如果您使用 Jettison,Foo 应使用 @XmlRootElement 注释。

如果您不想为您期望的每个实体创建自定义 Bean,您可以使用 ObjectMapString 作为参数并自行序列化:

@POST
@Path("/{department}/{team}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response handleJson(String json, @PathParam("department") String department, @PathParam("team") String team) {
    ...
    JSONObject jsonObject = new JSONObject(json);
    myObj.setPlatform(json.optString("platform"));
    ...
}

最后一个解决方案是实现一个处理JSONObjectMessageBodyReader。简单例子:

@Provider
public class JsonObjectReader implements MessageBodyReader<JSONObject> {

    @Override
    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return type == JSONObject.class && MediaType.APPLICATION_JSON_TYPE.equals(mediaType);
    }

    @Override
    public JSONObject readFrom(Class<JSONObject> type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
            throws IOException, WebApplicationException {
        return new JSONObject(IOUtils.toString(entityStream));
    }

}

【讨论】:

  • 至少前两个例子也适用于 Genson。
【解决方案3】:

您应该首先检查您的请求是如何发送的。它可能是作为转义字符串而不是原始 JSON 发送的。

在我的例子中,当我使用通用 REST 客户端将请求作为纯 JSON 字符串发送时发生了这种情况,因为我的客户端不知道对象定义。

为了防止这种情况发生,在您的客户端中,您可以发送 (org.codehaus.jettison.json) JSONObject 而不仅仅是 String(它有一个接受 JSON 字符串的构造函数),但这取决于您的依赖项。就我而言,我使用的是 Jersey 1.19。

请注意,根据您的类路径(在我的例子中,Jersey 1.19 和 Genson)如果您还想将响应读取为 JSON 字符串,您可能还需要手动读取响应输入流。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    • 1970-01-01
    • 2018-04-02
    • 2014-08-10
    相关资源
    最近更新 更多