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

Can't deserialise an empty tag into an instance with no fields #209

Closed
jlous opened this issue Sep 13, 2016 · 6 comments
Closed

Can't deserialise an empty tag into an instance with no fields #209

jlous opened this issue Sep 13, 2016 · 6 comments

Comments

@jlous
Copy link

jlous commented Sep 13, 2016

As noted in #89:

  • jackson deserializes <x></x> and <x/> for leaf-nodes as NULL..
  • JAXB deserializes <x></x> or <x/> for leaf-nodes not as NULL-values but provides default-values (an integer will be 0 by default).

This is a big problem for me. I need to deserialize a third-party schema which represents some state using the presence of a tag, in some cases with no children or attributes

   <myObject>
       <someStructuredData>...</someStructuredData>
       <flag1/>    
       <flag3/>
   </myObject>

This maps naturally to fields that can be null or populated with objects that are dumb, but typed:

   class myObject{
       SomeStructuredData someStructuredData;
       Flag1 flag1;
       Flag2 flag2;
       Flag3 flag3;
   }

After deserializing the example above I want flags 1 and 3 to be populated, and flag 2 to be null.

But I can find no way to get Jackson-xml to deserialise empty tags to anything but null.
Is it truly not supported, or am I just missing something? Discerning meaningfully between missing and empty tags is a perfectly valid use of xml, and should be supported in some way or other.

@cowtowncoder
Copy link
Member

cowtowncoder commented Sep 27, 2016

Note that explicit null is indeed different from no value at all, so Jackson does distinguish this.
So one thing that might work is to have setter methods that translate nulls to some other state change; setter is not called if element is not encountered.

I agree in that handling of empty values is not optimal, but haven't figured a good way to handle it better.
Specifically while I think null is not unreasonable for other types (and defaulting, if any, could be handled as an orthogonal concern perhaps), it's bit sub-optimal for Strings.

@markaren
Copy link

markaren commented May 2, 2018

Just encountered this issue my self. The XML I'm parsing uses a child tag to define the type of the object.
Example:

<ModelVariables>
  <ScalarVariable name="h" valueReference="0" description="height, used as state"
                  causality="local" variability="continuous" initial="exact">
    <Real start="1"/>
  </ScalarVariable>
  <ScalarVariable name="der(h)" valueReference="1" description="velocity of ball"
                  causality="local" variability="continuous" initial="calculated">
    <Real />
</ModelVariables>

From the above XML, the first list element gets serialized to a RealVariable because it contains the (non-empty) Real tag. The second case breaks the application because the tag is empty -> the field that decides the object type is set to null!

@cowtowncoder
Copy link
Member

cowtowncoder commented May 4, 2018

Jackson 2.9 added one new feature for @JsonSetter, for null handling:

https://medium.com/@cowtowncoder/jackson-2-9-features-b2a19029e9ff

(see "Null replacement/error/skipping (on deserialization)")

which is RFE FasterXML/jackson-databind#1402

wherein annotating property as:

@JsonSetter(nulls=Nulls.AS_EMPTY)

should result in null being coerced into "empty" value of the type.
For POJOs this should be newly constructed instance (and if so, requires no-arg constructor, NOT any other kind of creator).

Problem otherwise is that due to separate of streaming parser, databinding, lower level must decide in how to expose value, and as things are there is not enough information to be able to expose it either as null OR as START_OBJECT/END_OBJECT pair (since parser has no knowledge of what expected target at high level might be).

I will add tests in XML module to ensure that this approach works (or, if not, that it needs to be fixed).

@cowtowncoder
Copy link
Member

One other thing: it is also possible to configure null-handling for type via mapper.configOverrides(type).setSetterInfo(MyClass.class), or even as global default:

mapper.setDefaultSetterInfo(...)

(examples can be found from test cases under src/test/java/com/fasterxml/jackson/databind/deser/filter/NullConversionsGenericTest.java

I hope this helps.

@markaren
Copy link

markaren commented May 4, 2018

@JsonSetter(nulls=Nulls.AS_EMPTY)

did the trick for me. Now I can replace JAXB with Jackson :)

@cowtowncoder
Copy link
Member

@markaren yay!

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

No branches or pull requests

3 participants