Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NPE when transforming a tree to a model class object, at ArrayNode.elements() #4145

Closed
1 task done
OndraZizka opened this issue Oct 6, 2023 · 5 comments
Closed
1 task done
Labels
2.16 Issues planned for 2.16
Milestone

Comments

@OndraZizka
Copy link

Search before asking

  • I searched in the issues and found nothing similar.

Describe the bug

When deserializing a tree of JsonNodes, Jackson causes a NPE.

The ArrayNode where it fails is likely the one created this way in Kotlin:

tree.set<ObjectNode>("connectUiConfig", ObjectNode(factory, mapOf(
        "assetMetadataFilters" to ArrayNode(factory, ddbModel.systemData?.ui?.myOtherModel?.map { it ->
            MyOtherModelClass(...)
                .let { jsonMapper.valueToTree<ObjectNode>(it) }
        })
    )))

Which means, in ArrayNode(..., content), the content is null.

Version Information

2.15.2

Reproduction

tree.set<ObjectNode>("connectUiConfig", 
   ObjectNode(factory, mapOf(
        "assetMetadataFilters" to ArrayNode(..., null)
  ))
))

jsonMapper.treeToValue(tree, MyModel::class.java)

Where MyModel would be an appropriate class.

Expected behavior

  1. Maybe ArrayNode should not accept null as a content?

  2. Jackson should fail gracefully, with a proper error message

  3. Optionally, it could just create an empty array node in such situation, for those who prefer robustness over validity.

Additional context

com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.mycompany.myapp.api.tenants.TenantApiGetModel["connectUiConfig"])
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:402) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:361) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1853) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:572) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:439) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1409) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:4801) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2974) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.ObjectMapper.treeToValue(ObjectMapper.java:3438) ~[tenants-http-api.jar:?]
	at com.mycompany.myapp.api.SomeApiGetModelKt.from(SomeApiGetModel.kt:107) ~[tenants-http-api.jar:?]
Caused by: java.lang.NullPointerException
	at com.fasterxml.jackson.databind.node.ArrayNode.elements(ArrayNode.java:251) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.node.NodeCursor$ArrayCursor.<init>(NodeCursor.java:161) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.node.NodeCursor$ObjectCursor.startArray(NodeCursor.java:228) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.node.TreeTraversingParser.nextToken(TreeTraversingParser.java:118) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:425) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1409) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:545) ~[tenants-http-api.jar:?]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:570) ~[tenants-http-api.jar:?]
	... 76 more
@OndraZizka OndraZizka added the to-evaluate Issue that has been received but not yet evaluated label Oct 6, 2023
@cowtowncoder
Copy link
Member

Java reproduction would be needed, just in case. Or at least full standalone one -- this appears to be code snippet?

@OndraZizka
Copy link
Author

OndraZizka commented Oct 6, 2023

Yes, it is a snippet - I was hoping someone would see right away what the situation is, and the report would thus be useful.

The trigger is that the ArrayNode is created with null as a content instead of a list.

After I coded the tree manipulation properly:

val filters: List<SystemData.Ui.AssetMetadataFilter>? = ddbModel.systemData?.ui?.filters
    tree.set<ObjectNode>("uiConfig", ObjectNode(factory, mapOf(
        "filters" to
            if (filters == null) NullNode.instance
            else ArrayNode(factory, filters.map { filter ->
                Filters(defaultLabel = filter.defaultLabel, path = filter.path, type = filter.type)
                    .let { jsonMapper.valueToTree<ObjectNode>(it) }
        })
    )))

Now the objectMapper.treeToValue() works.

@cowtowncoder
Copy link
Member

Yeah, Kotlin version is pretty dense so it was not obvious to me where null would be coming in.
Thank you for clarification.

@cowtowncoder cowtowncoder added 2.16 Issues planned for 2.16 and removed to-evaluate Issue that has been received but not yet evaluated labels Oct 7, 2023
@cowtowncoder cowtowncoder changed the title NPE when transforming a tree to a model class object, at ArrayNode.elements(ArrayNode.java:251) NPE when transforming a tree to a model class object, at ArrayNode.elements() Oct 7, 2023
@cowtowncoder cowtowncoder added this to the 2.16.0 milestone Oct 7, 2023
cowtowncoder added a commit that referenced this issue Oct 7, 2023
@cowtowncoder
Copy link
Member

Thank you @OndraZizka: I added null check for both ArrayNode and ObjectNode constructors wrt passing of children argument. Eager check ftw!

@OndraZizka
Copy link
Author

Thanks @cowtowncoder :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2.16 Issues planned for 2.16
Projects
None yet
Development

No branches or pull requests

2 participants