com.fasterxml.jackson.databind.exc.MismatchedInputException при синтаксическом анализе ответа json в объект с использованием fastxml - PullRequest
0 голосов
/ 26 августа 2018

Я пытаюсь разобрать ответ json в POJO, используя fastxml. Но проблема в том, что ответ json включает вложенные объекты, которые включают обратную косую черту, поэтому во время чтения этого значения ObjectMapper я получаю com.fasterxml.jackson.databind.exc.MismatchedInputException

com.fasterxml. : "купить", "скорость": "22000,0", "действие": "обновление", "offerId": "b96f2da7-55f9-4221-aaa3-8e3ad177567d", "рынок": "BTC-PLN", "государство" : { "рынок": "BTC-PLN", "offerType": "Купить", "идентификатор": "b96f2da7-55f9-4221-aaa3-8e3ad177567d", "currentAmount": "0,0005", "lockedAmount": "11.00 », "скорость": "22000,0", "startAmount": "0,0005", "время": "1535023208260", "postOnly":, ложь "скрытый": ложь, "режим": "предел", "receivedAmount": "0"}} ') в [Источник: (Строка) "{ "Тема": "торговые / предложения / BTC-PLN", "Сообщение": "{\" EntryType \ ": \" Купить \ "\ "скорость \": \ "22000,0 \", \ "действия \": \ "обновление \", \ "offerId \": \" b96f2da7-55f9-4221-aaa3-8e3ad177567d \ "\ "рынок \": \ "BTC-зл \", \ "состояние \": {\ "рынок \": \ "BTC-зл \", \" offerType \ ": \" Купить \ "\ "идентификатор \": \ "b96f2da7-55f9-4221-aaa3-8e3ad177567d \", \ "currentAmount \": \ "0,0005 \", \ "lockedAmount \": \" 11.00 \ "\ "скорость \": \ "22000,0 \", \ "startAmount \": \ "0,0005 \", \ "время \": \ "1535023208260 \", \ "postOnly \" ложь \" скрытый \ ": false, \" mode \ ": \" limit \ ", \" receiveAmoun "[усеченные 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) at sun.reflect.NativeMethodAccessorImpl.invoke0 (собственный метод) at 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.FrameworkMethof: 1.50) в org.junit.internal.runners.model.ReflectiveCallable.run (ReflectiveCallable.java:12) в org.junit.runners.model.FrameworkMethod.invokeВзрывоопасно (FrameworkMethod.java:47) в org.junit.junit.statements.InvokeMethod.evaluate (InvokeMethod.java:17) в org.junit.runners.ParentRunner.runLeaf (ParentRunner.java:325) в org.junit.runners.BlockJUnit4ClassRunner.rlassNun.jun .jj4 ()junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:57) в org.junit.runners.ParentRunner $ 3.run (ParentRunner.java:290) в org.junit.runners.ParentRunner ParentRunner $ 1.sc $ 1.scв 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.j:363) в org.junit.runner.JUnitCore.run (JUnitCore.java:137) в com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs (JUnit4IdeaTestRunner.java:68) комиссионные сборы за вознаграждение.startRunnerWithArgs (IdeaTestRunner.java:47) в com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart (JUnitStarter.java:242) в com.intellij.rt.execution.junit.j.it.Jitit)

Я не знаю, как проанализировать этот объект, используя fastxml?!

Моя модель объектов 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": "trading / offer / BTC-PLN", "message": "{\" entryType \ ": \" Buy \ ", \" rate \ ": \ "22000,0 \", \ "действие \": \ "обновление \", \ "offerId \": \ "b96f2da7-55f9-4221-aaa3-8e3ad177567d \", \ "рынок \": \ "BTC-PLN \ "\ "состояние \": {\ "рынок \": \ "BTC-зл \", \ "offerType \": \ "Купить \", \ "ид \": \" b96f2da7-55f9-4221-aaa3-8e3ad177567d \», \ "currentAmount \": \ "0,0005 \", \ "lockedAmount \": \ "11,00 \", \ "скорость \": \ "22000,0 \", \ "startAmount \":\ "0,0005 \", \ "время \": \ "1535023208260 \", \ "postOnly \" ложь \ "скрытые \" ложь \ "режим \": \ "предел \", \ "receivedAmount \": \" 0 \ "}}", "timestamp": 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));
    }

Может быть, у кого-то тоже была такая же проблема, как и у меня. Как решить эту проблему?

1 Ответ

0 голосов
/ 26 августа 2018

Используемый вами JSON неверен, даже если он не экранирован Поэтому он рассматривает весь объект как строку. Использование правильного escape-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 с сервера, а затем изменить его локально на формат, упомянутый в первом подходе

...