Win a copy of Design for the Mind this week in the Design forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

How to call a generic method when I only have an Object

 
Jesper de Jong
Java Cowboy
Saloon Keeper
Posts: 15214
36
Android IntelliJ IDE Java Scala Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

I have an interface that specifies an encoder in a generic way. It specifies a method to convert an object of type T, resulting in a byte array:

I have several implementations of this, for example:

Now I have a heterogenous list of values (in a List<Object>), and I want to encode each of these using the appropriate encoder. However, the encode method of each encoder can only be called with the specific type that it accepts - it can't be called with a plain Object:

How can I call the encode method of the encoder?

I want to keep the encoders type-safe (i.e. keep the generics in the Encoder interface).

It can be done with reflection, but is there also another way without using reflection?
 
Matthew Brown
Bartender
Posts: 4566
8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm not 100% sure this would work, but it's the first thing that springs to mind (and it compiles!): try wrapping the Encoder in a generic "untyped" encoder. Within that wrapper you have access to the generic type, so you can cast the object. Like this:Then you can use it like this:
Any use?
 
Rob Spoor
Sheriff
Pie
Posts: 20511
54
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You're going to need an unsafe cast there somewhere. You can try forcing encoder into an Encoder<Object> reference. The compiler sees it as unsafe, but as long as you guarantee that encoder and value match types then that shouldn't be a problem.

Matthew: nice try, but the extra class is unnecessary. With it I get two warning because you're creating a raw EncoderWrapper instance, then assigning that to the typed wrapper variable. I can get only one warning (unchecked cast) with only one line of code:
 
Matthew Brown
Bartender
Posts: 4566
8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rob Spoor wrote:Matthew: nice try, but the extra class is unnecessary. With it I get two warning because you're creating a raw EncoderWrapper instance, then assigning that to the typed wrapper variable.

Yeah, fair enough. My "theory" (which I felt was not quite right, but I didn't get any warnings so thought I might have got away with it) was that the typed encoder I was passing into the constructor would provide the generic type of the wrapper. But of course that doesn't actually work because the compiler doesn't know what type it is....

Blame the C# I've been learning recently.
 
Hunter McMillen
Ranch Hand
Posts: 492
Firefox Browser Linux VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Couldn't you just use the Object class' getClass() method to determine what type of object you are looking at as you encounter them and declare the Encoders conditionally?

ex:


Hunter

 
Rob Spoor
Sheriff
Pie
Posts: 20511
54
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Getting the Encoder isn't the issue. It's calling the encode method of an Encoder<?> (type unknown; your example shows just why) using Object as argument. Sure, you could put the encoding within the if-statement, but I'm thinking Jesper's Encoder<?> lookup is a bit different than this one (perhaps using a Map?).
 
Hunter McMillen
Ranch Hand
Posts: 492
Firefox Browser Linux VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hmm I see that now, I was so focused on getting the correct encoder I completely missed the issue with the call to encode.

Hunter
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24208
35
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Remember that Java generics are a compile-time construct: they exist only in the mind of the compiler. Any code that has to make a runtime decision about unknown types is going to be forced to include unsafe casts, by definition. Fact of life, unfortunately.
 
Jesper de Jong
Java Cowboy
Saloon Keeper
Posts: 15214
36
Android IntelliJ IDE Java Scala Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rob's solution looks simple, I'll try that.

Ofcourse there has to be an unchecked cast somewhere to do this, so it's not going to be 100% type-safe, but at least I can implement the encoders themselves in a type-safe way - one thing I thought of was leaving the generics out of the interface, and just pass or return Object, but that's not so good, especially since I need to implement a list of different encoders for different Java types.

It's actually the same situation as a question that comes up on the forums here every now and then - why you can't add elements to a List<?>: because the compiler doesn't know what the type "?" is, so it has no way to check that you pass the right type of object.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic