简体   繁体   中英

com.fasterxml.jackson.databind.exc.MismatchedInputException while parsing json reply into object using fasterxml

I'm trying to parse json reply into POJO using fasterxml. But the problem is that the json reply includes nested objectes which include backslashes so during reading this value by ObjectMapper I'm receiving com.fasterxml.jackson.databind.exc.MismatchedInputException

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of com.am.api.Message (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"entryType":"Buy","rate":"22000.0","action":"update","offerId":"b96f2da7-55f9-4221-aaa3-8e3ad177567d","market":"BTC-PLN","state":{"market":"BTC-PLN","offerType":"Buy","id":"b96f2da7-55f9-4221-aaa3-8e3ad177567d","currentAmount":"0.0005","lockedAmount":"11.00","rate":"22000.0","startAmount":"0.0005","time":"1535023208260","postOnly":false,"hidden":false,"mode":"limit","receivedAmount":"0"}}') at [Source: (String)"{ "topic":"trading/offers/BTC-PLN", "message":"{\\"entryType\\":\\"Buy\\",\\"rate\\":\\"22000.0\\",\\"action\\":\\"update\\",\\"offerId\\":\\"b96f2da7-55f9-4221-aaa3-8e3ad177567d\\",\\"market\\":\\"BTC-PLN\\",\\"state\\":{\\"market\\":\\"BTC-PLN\\",\\"offerType\\":\\"Buy\\",\\"id\\":\\"b96f2da7-55f9-4221-aaa3-8e3ad177567d\\",\\"currentAmount\\":\\"0.0005\\",\\"lockedAmount\\":\\"11.00\\",\\"rat e\\":\\"22000.0\\",\\"startAmount\\":\\"0.0005\\",\\"time\\":\\"1535023208260\\",\\"postOnly\\":false,\\"hidden\\":false,\\"mode\\":\\"limit\\",\\"receivedAmoun"[truncated 45 chars]; line: 3, column: 13] (through reference chain: com.am.api.WsOrderReply["message"]) at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63) at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1329) at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1031) at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:370) at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:314) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1351) at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:170) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161) at com.fasterxml.jackson.databind.deser.Settable BeanProperty.deserialize(SettableBeanProperty.java:519) at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:527) at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:416) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1265) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:325) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992) at com.am.ReplyMapper.readValue(ReplyMapper.java:154) at com.am.ReplyMapper.mapReplyToCommonExecutionReport(ReplyMapper.java:73) at com.am.ReplyMapper.lambda$apply$1(ReplyMapper.java:54) at java.util.Optional.map(O ptional.java:215) at com.am.ReplyMapper.apply(ReplyMapper.java:54) at com.am.ReplyMapperTest.shouldMapUpdateOrderReplyNew(ReplyMapperTest.java:64) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRun ner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

I don't know how to parse this object using fasterxml?!

My POJO objects model looks like this:

@EqualsAndHashCode
@ToString
@Getter
@Builder
public class WsOrderReply {

    private final String topic;
    private final Message message;
    private final Long timestamp;

    @JsonCreator
    public WsOrderReply(
            @JsonProperty("topic") String topic,
            @JsonProperty("message") Message message,
            @JsonProperty("timestamp") Long timestamp) {
        this.topic = topic;
        this.message = message;
        this.timestamp = timestamp;
    }
}

@EqualsAndHashCode
@ToString
@Getter
public class Message {

    private final String entryType;
    private final BigDecimal rate;
    private final String action;
    private final String offerId;
    private final String market;
    private final State state;

    @JsonCreator
    public Message(
            @JsonProperty("entryType") String entryType,
            @JsonProperty("rate") BigDecimal rate,
            @JsonProperty("action") String action,
            @JsonProperty("offerId") String offerId,
            @JsonProperty("market") String market,
            @JsonProperty("state") State state) {
        this.entryType = entryType;
        this.rate = rate;
        this.action = action;
        this.offerId = offerId;
        this.market = market;
        this.state = state;
    }
}

@EqualsAndHashCode
@ToString
@Getter
public class State {

    private final String market;
    private final String offerType;
    private final String id;
    private final BigDecimal currentAmount;
    private final BigDecimal lockedAmount;
    private final BigDecimal rate;
    private final BigDecimal startAmount;
    private final String time;
    private final boolean postOnly;
    private final boolean hidden;
    private final String mode;
    private final BigDecimal receivedAmount;

    public State(
            @JsonProperty("market") String market,
            @JsonProperty("offerType") String offerType,
            @JsonProperty("id") String id,
            @JsonProperty("currentAmount") BigDecimal currentAmount,
            @JsonProperty("lockedAmount") BigDecimal lockedAmount,
            @JsonProperty("rate") BigDecimal rate,
            @JsonProperty("startAmount") BigDecimal startAmount,
            @JsonProperty("time") String time,
            @JsonProperty("postOnly") boolean postOnly,
            @JsonProperty("hidden") boolean hidden,
            @JsonProperty("mode") String mode,
            @JsonProperty("receivedAmount") BigDecimal receivedAmount) {
        this.market = market;
        this.offerType = offerType;
        this.id = id;
        this.currentAmount = currentAmount;
        this.lockedAmount = lockedAmount;
        this.rate = rate;
        this.startAmount = startAmount;
        this.time = time;
        this.postOnly = postOnly;
        this.hidden = hidden;
        this.mode = mode;
        this.receivedAmount = receivedAmount;
    }
}

Original json message which I'm receiving:

{ "topic":"trading/offers/BTC-PLN", "message":"{\\"entryType\\":\\"Buy\\",\\"rate\\":\\"22000.0\\",\\"action\\":\\"update\\",\\"offerId\\":\\"b96f2da7-55f9-4221-aaa3-8e3ad177567d\\",\\"market\\":\\"BTC-PLN\\",\\"state\\":{\\"market\\":\\"BTC-PLN\\",\\"offerType\\":\\"Buy\\",\\"id\\":\\"b96f2da7-55f9-4221-aaa3-8e3ad177567d\\",\\"currentAmount\\":\\"0.0005\\",\\"lockedAmount\\":\\"11.00\\",\\"rate\\":\\"22000.0\\",\\"startAmount\\":\\"0.0005\\",\\"time\\":\\"1535023208260\\",\\"postOnly\\":false,\\"hidden\\":false,\\"mode\\":\\"limit\\",\\"receivedAmount\\":\\"0\\"}}", "timestamp":1535023208264 }

My JUnit test:

public class ReplyMapperTest {

    private static ObjectMapper objectMapper;

    private MessageFactory msgFactory = new quickfix.fix42.MessageFactory();

    private TypeSelector fixMsgBuilder = FixMessageBuilder
            .usingFactory(msgFactory::create)
            .withBeginString(FixVersions.BEGINSTRING_FIX42);

    private ReplyMapper replyMapper = new ReplyMapper(objectMapper, fixMsgBuilder);

    @BeforeClass
    public static void beforeClass() {
        objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    }

    @Test
    public void shouldMapUpdateOrderReplyNew() throws FieldNotFound, IOException {
        String json = IOUtils.toString(this.getClass().getResourceAsStream("/json/UpdateOrderReplyNew.json"), StandardCharsets.UTF_8);

        //When
        List<Message> result = replyMapper.apply(json);

        //Then
        assertThat(result.get(0).getHeader().getString(MsgType.FIELD), is(Heartbeat.MSGTYPE));
    }

Maybe somebody also had same problem as I. How to solve this?

The JSON you are using is in incorrect even when unescaped Therefore it is treating the whole object as a String. Using the correct escaped json will solve the problem,i have corrected the JSON for you have a look now weather it works

{\r\n\t\"topic\": \"trading\/offers\/BTC-PLN\",\r\n\t\"message\": {\r\n\t\t\"entryType\": \"Buy\",\r\n\t\t\"rate\": \"22000.0\",\r\n\t\t\"action\": \"update\",\r\n\t\t\"offerId\": \"b96f2da7-55f9-4221-aaa3-8e3ad177567d\",\r\n\t\t\"market\": \"BTC-PLN\",\r\n\t\t\"state\": {\r\n\t\t\t\"market\": \"BTC-PLN\",\r\n\t\t\t\"offerType\": \"Buy\",\r\n\t\t\t\"id\": \"b96f2da7-55f9-4221-aaa3-8e3ad177567d\",\r\n\t\t\t\"currentAmount\": \"0.0005\",\r\n\t\t\t\"lockedAmount\": \"11.00\",\r\n\t\t\t\"rate\": \"22000.0\",\r\n\t\t\t\"startAmount\": \"0.0005\",\r\n\t\t\t\"time\": \"1535023208260\",\r\n\t\t\t\"postOnly\": false,\r\n\t\t\t\"hidden\": false,\r\n\t\t\t\"mode\": \"limit\",\r\n\t\t\t\"receivedAmount\": \"0\"\r\n\t\t}\r\n\t},\r\n\t\"timestamp\": 1535023208264\r\n}

If the Json cannot be changed then you need to get the message in constructor as String value and then convert it into the object explicitly using object mapper

public class WsOrderReply {

        private final String topic;
        private final Message message;
        private final Long timestamp;
        ObjectMapper mapper = new ObjectMapper();

        @JsonCreator
        public WsOrderReply(
                @JsonProperty("topic") String topic,
                @JsonProperty("message") String messageString,
                @JsonProperty("timestamp") Long timestamp) {
            this.topic = topic;
            this.message = mapper.readValue(messageString, Message.class);;
            this.timestamp = timestamp;
        }
    }

Another solution that would work without requiring changes in model class is to get the JSON from server and then changing it locally to format mentioned in 1st approach

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