electrotype
electrotype

Reputation: 8796

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;
}

Upvotes: 4

Views: 315

Answers (2)

EpicPandaForce
EpicPandaForce

Reputation: 81539

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>.

Upvotes: 2

mixel
mixel

Reputation: 25846

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;
}

Upvotes: 3

Related Questions