• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Paul Clapham
  • Ron McLeod
  • Jeanne Boyarsky
  • Tim Cooke
Sheriffs:
  • Bear Bibeault
  • Henry Wong
  • Devaka Cooray
Saloon Keepers:
  • salvin francis
  • Tim Moores
  • Tim Holloway
  • Stephan van Hulst
  • Frits Walraven
Bartenders:
  • Jj Roberts
  • Carey Brown
  • Scott Selikoff

Java Generic in run time

 
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi All,

I had one query regarding some piece of code I worked and got confused with Java Generic behaviour. I asked query in https://stackoverflow.com/questions/65607322/java-how-to-in-force-generic-type and I got the response that how it could have prevented.
I have another query which is not answered and that's why asking here.
Link of code sample - https://github.com/jitendraVishnoi/kafka

// Pencil does not implement KafkaRecord
ConsumerRecords<String, KafkaRecord> records = consumer.poll(Duration.ofMillis(getTimeout()));// consumer.poll will return ConsumerRecords<String,Pencil>

Could you please help me understand how above line running without issue.

 
Saloon Keeper
Posts: 12728
277
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

jitendra vishnoi wrote:consumer.poll will return ConsumerRecords<String,Pencil>


No it won't. consumer is a Consumer<String, KafkaRecord>, so consumer.poll() will return ConsumerRecords<String, KafkaRecord>.

Whether at runtime it actually does what you want it to do is a different matter, not related to generics.
 
jitendra vishnoi
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Stephan,

I am sending Pencil object form Kafka producer to Kafka as message and it sending those to consumer and its picking those message at line 27 in https://github.com/jitendraVishnoi/kafka/blob/master/src/main/java/CustomExecutor.java its able to print those Pencil messages. If there is method say void sellPencil(Pencil pencil), I need to just cast it like (Pencil) bean.value() and pass it. Everything works fine.
I understand I am missing some basic concepts. I got it how its not giving any error at compile time but if its not generic related how its working, Could you please help me understand.
Appreciate all your support.
 
Stephan van Hulst
Saloon Keeper
Posts: 12728
277
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'm not familiar with Kafka, and I see that Apache's Javadoc is once again as terrible as it usually is.

I don't know. If I were to guess it's that your PencilDeserializer isn't used at all, and Kafka just deserializes the JSON to a non-specific bean.

Try debugging your deserializer to see if it's called at all.
 
jitendra vishnoi
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes it has been called and return Pencil object.
Also could you please share your thoughts why you dont think its not Generic Erasure thing.

I was suspecting its possible as ConsumerRecords<String, KafkaRecord> lost its type(Generic Erasure) at run time and all works.
 
Stephan van Hulst
Saloon Keeper
Posts: 12728
277
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The fact that it works makes me even more wary of Apache Kafka.

Each bean that you iterate over should be a Consumer<String, KafkaRecord>, meaning that bean.value() is a KafkaRecord, and therefore can't be a Pencil.

You are likely correct that it works because of type erasure, but that also means that Apache Kafka doesn't take type safety seriously. Its use of generics only serves to give a false sense of security.

What happens when you change your code into this?
 
jitendra vishnoi
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Stephan,

I added below method(GIT code also updated) and pencilRecords.forEach(bean -> playWithRecord(bean.value()));


I tried with private void playWithRecord(KafkaRecord record) but its failing in runtime while receiving message -


Looks to me only reason why Consumer<String, KafkaRecord> pencilConsumer = getPencilConsumer(); is successful if type is erased as any futher line which trying to consider record as KafkaRecord is ClassCastException.
Let me know about your thoughts or if there is way to check what is code at runtime.
 
Stephan van Hulst
Saloon Keeper
Posts: 12728
277
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, it works because of type erasure and because Kafka allows you to set a deserializer without connecting the type of the deserializer to the type of the records you get from the consumer. Bad design.

I would just continue with whatever you are doing. Just stop casting object references. If you need references of type Pencil, create a Consumer<String, Pencil> and not a Consumer<String, KafkaRecord>. If you don't, and your Pencil really does represent a Kafka record, then why not let it extend KafkaRecord.
 
jitendra vishnoi
Greenhorn
Posts: 18
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


Just stop casting object references. If you need references of type Pencil, create a Consumer<String, Pencil> and not a Consumer<String, KafkaRecord>.



Actually its like we are getting different type of objects and that's why wanted to keep common part in some super class. Its like everyone will override their playWithRecord in thier own way and we dont have write duplicate code.


If you don't, and your Pencil really does represent a Kafka record, then why not let it extend KafkaRecord.



Yes Pencil is a Kafka record and it was accedently missed but the problem is its working fine.
If I have to ask someone to update the code I am not sure about the logic I would give as its working now and after the change it will keep working.
 
reply
    Bookmark Topic Watch Topic
  • New Topic