Re: Yet another generics question: Needs unchecked conversion to conform to ...
Tim, thank you very much for the feedback.
You have not and in general cannot verify that the object is of that
type. The signature is wrong. For instance, in your example ServiceX is
not a Service<ServiceComponent> but it is a Service<? extends
ServiceComponent>.
But since ServiceComponent is an abstract class or interface, in
practice, is'nt Service<? extends ServiceComponent> a "subset" of
Service<ServiceComponent> ? Therefore, is'nt the cast from the later
into the former safe?
Generally a good move when using reflection and generics, is to add a
layer of indirection, so you don't have to mix the two.
On the other hand, it seems more work for the service implementation
(ServiceX) who would have to provide two interfaces, and matching
implementation classes. I may be missing a point though.
I updated my test class to follow some of your recommandation. this is
whet I end up with.
import java.lang.reflect.Constructor;
public class Generics2 {
static interface ServiceProvider {
<T extends ServiceComponent> Service<T> find(
String className)
throws Exception;
}
static class ServiceProviderWithReflection implements ServiceProvider
{
@SuppressWarnings("unchecked")
public <T extends ServiceComponent> Service<T> find(
String className) throws Exception {
Class<?> bc = Class.forName(className);
Class<? extends Service> bfc = bc.asSubclass(Service.class);
Constructor<? extends Service> cstr =
bfc.getConstructor(new Class[]{});
Service<?> ret = cstr.newInstance(new Object[]{});
// It seems we will have to live with this warning
return (Service<T>)ret;
}
}
static public interface ServiceComponent {
}
static public interface Service<T extends ServiceComponent> {
T createServiceComponent();
void doSomethingWith(T component);
}
static class ServiceComponentX implements ServiceComponent {
}
static public class ServiceX implements Service<ServiceComponentX> {
public ServiceComponentX createServiceComponent() {
return new ServiceComponentX();
}
public void doSomethingWith(ServiceComponentX component) {
}
}
public static void main(String[] args) throws Exception {
// Use the reflection finder. We may also have chosen to
// use, say, an OSGi-based finder that locates the service
// using the OSGi bundle context.
ServiceProvider finder = new ServiceProviderWithReflection();
// Locate the service identified by the service id "ServiceX".
// In this example, it happens to be the class name but in real
// life, it is not the class name, but an ID from which the finder
// implementation uses to locate the real service.
Service<ServiceComponent> service =
finder.find(Generics2.ServiceX.class.getName());
ServiceComponent component = service.createServiceComponent();
// Setup the component state here
// ...
// once it is setup,
service.doSomethingWith(component);
}
}
--
Michel T.