简体   繁体   中英

Jackson deserialization of String fails

Our system utilizes Jackson (Java 11) to deserialize objects from external sources. When we receive the payload it is in String (UTF-8) format. It fails to deserialize with an exception (MismatchedInputException)

Cannot construct instance of 'object' (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{

Stack Technology:

  • Java 11
  • Jackson 2.9.8
  • Google Cloud (platform)

We ended up using multiple replaceAll statements just to get the payload in a state that would allow the string to be converted to an object in jackson. The code really smells...

I'm not sure if this helps but the payload is pulled from Google PubSub Subscription. So I have a message receiver listens on the subscription. I was originally using Springs JacksonPubSubMessageConverter but was throwing the exception above. I rolled my own, adding the replaceAll(..) below and now that seems to have fixed the problem.

public class ABCMessageReceiver implements MessageReceiver {
  private PubsubMessageConverter converter;
  public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
    Person person = converter.fromPubSubMessage(message, Person.class);
    ...
  }
}
payload = "{\n  \"general\": {\n    \"aggregatorId\": \"111111111111\",\n    \"communityId\": \"30303030\",\n    \"dateStamp\": \"2019-07-09\",\n    \"comments\": \"Testing E2E1\"\n  },\n  \"prospect\": {\n    \"firstName\": \"Joe\",\n    \"lastName\": \"Smith\",\n    \"nickName\": \"\",\n    \"email\": \"joe.smith@sample.com\",\n    \"gender\": \"MALE\",\n    \"maritalStatus\": \"SINGLE\",\n    \"dateOfBirth\": \"1956-06-15\",\n    \"veteranStatus\": \"NOTAVETERAN\",\n    \"address\": {\n      \"address1\": \"100 Acme Street \",\n      \"address2\": \"Suite 2300\",\n      \"city\": \"Acme City\",\n      \"state\": \"WI\",\n      \"zip\": \"53214\"\n    },\n    \"phones\": [\n      {\n        \"number\": \"4145551212\",\n        \"type\": \"WORK\"\n      }\n    ],\n    \"financial\": {\n      \"budgetAmount\": 2639,\n      \"budgetFrequency\": \"MONTHLY\",\n      \"medicaid\": true,\n      \"medicare\": true,\n      \"ltcPolicy\": false,\n      \"homeowner\": true,\n      \"vaAid\": false\n    },\n    \"prospectNeeds\": {\n      \"desiredCareLevel\": \"AL\"\n    }\n  },\n  \"tour\": {\n    \"date\": \"2019-07-14T17:00:00.000Z\",\n    \"notes\": \"Testing tour notes 1\"\n  }\n}"
payload = payload.replaceAll("\\\\\"", "\"");
payload = payload.replaceAll("\\\\n", "");
payload = payload.substring(1);
payload = payload.substring(0, payload.length()-1);

I don't like the overhead string replacements, but it seems to work for now, until I get another string permutation that I need to support.

I would like to thank @Andreas and others that supplied comments. It wasn't connecting at first regarding encoding, I had to come back to it the next day. Yes, I would love it if the producer submitted properly formatted JSON. Here is what I did to get it working, not the best solution, but it works. I extended JacksonPubSubMessageConverter.java and created a new unencoded version.

UnencodedJacksonPubSubMessageConverter.java

...
public <T> T fromPubSubMessage(PubsubMessage message, Class<T> payloadType) {
    try {
        String payload = message.getData().toStringUtf8();
        payload = removeQuotesIfNecessary(unescapePayload(payload));
        return (T) this.objectMapper.readerFor(payloadType).readValue(payload);
    }
    catch (IOException ex) {
        throw new PubSubMessageConversionException("JSON deserialization of an object of type " + payloadType.getName() + " failed.", ex);
    }
}

private String removeQuotesIfNecessary(String payload) {
    if (payload != null && payload.startsWith("\"") && payload.endsWith("\"")) {
        return payload.substring(1).substring(0, payload.length()-2);
    }
    return payload;
}

private String unescapePayload(String payload) {
    if (payload != null)
        return StringEscapeUtils.unescapeJson(payload);
    return payload;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM