【问题标题】:com.fasterxml.jackson.databind.exc.MismatchedInputException while parsing json reply into object using fasterxmlcom.fasterxml.jackson.databind.exc.MismatchedInputException,同时使用fastxml将json回复解析为对象
【发布时间】:2019-01-31 23:03:17
【问题描述】:

我正在尝试使用 fastxml 将 json 回复解析为 POJO。但问题是 json 回复包含嵌套对象,其中包含反斜杠,因此在 ObjectMapper 读取此值期间,我收到 com.fasterxml.jackson.databind.exc.MismatchedInputException

com.fasterxml.jackson.databind.exc.MismatchedInputException:无法构造com.am.api.Message 的实例(尽管至少存在一个创建者):没有从字符串值反序列化的字符串参数构造函数/工厂方法('{"entryType" :"买入","汇率":"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","re​​ceivedAmount": "0"}}') 在 [来源:(字符串)“{ "topic":"交易/报价/BTC-PLN", "message":"{\"entryType\":\"Buy\",\"rate\":\"22000.0\",\"action\":\"update\",\"offerId\":\" b96f2da7-55f9-4221-aaa3-8e3ad177567d\",\"market\":\"BTC-PLN\",\"state\":{\"market\":\"BTC-PLN\",\"offerType \":\"买入\",\"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\",\"receivedAmoun"[截断45个字符];行:3,列:13](通过引用链:com.am.api.WsOrderReply["message "]) 在 com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63) 在 com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1329) 在 com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1031) 在 com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:370) 在 com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:314) 在 com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1351) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:170) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:161) 在 com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:519) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:527) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:416) 在 com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1265) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:325) 在 com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159) 在 com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001) 在 com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992) 在 com.am.ReplyMapper.readValue(ReplyMapper.java:154) 在 com.am.ReplyMapper.mapReplyToCommonExecutionReport(ReplyMapper.java:73) 在 com.am.ReplyMapper.lambda$apply$1(ReplyMapper.java:54) 在 java.util.Optional.map(Optional.java:215) 在 com.am.ReplyMapper.apply(ReplyMapper.java:54) 在 com.am.ReplyMapperTest.shouldMapUpdateOrderReplyNew(ReplyMapperTest.java:64) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 在 org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 在 org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 在 org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 在 org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 在 org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 在 org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 在 org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 在 org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 在 org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 在 org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 在 org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 在 org.junit.runners.ParentRunner.run(ParentRunner.java:363) 在 org.junit.runner.JUnitCore.run(JUnitCore.java:137) 在 com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) 在 com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) 在 com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) 在 com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

不知道怎么用fasterxml解析这个对象?!

我的 POJO 对象模型如下所示:

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

我收到的原始 json 消息:

{ "topic":"交易/报价/BTC-PLN", "message":"{\"entryType\":\"Buy\",\"rate\":\"22000.0\",\"action\":\"update\",\"offerId\":\" b96f2da7-55f9-4221-aaa3-8e3ad177567d\",\"market\":\"BTC-PLN\",\"state\":{\"market\":\"BTC-PLN\",\"offerType \":\"买入\",\"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\"}}", “时间戳”:1535023208264 }

我的 JUnit 测试:

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

也许有人和我有同样的问题。如何解决这个问题?

【问题讨论】:

    标签: java json exception backslash fasterxml


    【解决方案1】:

    即使未转义,您使用的 JSON 也不正确 因此,它将整个对象视为一个字符串。 使用正确的转义 json 将解决问题,我已经更正了 JSON,你现在看看它是否可以正常工作

    {\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}
    

    如果无法更改 Json,则需要在构造函数中将消息作为字符串值获取,然后使用对象映射器将其显式转换为对象

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

    另一个无需更改模型类即可工作的解决方案是从服务器获取 JSON,然后在本地将其更改为第一种方法中提到的格式

    【讨论】:

    • 感谢您对本主题的关注,但我提供的 json 格式是我从服务器接收的格式。所以我不能改变 json 的格式,因为我的映射器不能工作。
    • 我已经对我的答案进行了相应的修改,请立即尝试,让我知道它是否有效。
    • 好的,我解决了这个问题。在作为回复的第一个嵌套对象中,我将消息类型更改为字符串(之前是对象消息),接下来我将字符串消息解析为消息对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多