1

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\",\"rate\":\"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.SettableBeanProperty.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(Optional.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(BlockJUnit4ClassRunner.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?

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for your interest of this topic, but the json format which I provided is in the format which I'm receiving from the server. So I can not change format of the json becasue my mapper will not work.
I have made edits to my answer accordingly,Please try it now and let me know weather it worked.
Ok I solved this problem. In first nested object as reply I have changed message type into String (ealier was object Message) and next I parse String message into Message object.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.