FasterXML / jackson-databind

General data-binding package for Jackson (2.x): works on streaming API (core) implementation(s)
Apache License 2.0
3.52k stars 1.38k forks source link

JsonInclude.Include.NON_EMPTY also excluding NULL map values #2136

Open anshchauhan opened 6 years ago

anshchauhan commented 6 years ago

Hi,

I just upgraded from Jackson 2.5.X to 2.9.X. I'm using Spring Boot and my global bean had: getObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_EMPTY).

I have a custom serializer in a class with a member map Map<String,Object> where I was writing null values and they were being serialized. But after the upgrade, NULL values are getting discarded.

I tried using getObjectMapper().setDefaultPropertyInclusion( JsonInclude.Value.construct(JsonInclude.Include.NON_EMPTY, JsonInclude.Include.ALWAYS));

but this also includes empty lists and maps which I don't want. Class level or member level annotations are not working as well since I've custom serializer. This has become a blocker for me. Please suggest how can I achieve the old NON_EMPTY behavior?

https://stackoverflow.com/questions/52273088/allow-null-map-values-in-a-custom-jsonserializer/52273674?noredirect=1#comment91494848_52273674

cowtowncoder commented 6 years ago

I think the behavior you are seeing now is the intended behavior, unfortunately.

But have you tried per-class config overrides? Something like:

mapper.configOverrides(Map.class)
      .setFormat(JsonInclude.Include.NON_EMPTY, JsonInclude.Include.ALWAYS));

which should then only apply to Maps and not other types.

anshchauhan commented 6 years ago

Hi, thank you for your reply. At the moment, I've done a workaround like: mapper.registerModule(getMapWithNullValuesModule())

private Module getMapWithNullValuesModule() {
    SimpleModule mapWithNullValueModule = new SimpleModule("MapWithNullValues");
    mapWithNullValueModule.setSerializerModifier(new BeanSerializerModifier() {
      @Override
      public JsonSerializer<?> modifyMapSerializer(SerializationConfig config, MapType valueType,
        BeanDescription beanDesc, JsonSerializer<?> serializer) {
        if (serializer instanceof MapSerializer) {
          MapSerializer mapSerializer = (MapSerializer) serializer;
          return mapSerializer.withContentInclusion(null, DONT_SUPPRESS_NULLS);
        } else {
          LOG.warn("{} not an instance of {}", serializer, MapSerializer.class.getName());
          return serializer;
        }
      }
    });
    return mapWithNullValueModule;
  }

Apparently, it's doing the job, but your way looks much cleaner. Will it include empty maps? I don't want that. If not, I'll replace my code with yours.

cowtowncoder commented 6 years ago

@anshchauhan I chose combination of "always include all Map values, but do not serialize empty Maps", so it will not include empty Maps in output.

EarthCitizen commented 6 years ago

I would consider this a bug because it breaks the contract of semantic versioning:

https://semver.org/

MAJOR version when you make incompatible API changes, MINOR version when you add functionality in a backwards-compatible manner, and PATCH version when you make backwards-compatible bug fixes.

Per semantic versioning 2.9.x needs to be backwards compatible with all previous 2.x versions. If this project is not going to follow the semantic versioning contract, then this should be stated boldly in the main README. Otherwise, there is an implied contract followed which is being broken.