Java recursive generics class wildcard matching - java

Having these generic interface and class:
interface TestIntf<T extends TestIntf<T>>
{
void test(T param);
}
class TestImpl<T extends TestIntf<T>> implements TestIntf<T>
{
#Override
public void test(T param) { System.out.println(param); }
}
This fails:
Class<? extends TestIntf<?>> clz = TestImpl.class;
(Type mismatch: cannot convert from Class<TestImpl> to Class<? extends TestIntf<?>>)
Why? How to properly provide a reference to TestImpl class to match Class<? extends TestIntf<?>>?

You can't. Use an unsafe cast.
Class<? extends TestIntf<?>> clz = (Class<? extends TestIntf<?>>) TestImpl.class;
or don't use the inner generics:
Class<? extends TestIntf> clz = TestImpl.class;
Update: When it regards annotations, there is nothing you can do - the annotation has to be changed. You cannot have a class literal represent a generic type.

Related

Why different result outputs between the generic type and wildcard type

I know what is the difference between the generic type and the wildcard type,
but in this situation I cannot use the same way again to understand.
For short, To compare both Interfaces below
public interface RequestParser {
<T extends Entity> Message<T> parseRequest(String json);
}
public interface RequestParser {
Message<? extends Entity> parseRequest(String json);
}
Only the first one can compile the below codes: (User extends Entity)
Message<User> message = requestParser.parseRequest(json);
The one uses wildcard ? cannot succeed.
So what exactly is the difference between them in this situation ...?
It's because Message<User> is not a subclass of Message<? extends Entity>.
The issue will be more evident when trying to implement RequestParser.
This will fail without a cast, as T is not necessarily AnotherUser:
public class AnotherUser extends Entity {}
public class RequestParserImpl implements RequestParser {
<T extends Entity> Message<T> parseRequest(String json) {
return new Message<AnotherUser>();
}
}
Whereas this will compile:
public class RequestParserImpl implements RequestParser {
Message<? extends Entity> parseRequest(String json) {
return new Message<AnotherUser>();
}
}

Java - Getting a more specific type than "Class<?>" for a parameterized generic class

I have a base interface that is parameterized using a type R extending the same base interface :
public interface IWidget<R extends IWidget<R>> {}
Then another interface is parameterized the same way :
public interface IWidgetManager<R extends IWidget<R>> {}
Finally, a class implements the second interface. This class will receive the IWidget implementation class when it will be declared :
public class MyWidgetManager<R extends IWidget<R>> implements IWidgetManager<R> {}
My question :
What is the more specific type that we can use to specify MyWidgetManager?
Class<?> works, of course :
public Class<?> ok() {
return MyWidgetManager.class;
}
But it is very generic and I'd like something more specific...
Those attempts don't compile:
public Class<? extends IWidgetManager<?>> fails() {
return MyWidgetManager.class;
}
==> Type mismatch: cannot convert from Class<MyWidgetManager> to Class<? extends IWidgetManager<?>>
public <R extends IWidget<?>> Class<? extends IWidgetManager<R>> fails() {
return MyWidgetManager.class;
}
==> Type mismatch: cannot convert from Class<MyWidgetManager> to Class<? extends IWidgetManager<R>>
public <R extends IWidget<R>> Class<? extends IWidgetManager<R>> fails() {
return MyWidgetManager.class;
}
==> Type mismatch: cannot convert from Class<MyWidgetManager> to Class<? extends IWidgetManager<R>>
public Class<? extends IWidgetManager<? extends IWidget<?>>> fails() {
return MyWidgetManager.class;
}
==> Type mismatch: cannot convert from Class<MyWidgetManager> to Class<? extends IWidgetManager<? extends IWidget<?>>>
Is there any way I can get a type more specific than Class<?> for MyWidgetManager.class?
UPDATE :
I changed the name of my interfaces. The final class is not a Widget itself, which wasn't clear in my original question... Sorry for the confusion.
UPDATE 2 :
Things are way easier when using concrete types, indeed.
This is really specific to my current situation, but I think I'll fix my "problem" by transforming MyWidgetManager<R extends IWidget<R>> implements IWidgetManager<R> into a WidgetManagerBase that doesn't implement anything. Then provide a default implementation with a concrete Widget class. Finally, the get method could be overriden easily (which is my main goal from the start, by the way!). So :
public interface IWidget<R extends IWidget<?>> {}
public interface IWidgetManager<R extends IWidget<R>> {}
public class WidgetManagerBase {}
// Default implementation
public class WidgetA implements IWidget<WidgetA> {}
public class AWidgetManager extends WidgetManagerBase implements IWidgetManager<WidgetA> {}
// default get method
public Class<? extends IWidgetManager<?>> getWidgetManagerClass() {
return AWidgetManager.class;
}
// The default get method then can be overriden with :
public class WidgetB implements IWidget<WidgetB> {}
public class BWidgetManager extends WidgetManagerBase implements IWidgetManager<WidgetB> {}
#Override
public Class<? extends IWidgetManager<?>> getWidgetManagerClass() {
return BWidgetManager.class;
}
Because of Java Type Erasure the most specific match for MyWidget.class is Class<? extends IWidget>:
public Class<? extends IWidget> test() {
return MyWidget.class;
}
If you want to be even more specific than you should extend MyWidget with concrete type parameters:
public class ConcreteBaseWidget implements IBaseWidget<ConcreteBaseWidget> {
}
public class ConcreteWidget extends MyWidget<ConcreteBaseWidget> {
}
And then all these methods will work:
public Class<? extends IWidget<? extends IBaseWidget<? extends IBaseWidget<?>>>> test1() {
return ConcreteWidget.class;
}
public Class<? extends IWidget<? extends IBaseWidget<ConcreteBaseWidget>>> test2() {
return ConcreteWidget.class;
}
public Class<? extends IWidget<? extends ConcreteBaseWidget>> test3() {
return ConcreteWidget.class;
}
I really think you're just looking for
public interface IBaseWidget<R extends IBaseWidget<R>> {}
and
public interface IWidget<R extends IWidget<R>> extends IBaseWidget<R> {} //not sure about this one.
and
public class MyWidget implements IWidget<MyWidget> {}
That way you can see MyWidget.class as Class<R>.
Is this what you are looking for, or do I misinterpret your intentions?
EDIT:
In that case,
public interface IWidgetManager<R extends IWidget<R>> {}
public class MyWidgetManager<R extends IWidget<R>> implements IWidgetManager<R> {}
could be replaced with
public interface IWidgetManager<R extends IWidget<R>, WM extends IWidgetManager<R, WM>> {}
public class MyWidgetManager<R extends IWidget<R>> implements IWidgetManager<R, MyWidgetManager> {}
because then you will be able to access MyWidgetManager.class as Class<WM>.

how can a Class.forName returns a Class<? extends MyAbstractClass>?

Let's say I have an abstract class MyAbstractClass:
public abstract class MyAbstractClass {
public abstract SomeObject doSomething();
}
and I have some concrete implementations of this class, MyConcreteClass1 and MyConcreteClass2.
Let's say I read the class name of any of the concrete implementations from a file and then I want to create the object:
String concreteImplementationName = getConcreteImplementationName();
Class<?> klass = Class.forName(concreteImplementationName);
I get the Class and then using reflection I can instantiate an object.
Now, in this case I know that the concreteImplementationName will only contain the name of one of the implementations of MyAbstractClass. How can I convert klass to a Class<? extends MyAbstractClass>?
Class<? extends MyAbstractClass> x = // what do I need to do here?
You can use Class.asSubclass to do this. It works similarly to a cast, but for a Class object.
c.asSubclass(T.class) will check that c is actually a subclass of T, and if so it will return a Class<? extends T>. Otherwise it will throw a ClassCastException.
So you want this:
Class<? extends MyAbstractClass> x = klass.asSubclass(MyAbstractClass.class);
Just add a cast. You can do this safely because you know it's a subtype of MyAbstractClass
public class Example {
public static void main(String[] args) throws Exception {
String concreteImplementationName = "com.example.Implementation";
Class<? extends MyAbstractClass> x = (Class<? extends MyAbstractClass>) Class.forName(concreteImplementationName); // what do i need to do
}
}
class Implementation extends MyAbstractClass {
}
class MyAbstractClass {
}

Generics with Wildcards (Map<? extends A, List<? extends B>>)

Consider the following code:
public interface A {};
public class AImpl implements A {};
public interface B {};
public class BImpl implements B {};
public interface Service{
Map<? extends A, List<? extends B>> get();
}
Why does the following implementation of Service not compile?
public class ServiceImpl implements Service {
public Map<AImpl, List<BImpl>> get() {
return null;
}
}
Compiler error:
The return type is incompatible with Service.get()
But the following code compile:
public interface Service{
List<? extents B> get();
}
public class ServiceImpl implements Service{
public List<BImpl> get(){
return null;
}
}
Because <? extends BaseType> means "some unspecified sub-type BaseType", and class Sub extends BaseType, while sub-type of BaseType, is not it. Read Java Generics FAQ, in particular starting from Wildcard Capture section, for more details.
You should generify your code properly:
public interface Service<K extends A, V extends B> {
Map<K, List<V>> get();
}
public class ServiceImpl implements Service<AImpl, BImpl> {
#Override
public Map<AImpl, List<BImpl>> get() {
return null;
}
}
The return type of the Service#get() method is specified as
Map<? extends A, List<? extends B>> get();
And you are trying to return a
Map<AImpl, List<BImpl>>
You can use covariant return types. And it seems like you thought this would be the case here. But the problem is that this covariance does not apply to the generic type parameters. Although List<BImpl> is a subtype of List<? extends B>, this does not mean that Map<AImpl, List<BImpl>> is a subtype of Map<? extends A, List<? extends B>>.
A structurally similar but simpler case is that List<Integer> is not a subtype of List<Number>.
You could change the return type in the Service interface to
Map<? extends A, ? extends List<? extends B>> get();
to make it work.
ServiceImpl cannot be an interface because your Implementation cannot be in an interface; Change it to a base base class and try it.
What do you write?
Map<? extents A, List<? extents B> get();
java doesn't know anything about extents
At least use extends

Why nested wildcard capture is not possible?

I'm struggling to capture a wildcard when it is "nested in another wildcard".
Is it possible?
The code:
public class ConvolutedGenerics {
// listClass is a class implementing a List of some Serializable type
public void doSomethingWithListOfSerializables(
Class<? extends List<? extends Serializable>> listClass) {
// Capture '? extends Serializable' as 'T extends Serializable'
// The line does not compile with javac 7
captureTheWildcard(listClass); // <------ zonk here
}
// listClass is a class implementing a List of some Serializable type
private <T extends Serializable>
void captureTheWildcard(
Class<? extends List</* ? extends */T>> listClass) {
// Do something
}
}
compiled with javac 7 produces:
ConvolutedGenerics.java:18: error: method captureTheWildcard in class ConvolutedGenerics cannot be applied to given types;
captureTheWildcard(listClass);
^
required: Class<? extends List<T>>
found: Class<CAP#1>
reason: no instance(s) of type variable(s) T exist so that argument type Class<CAP#1> conforms to formal parameter type Class<? extends List<T>>
where T is a type-variable:
T extends Serializable declared in method <T>captureTheWildcard(Class<? extends List<T>>)
where CAP#1 is a fresh type-variable:
CAP#1 extends List<? extends Serializable> from capture of ? extends List<? extends Serializable>
1 error
Besides many more simpler cases I've found
Incompatible generic wildcard captures
Using Java wildcards
but I could not infer an answer for my problem from those.
It is not possible, as you probably already know.
Let me illustrate with a counter-example:
List<Integer> foo = Arrays.asList(1,2,3);
List<String> bar = Arrays.asList("hi","mom");
List<List<? extends Serializable>> baz = Arrays.asList(foo, bar);
doSomethingWithListOfSerializables(baz);
public void doSomethingWithListOfSerializables(
List<? extends List<? extends Serializable>> listList) {
captureTheWildcard(listList);
}
private <T extends Serializable>
void captureTheWildcard(
List<? extends List<T>> listList) {
// Do something
}
What should T be?
The problem with your code is that you're trying to call captureTheWildcard passing different typed parameter then defined here:
private <T extends Serializable> void captureTheWildcard(Class<? extends List<T>> listClass)
You should explicitly say in your method definition that parameter passed is actually of type of Class<? extends List<? extends Serializable>>or modify the type of listClass like this:
import java.util.List;
import java.io.Serializable;
public class ConvolutedGenerics {
// listClass is a class implementing a List of some Serializable type
public <T extends Serializable> void doSomethingWithListOfSerializables(
Class<? extends List<T>> listClass) {
// Capture '? extends Serializable' as 'T extends Serializable'
// The line does not compile with javac 7
captureTheWildcard(listClass); // <------ zonk here
}
// listClass is a class implementing a List of some Serializable type
private <T extends Serializable> void captureTheWildcard(Class<? extends List<T>> listClass) {
// Do something
}
}
Compiles well with javac 1.7.0_25

Categories