-
-
Notifications
You must be signed in to change notification settings - Fork 819
Description
Describe the bug
If I use the ObjectMapper.readValue(byte[], int offset, int len, TypeReference)
interface to deserialize a value AND the deserialize fails (e.g. bad data not conforming to the expected type), the exception refers to the entire buffer rather than the buffer starting at offset
.
This leads to a misleading exception where it appears as the entire buffer is the problem, where the real problem is starting somewhere else.
This came up when processing byte buffers of JSON line separated data (so the buffer may contain more than one JSON object).
Version information
Which Jackson version(s) was this for?
2.11.0
To Reproduce
If you have a way to reproduce this with:
@Test
public void simpleJsonTest()
throws Exception
{
String json = "{\"k1\":\"v1\"}\n[\"oops\"]\n{\"k2\":\"v2\"}";
byte[] buffer = json.getBytes(UTF_8);
int itemStart = json.indexOf('\n') + 1; // Get the second record start
int itemEnd = json.indexOf('\n', itemStart); // End of second record
int itemLength = itemEnd - itemStart;
ObjectMapper mapper = new ObjectMapper();
TypeReference<Map<String, String>> typeReference = new TypeReference<>()
{
};
Map<String, String> decoded = mapper.readValue(buffer, itemStart, itemLength, typeReference);
}
Stack trace with error:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.LinkedHashMap<java.lang.Object,java.lang.Object>` out of START_ARRAY token
at [Source: (byte[])"{"k1":"v1"}
["oops"]
{"k2":"v2"}"; line: 1, column: 1]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1464)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1238)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1148)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer._deserializeFromEmpty(StdDeserializer.java:639)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:360)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:29)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4482)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3521)
at XXX.simpleJsonTest(XXX.java:152)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:583)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:719)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:989)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
at org.testng.TestRunner.privateRun(TestRunner.java:648)
at org.testng.TestRunner.run(TestRunner.java:505)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
at org.testng.SuiteRunner.run(SuiteRunner.java:364)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1137)
at org.testng.TestNG.runSuites(TestNG.java:1049)
at org.testng.TestNG.run(TestNG.java:1017)
at com.intellij.rt.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:66)
at com.intellij.rt.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:109)
Expected behavior
In this case, I would expect the exception error message to point to the start offset (here its the ["oops"]
chunk). Due to the supplied source context, the "line 1 column 1" guides the reader to point to the start of the (valid) first record in the buffer, rather than the actual problem which is line 1 column 1 in the second invalid record.
Additional context
Add any other context about the problem here.
In the example, the underlying exceptions' JsonLocation looks like this:
_totalBytes = 0
_totalChars = -1
_lineNr = 1
_columnNr = 1
_sourceRef= The whole buffer