【问题标题】:Can not deserialize instance of java.lang.String out of START_OBJECT token无法从 START_OBJECT 令牌中反序列化 java.lang.String 的实例
【发布时间】:2013-10-23 18:13:15
【问题描述】:

我遇到了一个问题,我的可部署 jar 遇到了一个异常,当我在 IntelliJ 中本地运行它时不会发生这种异常。

例外:

Receiving an event {id=2, socket=0c317829-69bf-43d6-b598-7c0c550635bb, type=getDashboard, data={workstationUuid=ddec1caa-a97f-4922-833f-632da07ffc11}, reply=true}
Firing getDashboard event to Socket#0c317829-69bf-43d6-b598-7c0c550635bb
Failed invoking AtmosphereFramework.doCometSupport()
java.lang.IllegalArgumentException: Can not deserialize instance of java.lang.String out of START_OBJECT token
 at [Source: N/A; line: -1, column: -1]
        at org.codehaus.jackson.map.ObjectMapper._convert(ObjectMapper.java:2502)
        at org.codehaus.jackson.map.ObjectMapper.convertValue(ObjectMapper.java:2468)
        at com.github.flowersinthesand.portal.support.DefaultDispatcher$DefaultHandler$DataParam.resolve(DefaultDispatcher.java:270)
        at com.github.flowersinthesand.portal.support.DefaultDispatcher$DefaultHandler.handle(DefaultDispatcher.java:204)
        at com.github.flowersinthesand.portal.support.DefaultDispatcher.fire(DefaultDispatcher.java:107)
        at com.github.flowersinthesand.portal.support.AbstractSocketFactory.fire(AbstractSocketFactory.java:73)
        at com.github.flowersinthesand.portal.atmosphere.AtmosphereSocketFactory.onRequest(AtmosphereSocketFactory.java:75)
        at org.atmosphere.cpr.AsynchronousProcessor.action(AsynchronousProcessor.java:256)
        at org.atmosphere.cpr.AsynchronousProcessor.suspended(AsynchronousProcessor.java:166)
        at org.atmosphere.container.Grizzly2WebSocketSupport.service(Grizzly2WebSocketSupport.java:75)
        at org.atmosphere.cpr.AtmosphereFramework.doCometSupport(AtmosphereFramework.java:1342)
        at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:219)
        at org.atmosphere.websocket.DefaultWebSocketProcessor$2.run(DefaultWebSocketProcessor.java:183)
        at org.atmosphere.util.VoidExecutorService.execute(VoidExecutorService.java:101)
        at org.atmosphere.websocket.DefaultWebSocketProcessor.dispatch(DefaultWebSocketProcessor.java:178)
        at org.atmosphere.websocket.DefaultWebSocketProcessor.invokeWebSocketProtocol(DefaultWebSocketProcessor.java:167)
        at org.atmosphere.container.Grizzly2WebSocketSupport$Grizzly2WebSocketApplication.onMessage(Grizzly2WebSocketSupport.java:171)
        at org.glassfish.grizzly.websockets.DefaultWebSocket.onMessage(DefaultWebSocket.java:164)
        at org.glassfish.grizzly.websockets.frametypes.TextFrameType.respond(TextFrameType.java:70)
        at org.glassfish.grizzly.websockets.DataFrame.respond(DataFrame.java:104)
        at org.glassfish.grizzly.websockets.WebSocketFilter.handleRead(WebSocketFilter.java:221)
        at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:265)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:134)
        at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
        at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:78)
        at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:770)
        at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
        at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
        at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:551)
        at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:531)
        at java.lang.Thread.run(Thread.java:781)
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
 at [Source: N/A; line: -1, column: -1]
        at org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:163)
        at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:219)
        at org.codehaus.jackson.map.deser.std.StringDeserializer.deserialize(StringDeserializer.java:44)
        at org.codehaus.jackson.map.deser.std.StringDeserializer.deserialize(StringDeserializer.java:13)
        at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2704)
        at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1315)
        at org.codehaus.jackson.map.ObjectMapper._convert(ObjectMapper.java:2498)
        ... 34 more
java.lang.IllegalArgumentException: Can not deserialize instance of java.lang.String out of START_OBJECT token
 at [Source: N/A; line: -1, column: -1] Status 500 Message Server Error

套接字处理程序

我相信当 JSON 被解析为 WorkstationRequest 对象时会发生异常,因为以下项目。这是套接字处理程序:

@On
@Reply
@JsonView({Views.WorkstationView.class})
public WorkstationDashboard getDashboard(@Data WorkstationRequest request) {
    return new WorkstationDashboard(request.getWorkstation());
}

套接字处理程序映射到的对象:

public class WorkstationRequest {

    /* Class to instantiate if this workstation does not already exist */
    private Class<? extends Workstation> workstationClass;

    private WorkflowProcess workflowProcess;

    private PhysicalWorkstation workstation;

    WorkstationService workstationService;

    /**
     * @param workstationClass Required so when jackson maps the UUID we can auto fetch the class
     */
    public WorkstationRequest(Class<? extends Workstation> workstationClass) {
        this.workstationClass = workstationClass;
        workstationService = (WorkstationService) ApplicationContextProvider.getApplicationContext().getBean("workstationService");
    }

    /* Set the workstation based on UUID.  Will register the workstation if it's new */
    @JsonProperty("workstationUuid")
    public void setWorkstation(String workstationUUID) {
        workstation = (PhysicalWorkstation)WorkstationService.getWorkstation(workstationUUID);

        //setup new workstation
        if (workstation == null) {
            WorkstationEntity workstationEntity = workstationService.findByUUID(workstationUUID);
            workstation = (PhysicalWorkstation)Workstation.factory(workstationEntity, workstationClass);

            //register with queue
            WorkflowProcessService.getWorkflowProcess(workstation).registerWorkstation(workstation);
        }
    }

    public PhysicalWorkstation getWorkstation() {
        return workstation;
    }
}

被映射的 JSON:

{"id":2,"socket":"0c317829-69bf-43d6-b598-7c0c550635bb","type":"getDashboard","data":{"workstationUuid":"ddec1caa-a97f-4922-833f-632da07ffc11"},"reply":true}

WorkstationDashboard.java

public class WorkstationDashboard {
    private HashMap<String, Object> queue = new HashMap<String, Object>();

    private LinkedBlockingDeque<JobSetEntity> currentWork;

    public WorkstationDashboard() {
        queue.put("size", 0);
    }

    public WorkstationDashboard(Workstation workstation) {
        fromWorkstation(workstation);
    }

    /* Populate dashboard data from a workstation */
    public void fromWorkstation(Workstation workstation) {
        WorkflowProcess workflowProcess = WorkflowProcessService.getWorkflowProcess(workstation);

        setCurrentWork(workstation.getCurrentWork());
        setQueueSize(workflowProcess.getQueue().size());
    }

    public void setQueueSize(Integer queueSize) {
        queue.put("size", queueSize);
    }

    public HashMap<String, Object> getQueue() {
        return queue;
    }

    public LinkedBlockingDeque<JobSetEntity> getCurrentWork() {
        return currentWork;
    }

    public void setCurrentWork(LinkedBlockingDeque<JobSetEntity> currentWork) {
        this.currentWork = currentWork;
    }
}

我不知道如何开始调试它。堆栈跟踪永远不会触及我的应用程序。我正在使用 Maven -&gt; Package 部署我的 .jar 并使用 java -jar /path-to-jar.jar 执行它

更新:为了避免这个问题过长,我在此处包含了我的 pom.xml:http://pastebin.com/1ZUtKCfE。我认为这是一个依赖问题,因为该错误仅发生在我的可部署 jar 上,而不发生在我的本地 PC 上。

【问题讨论】:

    标签: java deployment atmosphere grizzly


    【解决方案1】:

    要解决这个问题(如果您的数据对象可以有任何未定义的 json 或没有为数据定义 POJO),只需使用JsonNode 将数据作为输入

    private JsonNode data;
    

    那么你就可以使用jsonpath dependency来访问数据里面的值了。

    从这个 json 中获取 uuid

      "data": {
        "workStation": {
            {
              "uuid": "2",
              "Title": "Graduation day party"              
            }
        }
        "code": 200
      }
    

    使用 JsonPath 库中的 JsonContext 通过 JsonPath 读取

    DocumentContext jsonContext = JsonContext.createContext(data);
    String uuid = jsonContext.read("workStation.uuid");
    

    DocumentContext读取方法以json中的路径为属性

    【讨论】:

      【解决方案2】:

      当我们为 POJO 变量使用不正确的数据类型时,会发生这些类型的错误。

      【讨论】:

        【解决方案3】:

        如果您使用 Kotlin,您可能想尝试从类声明中删除 data 关键字。

           {
              "data": {
                "Calendar": {
                  "Events": [
                    {
                      "ID": "1",
                      "Title": "Graduation day"
                    },
                    {
                      "ID": "2",
                      "Title": "Graduation day party"              
                    }
                  ]
                }
              }
              "code": 200
            }
        

        我有一个 JSON 格式,我的 POJO 类是这样的:

        class Response(code: Int, val data: Data){
            @JsonIgnoreProperties(ignoreUnknown = true)
            class Data(@JsonProperty("Calendar") val calendar: Calendar) {}
        
            @JsonIgnoreProperties(ignoreUnknown = true)
            data class Event(
                val ID: Int? = null,
                val Title: String? = null
            )
        
            data class Calendar(
                @JsonProperty("Events") val eventsList: ArrayList<Event>
            )
        }
        

        class Eventclass Calendar 中删除data 对我有用。

        【讨论】:

          【解决方案4】:

          这样我解决了我的问题。希望它可以帮助别人。 在我的例子中,我创建了一个类、一个字段、它们的 getter 和 setter,然后提供对象而不是字符串。

          使用这个

          public static class EncryptedData {
              private String encryptedData;
          
              public String getEncryptedData() {
                  return encryptedData;
              }
          
              public void setEncryptedData(String encryptedData) {
                  this.encryptedData = encryptedData;
              }
          }
          
          @PutMapping(value = MY_IP_ADDRESS)
          public ResponseEntity<RestResponse> updateMyIpAddress(@RequestBody final EncryptedData encryptedData) {
              try {
                  Path path = Paths.get(PUBLIC_KEY);
                  byte[] bytes = Files.readAllBytes(path);
                  PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(base64.decode(bytes));
                  PrivateKey privateKey = KeyFactory.getInstance(CRYPTO_ALGO_RSA).generatePrivate(ks);
          
                  Cipher cipher = Cipher.getInstance(CRYPTO_ALGO_RSA);
                  cipher.init(Cipher.PRIVATE_KEY, privateKey);
                  String decryptedData = new String(cipher.doFinal(encryptedData.getEncryptedData().getBytes()));
                  String[] dataArray = decryptedData.split("|");
          
          
                  Method updateIp = Class.forName("com.cuanet.client.helper").getMethod("methodName", String.class,String.class);
                  updateIp.invoke(null, dataArray[0], dataArray[1]);
          
              } catch (Exception e) {
                  LOG.error("Unable to update ip address for encrypted data: "+encryptedData, e);
              }
          
              return null;
          

          而不是这个

          @PutMapping(value = MY_IP_ADDRESS)
          public ResponseEntity<RestResponse> updateMyIpAddress(@RequestBody final EncryptedData encryptedData) {
              try {
                  Path path = Paths.get(PUBLIC_KEY);
                  byte[] bytes = Files.readAllBytes(path);
                  PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(base64.decode(bytes));
                  PrivateKey privateKey = KeyFactory.getInstance(CRYPTO_ALGO_RSA).generatePrivate(ks);
          
                  Cipher cipher = Cipher.getInstance(CRYPTO_ALGO_RSA);
                  cipher.init(Cipher.PRIVATE_KEY, privateKey);
                  String decryptedData = new String(cipher.doFinal(encryptedData.getBytes()));
                  String[] dataArray = decryptedData.split("|");
          
          
                  Method updateIp = Class.forName("com.cuanet.client.helper").getMethod("methodName", String.class,String.class);
                  updateIp.invoke(null, dataArray[0], dataArray[1]);
          
              } catch (Exception e) {
                  LOG.error("Unable to update ip address for encrypted data: "+encryptedData, e);
              }
          
              return null;
          }
          

          【讨论】:

            【解决方案5】:

            使用 Jackson 库解决了该问题。从 Main 类调用打印并创建所有 POJO 类。这是代码sn-ps。

            MainClass.java

            public class MainClass {
              public static void main(String[] args) throws JsonParseException, 
                   JsonMappingException, IOException {
            
            String jsonStr = "{\r\n" + "    \"id\": 2,\r\n" + " \"socket\": \"0c317829-69bf- 
                         43d6-b598-7c0c550635bb\",\r\n"
                        + " \"type\": \"getDashboard\",\r\n" + "    \"data\": {\r\n"
                        + "     \"workstationUuid\": \"ddec1caa-a97f-4922-833f- 
                        632da07ffc11\"\r\n" + " },\r\n"
                        + " \"reply\": true\r\n" + "}";
            
                ObjectMapper mapper = new ObjectMapper();
            
                MyPojo details = mapper.readValue(jsonStr, MyPojo.class);
            
                System.out.println("Value for getFirstName is: " + details.getId());
                System.out.println("Value for getLastName  is: " + details.getSocket());
                System.out.println("Value for getChildren is: " + 
                  details.getData().getWorkstationUuid());
                System.out.println("Value for getChildren is: " + details.getReply());
            
            }
            

            MyPojo.java

            public class MyPojo {
                private String id;
            
                private Data data;
            
                private String reply;
            
                private String socket;
            
                private String type;
            
                public String getId() {
                    return id;
                }
            
                public void setId(String id) {
                    this.id = id;
                }
            
                public Data getData() {
                    return data;
                }
            
                public void setData(Data data) {
                    this.data = data;
                }
            
                public String getReply() {
                    return reply;
                }
            
                public void setReply(String reply) {
                    this.reply = reply;
                }
            
                public String getSocket() {
                    return socket;
                }
            
                public void setSocket(String socket) {
                    this.socket = socket;
                }
            
                public String getType() {
                    return type;
                }
            
                public void setType(String type) {
                    this.type = type;
                } 
            }
            

            Data.java

            public class Data {
                private String workstationUuid;
            
                public String getWorkstationUuid() {
                    return workstationUuid;
                }
            
                public void setWorkstationUuid(String workstationUuid) {
                    this.workstationUuid = workstationUuid;
                }   
            }
            

            结果:

            getFirstName 的值为:2 getLastName 的值为:0c317829-69bf-43d6-b598-7c0c550635bb getChildren 的值为:ddec1caa-a97f-4922-833f-632da07ffc11 getChildren 的值为:true

            【讨论】:

              【解决方案6】:

              如果您不想为嵌套 json 定义单独的类,将嵌套 json 对象定义为 JsonNode 应该可以工作,例如:

              {"id":2,"socket":"0c317829-69bf-43d6-b598-7c0c550635bb","type":"getDashboard","data":{"workstationUuid":"ddec1caa-a97f-4922-833f-632da07ffc11"},"reply":true}
              
              @JsonProperty("data")
                  private JsonNode data;
              

              【讨论】:

              • 我不需要使用 @JsonProperty 注释 - 据我了解,只有在 JSON 中的名称与 Object 中的属性名称不同时才需要。
              • 如果您不想使用 'JsonNode',您可以为 '"data":{..}' 数组定义一个单独的类,并使用该类名而不是 'JsonNode'。跨度>
              【解决方案7】:

              数据内容如此多变,我认为最好的形式是将其定义为“ObjectNode”,然后创建自己的类进行解析:

              最后:

              私有 ObjectNode 数据;

              【讨论】:

              • 您为此节省了我的长期追逐。我的data 字段里面可以有任何 JSON,所以我不能用一些 POJO 映射它。我正在寻找一些只能保存 JSON 值的解决方案。太感谢了。只是仔细检查一下,使用它是否有任何副作用或缺点?
              【解决方案8】:

              您正在映射此 JSON

              {
                  "id": 2,
                  "socket": "0c317829-69bf-43d6-b598-7c0c550635bb",
                  "type": "getDashboard",
                  "data": {
                      "workstationUuid": "ddec1caa-a97f-4922-833f-632da07ffc11"
                  },
                  "reply": true
              }
              

              包含一个名为 data 的元素,该元素的值是一个 JSON 对象。您正在尝试将名为 workstationUuid 的元素从该 JSON 对象反序列化到此设置器中。

              @JsonProperty("workstationUuid")
              public void setWorkstation(String workstationUUID) {
              

              这不会直接起作用,因为 Jackson 看到的是 JSON_OBJECT,而不是字符串。

              尝试创建一个类Data

              public class Data { // the name doesn't matter 
                  @JsonProperty("workstationUuid")
                  private String workstationUuid;
                  // getter and setter
              }
              

              改变你的方法

              @JsonProperty("data")
              public void setWorkstation(Data data) {
                  // use getter to retrieve it
              

              【讨论】:

              • 我没有详细描述这一点,但是我使用的 Socket 库将该数组中的data 字段通过public WorkstationDashboard getDashboard(@Data WorkstationRequest request) { 映射到我的对象。它调用getDashboard(),因为该JSON 中有type,然后映射data。我可能是错的,因为我真的不知道发生了什么。但由于这一切都在我的 PC 上本地运行,并且当我通过 .jar 部署我的应用程序时中断,这似乎是某种依赖问题。我的 pom 在这里:pastebin.com/1ZUtKCfE
              • @Webnet @Data 是绑定 JSON 中的 data 字段的自定义注解吗?您必须回溯以查看它如何生成 WorkstationRequest 参数。
              • @SotiriosDelimanolis,可靠的回答者。为我节省了数小时的故障排除时间。
              • @SotiriosDelimanolis,如果我的数据不断变化,我的意思是我不确定data 字段将包含多少个值。有什么解决办法吗? stackoverflow.com/questions/39053106/…
              • @theGamblerRises 如果您完全不知道将与什么类型相关联,您可以将通用 JSON 类型用于您正在使用的 JSON 库。对于杰克逊,那就是JsonNode。但是,这会将您的代码与 Jackson 结合起来,并且不容易使用该值。
              猜你喜欢
              • 2019-06-01
              • 2019-12-13
              • 2019-02-08
              • 2017-09-23
              • 1970-01-01
              • 2018-05-22
              • 1970-01-01
              • 1970-01-01
              • 2014-12-17
              相关资源
              最近更新 更多