NULL inclusion bug(?) even with Include.NON_NULL

727 views
Skip to first unread message

Bogdan Vaneev

unread,
Jul 20, 2018, 3:44:39 PM7/20/18
to jackson-user
I am using jackson-databind 2.9.6:
compile("com.fasterxml.jackson.core:jackson-databind:2.9.6")

And it looks like I found a bug. When object mapper is told to not include nulls, it still includes if you read JSON to tree, then write to string from this tree.
I wrote small example using groovy and spock:

package jackson

import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.ObjectMapper
import spock.lang.Specification

class ObjectMapperTest extends Specification {
    def "should not include nulls"() {
        given:
        def json = '''
                {
                    "a": {},
                    "b": [],
                    "c": "",
                    "d": 0,
                    "e": null
                }
        '''

        def obj = [
                "a": [:],
                "b": [],
                "c": "",
                "d": 0,
                "e": null
        ]

        def jsonMapper = new ObjectMapper()
                .setSerializationInclusion(JsonInclude.Include.NON_NULL)
        def tree = jsonMapper.readTree(json)


        when:
        def a1 = jsonMapper.writeValueAsString(tree)
        def a2 = jsonMapper.writeValueAsString(obj)

        then:
        a1 == a2
    }
}


Because the same mapper is used, both a1 and a2 should not include key "e" (its value is null).

But the actual output is the following:
Condition not satisfied:

a1 == a2
|  |  |
|  |  {"a":{},"b":[],"c":"","d":0}
|  false
|  9 differences (75% similarity)
|  {"a":{},"b":[],"c":"","d":0(,"e":null)}
|  {"a":{},"b":[],"c":"","d":0(---------)}
{"a":{},"b":[],"c":"","d":0,"e":null}

Expected :{"a":{},"b":[],"c":"","d":0}

Actual   :{"a":{},"b":[],"c":"","d":0,"e":null}


Is that a bug?

Tatu Saloranta

unread,
Jul 20, 2018, 3:55:24 PM7/20/18
to jackson-user
No: JsonNode trees are not subject to most processing that is applied
for POJOs, since inclusion criteria
is defined for POJO properties, and nodes are not considered POJOs in
this context.
I realize that this is confusing as basically there are really
multiple kinds of Java objects (POJOs and
JsonNode differ, but Maps are yet another class... so at least 3) with
diffierent processing models.

Much of this is due to backend handlers being different, although part
has to do with intended semantics too.
My thinking from beginning has been that JsonNode is meant to
represent JSON contents 1-to-1, with no
changes or distortions, whereas POJO mapping is designed to apply
various minor translations, in order to
bridge the so-called impedance (Java object model, JSON model
differing). This made sense to me, but I can
see that it may not make sense to others, or could be matter of preference too.

For Jackson 3.x it would be good to figure out how to define rules
that are simpler (if possible), and applicability.
I have some ideas on how that could work, esp. by "Class categories";
ability to define settings for "kinds" (categories)
of classes -- like, "all Collections" or "all scalar types". If so,
inclusion criteria could also be specified separately for
"all JsonNodes".

For Jackson 2.x it is probably not possible to change things much
since existing behavior is what users count on,
and changes could lead to regression in existing application code.

I hope this helps.

-+ Tatu +-
Reply all
Reply to author
Forward
0 new messages