Hello,
the backport for #2331 into 2.9.9, specific 2.9.9.2, which comes through 2.9.9.20190727, leads to a null pointer exception together with the JDK 8 module:
Given
package ac.simons;
import java.io.IOException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
public class JacksonTest {
@Test
void shouldWorkWithoutJdk8Module() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
final JsonNode responseNode = objectMapper.readTree("{}");
Assertions.assertNotNull(responseNode);
}
@Test
void shouldWorkWithJdk8Module() throws IOException {
ObjectMapper objectMapper = new ObjectMapper()
.registerModule(new Jdk8Module());
final JsonNode responseNode = objectMapper.readTree("{}");
Assertions.assertNotNull(responseNode);
}
}
It doesn't matter whether the object to be parsed is empty as above or contains data as for example
final JsonNode responseNode = objectMapper.readTree("{\"something\":\"foobar\"}");
Works with com.fasterxml.jackson:jackson-bom:2.9.9 and breaks with com.fasterxml.jackson:jackson-bom:2.9.9.20190727:
java.lang.NullPointerException
at com.fasterxml.jackson.databind.type.ResolvedRecursiveType.getBindings(ResolvedRecursiveType.java:42)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1243)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1452)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1221)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1367)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1314)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1217)
at com.fasterxml.jackson.databind.type.TypeFactory.constructType(TypeFactory.java:631)
at com.fasterxml.jackson.databind.cfg.MapperConfig.constructType(MapperConfig.java:281)
at com.fasterxml.jackson.databind.cfg.MapperConfig.introspectClassAnnotations(MapperConfig.java:311)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findTypeDeserializer(BasicDeserializerFactory.java:1571)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:483)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4191)
at com.fasterxml.jackson.databind.ObjectMapper._readTreeAndClose(ObjectMapper.java:4052)
at com.fasterxml.jackson.databind.ObjectMapper.readTree(ObjectMapper.java:2552)
at ac.simons.JacksonTest.shouldWorkWithJdk8Module(JacksonTest.java:27)
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.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:675)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:125)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:132)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:124)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:74)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:104)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:62)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:43)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:35)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:202)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:198)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
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)
Please find a sample project attached.
I can confirm this bug. I just wasted my morning trying to find out what's going on. Turned out to be the 2.9.9.2 release.
Confirmed here too. Using JDK 11. In my case, when Dropwizard is trying to parse its yml config file:
java.lang.NullPointerException
at com.fasterxml.jackson.databind.type.ResolvedRecursiveType.getBindings(ResolvedRecursiveType.java:42)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1243)
at com.fasterxml.jackson.databind.type.TypeFactory._fromParamType(TypeFactory.java:1452)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1221)
at com.fasterxml.jackson.databind.type.TypeFactory._resolveSuperInterfaces(TypeFactory.java:1367)
at com.fasterxml.jackson.databind.type.TypeFactory._fromClass(TypeFactory.java:1314)
at com.fasterxml.jackson.databind.type.TypeFactory._fromAny(TypeFactory.java:1217)
at com.fasterxml.jackson.databind.type.TypeFactory.constructType(TypeFactory.java:631)
at com.fasterxml.jackson.databind.cfg.MapperConfig.constructType(MapperConfig.java:281)
at com.fasterxml.jackson.databind.cfg.MapperConfig.introspectClassAnnotations(MapperConfig.java:311)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findTypeDeserializer(BasicDeserializerFactory.java:1571)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:483)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4191)
at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:3980)
at com.fasterxml.jackson.databind.ObjectMapper.readTree(ObjectMapper.java:2385)
at io.dropwizard.configuration.BaseConfigurationFactory.build(BaseConfigurationFactory.java:81)
We are also affected.
In our case the issue is observed using spring-data-redis's Jackson2HashMapper; but looks like a similar problem; details here.
(_Edit_: just checked and we initialize our Jackson2HashMapper with the default ObjectMapper injected via Spring; which itself has the JDK8 module registered by default via the Jackson2ObjectMapperBuilder's "well-known modules" support; so it seems quite possible it's the same root cause.)
It would also be good if we could get the changelog fixed too; the change that broke this was incorrectly included in the changelog for 2.9.9.1 - not 2.9.9.2 when it was actually released.
I'll update the changelog first. Reproduction with Java8 module is interesting since it is unclear why and how that should have any effect (obviously basic readTree() functionality is heavily tested in databind itself, but won't fail somehow).
I will start with the test case but will need to figure out how to reproduce without other modules as tests from jackson-databind can not rely on modules (which depend on databind).
I can reproduce this: looks like NPE is indirectly triggered by call to JavaType.getBindings();, which is not needed if no TypeModifiers registered. Bit odd that existing test class TestTypeModifiers does NOT somehow hit that... which is too bad as that would have caught the problem.
Ah. This is due to JsonNode having recursive self-reference via Iterable<JsonNode>.
Great response time! :rocket:
Indeed. Shit happens, and this is has been dealt with. Thank you, @cowtowncoder !
Do you have an indication about availability in a release?
I'll have to think about timing a bit. There haven't been too many fixes aside from this one critical one, so it'll probably be 2.9.9.3 with matching jackson-bom; this is relatively light-weight thing to do (an hour or so). But I'd like to see if there are any fixes that would be backported in 2.9 jackson-databind since there will be another release.
But I think I will release that micro-patch by end of this week (so within 6 days).
Thanks a lot!
Any plans to release 2.9.9.3 soon?
^
@cowtowncoder there is a Spring Boot milestone coming up in less than 24h. No rush from our side as this is a pre-release but would love to get the CVE fix if you have time to release this fix. Thank you!
I'll try to get this released tonight -- meant to do it over the weekend but things got bit busy.
Came to report https://github.com/talios/broken-jackson-databind which I mentioned on the mailing list yesterday - good to see it's fixed already!
@talios yes, it's unfortunate this nasty regression got released, but at least it was promptly reported and help is on its way.
2.9.9.3 of jackson-databind out with matching jackson-bom, as per:
https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.9
Thanks @cowtowncoder !
Bummer @cowtowncoder, the new bom still refers to 2.9.9.2 as far as I can see, see https://github.com/FasterXML/jackson-bom/issues/24
Oh... f. Ok. How did I manage to do that. Joys of manual releases. Will need to release another pom. Thank you for reporting this.
2.9.9.20190807 on its way now.
Thanks for the quick turnaround @cowtowncoder
Most helpful comment
2.9.9.3ofjackson-databindout with matchingjackson-bom, as per:https://github.com/FasterXML/jackson/wiki/Jackson-Release-2.9