Java Webhook - Migration to v2 - Can not set query

2019-04-10 10:32发布

问题:

i am using dialogflow v1 with spring boot java as webhook using: http://mvnrepository.org/artifact/ai.api/libai/1.6.12

now i try upgrading to dialogflow v2 using this: http://mvnrepository.org/artifact/com.google.apis/google-api-services-dialogflow/v2-rev2-1.23.0

<dependency>
    <groupId>com.google.apis</groupId>
    <artifactId>google-api-services-dialogflow</artifactId>
    <version>v2-rev2-1.23.0</version>
</dependency>

purpose: so i dont have to take care of parsing/building the json myself i have found it over the mvnrepository search

i intercepted this json:

{
    "responseId": "72945ef4-0897-4705-a770-a12100162b45",
    "queryResult": {
        "queryText": "was gibts neues?",
        "action": "GetNewsFromWordpress",
        "parameters": {
            "allRequiredParamsPresent": true
        },
        "name": "projects/kreamont-abf6b/agent/intents/fe2c13a1-2e3f-48eb-a15a-660501c16807",
        "diagnosticInfo": {

        }
    },
    "languageCode": {
        "intentDetectionConfidence": 1.0
    },
    "displayName": {
        "payload": {

        }
    },
    "session": "projects/kreamont-abf6b/agent/sessions/e69aabe7-4f6a-4224-b881-8bbf31835ef2"
}           

jackson is somehow unable to bind the model. how can i use some java lib so i dont have to take care of parsing the json myself?

com.fasterxml.jackson.databind.JsonMappingException: Can not set com.google.api.services.dialogflow.v2.model.GoogleCloudDialogflowV2QueryResult field com.google.api.services.dialogflow.v2.model.GoogleCloudDialogflowV2WebhookRequest.queryResult to java.util.LinkedHashMap (through reference chain: com.google.api.services.dialogflow.v2.model.GoogleCloudDialogflowV2WebhookRequest["queryResult"])

@RequestMapping(method = RequestMethod.POST, path = "fulfillment", consumes = MediaType.APPLICATION_JSON_VALUE)
public GoogleCloudDialogflowV2WebhookResponse getFulfillment(@RequestBody GoogleCloudDialogflowV2WebhookRequest request) {
    // HttpMessageNotReadableException 
    ...

回答1:

The library is depending on the google-api-client. That has a customized json parser for the transfer objects (like GoogleCloudDialogflowV2WebhookRequest). These objects extending from a map. Their elements are marked with the Key annotation. That is why the normal jackson or gson parsers are failing. You have multiple options:

  1. copy and modify the transfer objects (bad if the api will change in the future)
  2. write a httpmessageconverter for spring that uses the google api json parser (do not know how much effort that would be)
  3. disable the spring message converters for your endpoint and do the marshalling on your own like this:

    import com.google.api.client.json.JsonGenerator;
    import com.google.api.client.json.jackson2.JacksonFactory;
    import com.google.api.services.dialogflow.v2.model.*;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;
    import reactor.core.publisher.Mono;
    
    import java.io.IOException;
    import java.io.StringWriter;
    import java.util.Collections;
    
    @RestController
    public class DialogflowWebhookController {
    
    private static JacksonFactory jacksonFactory = JacksonFactory.getDefaultInstance();
    
    @PostMapping("/dialogflow")
    public Mono<String> webhook(@RequestBody String rawRequest) throws IOException {
    
        GoogleCloudDialogflowV2WebhookRequest request = jacksonFactory.createJsonParser(rawRequest)
            .parse(GoogleCloudDialogflowV2WebhookRequest.class);
    
        StringWriter stringWriter = new StringWriter();
        JsonGenerator jsonGenerator = jacksonFactory.createJsonGenerator(stringWriter);
        GoogleCloudDialogflowV2WebhookResponse response = ...
        jsonGenerator.serialize(response);
        jsonGenerator.flush();
        return Mono.just(stringWriter.toString());
    }
    }