0
votes

I've been building Kafka Producer Service. I used ? wildcard type of generics for key value so it could either be an Integer String etc.

@Slf4j
public abstract class ProducerService<T> {

    protected KafkaClientConfigProperties properties;

    @Autowired
    protected KafkaTemplate<?, T> kafkaTemplate;

    public void send(T value, Iterable<Header> headers) {
        ProducerRecord<?, T> record = new ProducerRecord<>(properties.getTopic(), null, null, null, value, headers);
        this.kafkaTemplate.send(record);
    }

However upon calling the send method with an argument of ProducerRecord i am having an error of

The method send(ProducerRecord<capture#2-of ?,T>) in the type KafkaTemplate<capture#2-of ?,T> is not applicable for the arguments (ProducerRecord<capture#3-of ?,T>)

I also tried

ProducerRecord<String, T> record = new ProducerRecord<>(properties.getTopic(), null, null, null, value, headers);

And having an error of

ProducerRecord<String, T> record = new ProducerRecord<>(properties.getTopic(), null, null, null, value, headers);

Can someone please help me understand what's wrong with the code? Thanks

1
Can you share the code where you actually extend and then use the abstract ProducerService?akortex

1 Answers

0
votes

There are various things that could be changed/fixed here. First of all answering the question you asked. The reason why you are getting the error in question, is due to the fact that the ProducerRecord you are creating takes in a null key variable.

Since this class is generic, expecting K as the type of the key and a V as the type of the value, passing in null there means that there is no way for the type of the K to be inferred, this is something that is also augmented from the fact that you are ? as the key type which is also incorrect.

There are various ways to mitigate this.

  1. If you are really interested in sending over headers then your class should also accept a type for the key (and not a wildcard). Consider the following example:
public abstract class ProducerService<K, T> {

    @Autowired
    protected KafkaTemplate<K, T> template;

    public void send(T value, Iterable<Header> headers) {
    ProducerRecord<K, T> record = new ProducerRecord<>("topic", null, null, null, value, headers);
    template.send(record);
    }

}
  1. If you are not interested in sending over custom headers, the simply calling KafkaTemplate#send and passing in the the object to be send should suffice:
public abstract class ProducerService<T> {

    @Autowired
    protected KafkaTemplate<String, T> template;

    public void send(T value, Iterable<Header> headers) {
    template.send("topic", value);
    }

}

As you can see from both the examples up top, typing to the correct key type and not using the wildcard should work fine for you. Finally, one more recommendation should be to avoid making the class generic.

There is no need to have multiple implementations of a producer service for specific object types. You could simply try and generalize your approach in order to be able to handle any kind of values.