[jackson-user] NULL inclusion bug(?) even with Include.NON_NULL

2018-08-05 Thread Bogdan Vaneev
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?

-- 
You received this message because you are subscribed to the Google Groups 
"jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to jackson-user+unsubscr...@googlegroups.com.
To post to this group, send email to jackson-user@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [jackson-user] NULL inclusion bug(?) even with Include.NON_NULL

2018-08-05 Thread Tatu Saloranta
On Wed, Jul 18, 2018 at 4:32 AM, Bogdan Vaneev  wrote:
> 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?

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 +-

-- 
You received this message because you are subscribed to the Google Groups 
"jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to jackson-user+unsubscr...@googlegroups.com.
To post to this group, send email to jackson-user@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.