1

I had an issue with injecting a custom ObjectMapper into Spring Kafka serializer which I have resolved with this answer, LocalDateTime are getting serialized with right pattern.

@Configuration
public class KafkaCustomizer implements DefaultKafkaProducerFactoryCustomizer {

    @Bean
    public ObjectMapper objectMapper() {
        var mapper = new ObjectMapper();
        var module = new JavaTimeModule();
        var serializer = new LocalDateTimeSerializer(
                DateTimeFormatter.ofPattern(DateConstants.DATETIME_FORMAT_PATTERN));
        module.addSerializer(LocalDateTime.class, serializer);
        mapper.registerModule(module);
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        return mapper;
    }

    @Override
    public void customize(DefaultKafkaProducerFactory<?, ?> producerFactory) {
        producerFactory.setValueSerializer(new JsonSerializer<>(objectMapper()));
    }

}

But now I face another problem, the spring.kafka.producer.properties.spring.json.type.mapping property is being ignored.

The __TypeId__ header of my record is set with FQCN and not with the token I have put in spring.json.type.mapping property : foo > com.foo.package.Foo

When I did debbug it seems that the configure method of org.springframework.kafka.support.serializer.JsonSerializer class is not being invoked :

@Override
public void configure(Map<String, ?> configs, boolean isKey) {
    ...
    if (configs.containsKey(TYPE_MAPPINGS) && !this.typeMapperExplicitlySet
            && this.typeMapper instanceof AbstractJavaTypeMapper) {
        ((AbstractJavaTypeMapper) this.typeMapper)
                .setIdClassMapping(createMappings((String) configs.get(TYPE_MAPPINGS)));
    }
}

But when I disable the customization

    @Override
    public void customize(DefaultKafkaProducerFactory<?, ?> producerFactory) {
        // producerFactory.setValueSerializer(new JsonSerializer<>(objectMapper()));
    }

Then the __TypeId__ header is set with right token But as expected I loose the date format with my custom ObjectMapper

So how to handle this whole situation ?

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Hayi
  • 6,972
  • 26
  • 80
  • 139

1 Answers1

1

If you do your own new JsonSerializer<>, you are on your own to feed it with appropriate producer configs. When the instance of serialized is not controlled by Kafka Client, that configure() is not called.

I would say it is possible to do it like this in your case:

public void customize(DefaultKafkaProducerFactory<?, ?> producerFactory) {
    JsonSerializer<Object> jsonSerializer = new JsonSerializer<>(objectMapper());
    jsonSerializer.configure(producerFactory.getConfigurationProperties(), false);
    producerFactory.setValueSerializer(jsonSerializer);
}

There is some info in docs: https://docs.spring.io/spring-kafka/docs/current/reference/html/#tip-json, but probably we need to extend it for the programmatic configuration case...

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • with this line `producerFactory.setValueSerializer(jsonSerializer);` I got `error: incompatible types: JsonSerializer cannot be converted to Serializer` – Hayi Jul 21 '21 at 15:52
  • `Required type: Serializer Provided: JsonSerializer ` – Hayi Jul 21 '21 at 15:52
  • That is just general Java generics coercion issue: `DefaultKafkaProducerFactory, Object> producerFactory` or `producerFactory.setValueSerializer((JsonSerializer) jsonSerializer);`. Or an explicit type you expect to produce via that `producerFactory`. – Artem Bilan Jul 21 '21 at 16:08
  • it has worked just with `producerFactory.setValueSerializer((JsonSerializer) jsonSerializer);` – Hayi Jul 21 '21 at 16:37
  • am i doing the right approach to serialize my `LocalDateTime` ? because i notice that feeding my own `JsonSerializer` has a lot of impact – Hayi Jul 21 '21 at 16:38
  • Well, technically it is a different story, but it doesn't look like you need that customization at all. The default `ObjectMapper` in the `JsonSerializer` registers well-known modules including a `JavaTimeModule`. What makes you to not rely on a default one though? – Artem Bilan Jul 21 '21 at 16:42
  • i explain why in this question https://stackoverflow.com/questions/68313583/issue-with-customizing-object-mapper/68317609, is there another approach ? – Hayi Jul 21 '21 at 16:51
  • Yeah... I see. Looks like Jackson doesn't provide for a hook to inject some custom formatter via properties or so. Therefore your approach with a custom module is OK. – Artem Bilan Jul 21 '21 at 16:57
  • 1
    Thanks for your help, I think it would be convenient if there can be a way to invoke the `configure()` method implicitly under the hood when using a custom `ObjectMapper` – Hayi Jul 21 '21 at 17:56
  • 1
    Here is an issue to re-think the solution according your concerns: https://github.com/spring-projects/spring-kafka/issues/1879 – Artem Bilan Jul 21 '21 at 18:29