Recursively restricted casting

I defined a Java interface to represent the ability to copy an object (no, I do not want to use Cloneable , but thanks for the suggestion ;-). It is common:

 public interface Copiable<T> { T copy(); } 

An object will only make copies of its type:

 public class Foo implements Copiable<Foo> { Foo copy() { return new Foo(); } } 

Now I am reading Class<?> Objects from a non-shared API (Hibernate metadata if anyone is interested), and if they are Copiable , I want to register them using one of my components. The register method has the following signature:

 <T extends Copiable<T>> register(Class<T> clazz); 

My problem is, how do I pass a class before passing it to a method? What I am doing now is:

 Class<?> candidateClass = ... if (Copiable.class.isAssignableFrom(candidateClass)) { register(candidateClass.asSubclass(Copiable.class)); } 

This does what I want, but with a compiler warning. And I don’t think I can express a recursive binding at runtime.

Is there any way to redo my code so that it is visible?

thanks

+4
source share
3 answers

Run-time failure <? extends Copiable<?> <? extends Copiable<?> (in a register() call) because there is no way to declare the first ? and second ? is the same (unknown) thing.

Calling asSubclass() gives a warning about the compiler for the same reason - because the generics were erased, at run time there is no way to prove that Copiable is Copiable<AnythingInParticular> . You proved that it is a Copiable , but you did not prove that it is a Copiable<Itself> .

I think the best thing you can hope is to localize warnings for one messy method and add @SuppressWarnings("unchecked") and some comments.

Do you know that this will work at runtime? It seems to me that the compiler is telling the truth here. Are the classes that you get from Hibernate actually extend Copiable , or do the method declarations just follow that correspond to the Copiable interface? If this is the latter, then - Java is a strongly typed language - your isAssignableFrom() will always return false anyway.

0
source

It is not possible to drop a non-shared API for a shared one and not receive a warning. You can use the @SuppressWarnings("unchecked") annotation to suppress it.
Class<?> also useless in this case - instead of it, you can use a non-common Class candidateClass .

0
source

Perhaps you could somehow apply a super-type marker . Why do you need to limit your case ()? I think the problem is that you are using Class.forName and it is taking too long to complete.

0
source

All Articles