Is there any way to set the return value of a method to Encoder<Cat>
when Cat.class
was passed as an argument?
I'm exploring reworking an API to be as generic as possible. I have a series of interfaces for data encoders but this api is for multiple applications. I want the application author to be able to define the "available encoders" so that their API reflects what's available accurately.
For example, if app developer Bob wants to offer an encoder for the type Cat
he might do:
encoderRegistry.register(Cat.class, new CatEncoder());
Then, someone using his apps' API could get the encoder for a specific type and would see the appropriate type-based arguments:
encoderRegistry.get(Cat.class).encode(Cat cat);
I'm trying to avoid Object
types because I want the API to be as user-friendly as possible and if the IDE pops up a method accepting Cat
, there's no question.
So far the only way I've been able to get close is by adding a type to the get
method:
encoderRegistry.<IEncoder<Cat>>get(Cat.class)
This properly informs the return value for get
so that I can use encode(Cat cat)
but it's verbose, and there's no stopping me from using encoderRegistry.<IEncoder<Cat>>get(Dog.class)
CodePudding user response:
You can set up the API to accept the right types, but internally you will need to type cast. Java's type system is not strong enough to represent heterogenous type maps, so you will need to depend on the compiler to enforce safety at the API edges. Example:
interface Encoder<T> {
String encode(T value);
}
static class EncoderRegistry {
Map<Class, Encoder> encoders = new HashMap<>();
<T> void register(Class<T> clz, Encoder<? super T> encoder) {
encoders.put(clz, encoder);
};
<T> Encoder<T> get(Class<T> clz) {
return (Encoder<T>) (Encoder) encoders.get(clz);
}
}
public static void run() {
class Cat {}
class CatEncoder implements Encoder<Cat> {
@Override
public String encode(Cat value) {
return value.toString();
}
}
var registry = new EncoderRegistry();
registry.register(Cat.class, new CatEncoder());
registry.get(Cat.class).encode(new Cat());
}