web-dev-qa-db-fra.com

Impossible de désérialiser l'instance de Java.lang.String à partir du jeton START_OBJECT

Je rencontre un problème où mon pot déployable rencontre une exception qui ne se produit pas lorsque je l'exécute localement dans IntelliJ. 

Exception:

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

Gestionnaire de sockets

Je crois que l'exception se produit lorsque le JSON est analysé dans un objet WorkstationRequest en raison de l'élément ci-dessous. Voici le gestionnaire de socket:

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

L'objet que le gestionnaire de socket met en correspondance avec:

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;
    }
}

Le JSON en cours de mappage:

{"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;
    }
}

Je ne sais pas trop comment commencer à déboguer cela. La trace de pile ne touche jamais mon application. J'utilise Maven -> Package pour déployer mon fichier .jar et l'exécuter avec Java -jar /path-to-jar.jar

Mise à jour: Pour éviter que cette question ne soit incroyablement longue, j'ai inclus mon pom.xml ici: http://Pastebin.com/1ZUtKCfE . Je pense qu'il s'agit d'un problème de dépendance, car l'erreur ne se produit que sur mon fichier jar déployable et non sur mon PC local.

42
Webnet

Vous mappez ce JSON 

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

qui contient un élément nommé data dont la valeur est un objet JSON. Vous essayez de désérialiser l'élément nommé workstationUuid de cet objet JSON dans ce programme de configuration.

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

Cela ne fonctionnera pas directement car Jackson voit un JSON_OBJECT, pas une chaîne.

Essayez de créer une classe Data

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

l'interrupteur de votre méthode

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

Le contenu des données est tellement variable, je pense que la meilleure forme est de le définir comme "ObjectNode" et ensuite de créer sa propre classe à analyser:

Finalement: 

données ObjectNode privées;

15
richardhell

Si vous ne souhaitez pas définir une classe distincte pour JSON imbriqué, la définition d'un objet JSON imbriqué en tant que JsonNode devrait fonctionner.

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

@JsonProperty("data")
    private JsonNode data;
9
Sindhu

Résolu le problème en utilisant la bibliothèque de Jackson. Les impressions sont appelées en dehors de la classe Main et toutes les classes POJO sont créées. Voici les extraits de code.

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;
    }   
}

RÉSULTATS:

 La valeur de getFirstName est: 2 
 La valeur de getLastName est: 0c317829-69bf-43d6-b598-7c0c550635bb 
 La valeur de getChildren est: ddec1caa-a22f-4922-833f-632d07ffc11 
 : vrai
0
Lucky