Avoiding cast in generic factory-based MVP framework - java

I was trying to implement a way to decouple View and Presenter in the MVP pattern to provide a framework, which does exactly this, but after a point I got confused.
Background
I have a View interface with a generic type for the connected presenter and vice versa. Those interfaces are to be extended by the implementing developer. The concrete interface is not of interest for this question, but the class definition of those both look like the following:
public interface Presenter<T extends View>
and
public interface View<T extends Presenter>
The idea is that both the View and the Presenter know the opposing interface.
For using this structure, the developer should provide a factory, that instantiates the View he wants to show and the Presenter that is handling this View. He gives both of them to a class called the SuperController. They are associated by the class of the View.
The PresenterFactory interface, which creates the Presenter, has no parameters and returns a Presenter implementation and looks the following:
public interface PresenterFactory<T extends View> {
<S extends Presenter<T>> S create();
}
The ViewFactory interface, which creates the View, creates a View implementation, based on the Presenter and looks the following:
public interface ViewFactory<T extends View, S extends Presenter<T>> {
T create(S presenter);
}
Problem
The problem I am encountering is the following:
I wanted to provide an example with a TestView and a TestPresenter. Those look like this:
public interface TestPresenter extends Presenter<TestView> {...}
public interface TestView extends View<TestPresenter> {...}
Also, a ViewFactory is provided, which looks like this:
class TestViewFactory implements ViewFactory<TestView, TestPresenter> {
#Override
public TestView create(TestPresenter presenter) {
return new TestViewImpl(presenter);
}
}
And this is the TestPresenterFactory:
private class TestPresenterFactory implements PresenterFactory<TestView> {
#Override
public <S extends Presenter<TestView>> S create() {
return new TestPresenterImpl();
}
}
This code cannot be compiled. The problem is the return value of the TestPresenterFactory. Java says, it expects S and not a TestPresenterImpl. Also, casting to TestPresenter will not work. However, casting to S will work. It than can be compiled and also runs successfully, but this is not what I wanted the implementing developer to do.
Why does this problem exist? And why does casting to the concrete interface not work? In my opinion, this should work, because the TestPresenterImpl implements the TestPresenter, which extends Presenter of the generic type TestView yet it is not compilable.
The following does work. If you change the PresenterFactory definition like this:
public interface PresenterFactory<T extends View, S extends Presenter<T>> {
S create();
}
with the example implementation now looking like this:
private class TestPresenterFactory implements PresenterFactory<TestView, TestPresenter> {
#Override
public TestPresenter create() {
return new TestPresenterImpl();
}
}
It can be compiled and run, just like if I cast to S in the above example.
However, this is not what I want. The generic type declaration is redundant. Letting the implementing developer declare the View and the presenter, to only create the Presenter looks awkward. It would be really great if the type could inferred at the method.
Also, I do not want to force the implementing developer to cast to S.
Is there a more elegant way for this?
edit
A question was brought up as a duplicate and I want to distance myself from this question.
The problem that arises from this has nothing to do with Producer Extends Consumer Super. I have two producers (factories) in use. Both of which are producing a class. One depends on another class (the View depends on the Presenter), while the other one is without dependency (the Presenter can be instantiated with a default constructor). All respected interfaces have the T extends XYZ definition, to allow the production of interfaces, which inherit of that interface (either the Presenter or the View).
The real problem here is that the generic within the ViewFactory can be inferred by Java. Both of the generic types are declared within the class definition. Within the PresenterFactory, the method-level generic cannot be inferred by Java. Even though, the generic type is the same as the one in the view factory <S extends Presenter<T>>; at the method, this type cannot be inferred.
The solution is to either cast (which I don't want the using developer to do) or to declare the PresenterType in the class definition (which seems to be redundant. The only thing of interest is, that the view is defined and any Presenter for that view is returned).
My question is what can I do to work around said issues that are a result of the extends clause?

For starters, this will solve the problem:
interface PresenterFactory<T extends View, S extends Presenter<T>> {
S create();
}
class TestPresenterFactory implements PresenterFactory<TestView, TestPresenterImpl> {
#Override
public TestPresenterImpl create() {
return new TestPresenterImpl();
}
}
But I still don't like:
the circular dependency between View and Presenter;
the use of raw types: actually, if you blindly use View<?> and Presenter<?> in their respective interface declarations, then again it won't compile (TestPresenterFactory will fail).
--- edit ---
So how about this to fix the last 2 points, along with your original issue:
interface Presenter<P extends Presenter<P, V>, V extends View<P, V>> {
}
interface View<P extends Presenter<P, V>, V extends View<P, V>> {
}
interface PresenterFactory<P extends Presenter<P, V>, V extends View<P, V>> {
P create();
}
interface ViewFactory<P extends Presenter<P, V>, V extends View<P, V>> {
V create(P presenter);
}
interface TestPresenter extends Presenter<TestPresenter, TestView> {}
class TestPresenterImpl implements TestPresenter {
}
interface TestView extends View<TestPresenter, TestView> {}
class TestViewImpl implements TestView {
public TestViewImpl(Presenter<?, ?> presenter) {
}
}
class TestViewFactory implements ViewFactory<TestPresenter, TestView> {
#Override
public TestView create(TestPresenter presenter) {
return new TestViewImpl(presenter);
}
}
class TestPresenterFactory implements PresenterFactory<TestPresenter, TestView> {
#Override
public TestPresenter create() {
return new TestPresenterImpl();
}
}

Related

Nested Parameterized types in interface

I have following interfaces:
CacheKey interface:
public interface CacheKey<K extends Serializable> extends Serializable {
K get();
}
CacheValue interface:
public interface CacheValue<V extends Serializable> extends Serializable {
V get();
}
Cache interface:
public interface Cache<CacheKey<K extends Serializable>, CacheValue<V extends Serializable>> {
}
Cache interface doesn't compile. Error I get is:
[13,35] > expected
i.e. after CacheKey compiler doesn't like another opening angle bracket:
public interface Cache<CacheKey<
^
Is this not possible in Java?
You're missing a crucial step here : the implementation.
It's usually in the implementation that you want to define what the type of ? extends Serializable will be. You don't need to implement this in the Cache interface.
The interface only needs to know what its generics types will be, not the generics of their child : this is for the implementation.
Take a look at the example here below to understand what I exactly mean by that.
Addition : When your define something like Cache<CacheKey, CacheValue> you're not referring to the classes, but you're creation a generic alias. CacheKey could easily be replaced by Blabla and continue to have the same behaviour. The solution is to use extends to make sure we're talking about the type.
This was also the reason why Cache<CacheKey<...>> did not compile, because CacheKey is not referring to the class but is used as an alias
public interface CacheKey<K extends Serializable> extends Serializable {
K get();
}
public interface CacheValue<V extends Serializable> extends Serializable {
V get();
}
public interface Cache<K extends CacheKey<? extends Serializable>, V extends CacheValue<? extends Serializable>> {
void put(K key, V value);
}
public class CacheImpl implements Cache<CacheKey<String>, CacheValue<String>> {
#Override
public void put(CacheKey<String> key, CacheValue<String> value) {
// do whatever
}
}
Using a wildcard-bounded generic type, as suggested in other answers, isn't a great idea.
If you declare your class like this:
public interface Cache<K extends CacheKey<?>, V extends CacheValue<?>> {
}
then you would never be able to usefully invoke get() on the key or value, because they would only ever return Serializable. And Serializable is a useless class (it's barely different to Object actually inside your code).
Instead, I would simply declare the class like:
public interface Cache<K extends Serializable, V extends Serializable> {
and then declare that the put method takes a CacheKey<K> and a CacheValue<V>:
void put(CacheKey<K> key, CacheValue<V> value);
because, ultimately, all implementations of CacheKey<K> and CacheValue<V> should be indistinguishable.
If you really want to force the CacheKey<K> and CacheValue<V> to be of specific types, you need to add more type variables:
public interface Cache<
K extends Serializable, CK extends CacheKey<K>,
V extends Serializable, CV extends CacheValue<V>> {
void put(CK key, CV value);
}
but this is really quite gross, as you would have to carry around all of these 4 type variables wherever you use a Cache type directly.
Of course, you can specialize the interface to hide some of these type variables:
interface StringKey extends CacheKey<String> {}
interface IntegerValue extends CacheValue<Integer> {}
interface StringIntegerCache extends Cache<String, StringKey, Integer, IntegerValue> {}
and then just use StringIntegerCache. The usefulness of doing so depends on your application.

Generics - Inheriting class modifies a Generic Type and causes a compiler error

I have the following abstract class:
public abstract class PresenterWithBreadCrumb<V extends View> extends PresenterWidget<V> {
...
What I want to do is extend this class and modify the type V. There is a method that I need in addition to what is provided by the View interface. The new instance is below.
public abstract class ApplicationPanelPresenter<V extends ApplicationPanelPresenter.ApplicationPanelView>
extends PresenterWithBreadCrumb<ApplicationPanelPresenter.ApplicationPanelView> {
public interface ApplicationPanelView extends View {
void clearPanel();
}
When I try to refactor my code, and change the classes that were originally extending PresenterWithBreadCrumb to ApplicationPanelPresenter I'm introducing a compile error.
Sample before:
public class RequirementsPanelPresenter extends PresenterWithBreadCrumb<RequirementsPanelPresenter.MyView>
implements RequirementsPanelUiHandlers {
interface MyView extends View, HasUiHandlers<RequirementsPanelUiHandlers> {
}
#Inject
RequirementsPanelPresenter(EventBus eventBus, MyView view) {
super(eventBus, view);
getView().setUiHandlers(this);
}
Sample After:
public class RequirementsPanelPresenter extends ApplicationPanelPresenter<RequirementsPanelPresenter.MyView>
implements RequirementsPanelUiHandlers {
interface MyView extends ApplicationPanelPresenter.ApplicationPanelView, HasUiHandlers<RequirementsPanelUiHandlers> {
}
#Inject
RequirementsPanelPresenter(EventBus eventBus, MyView view) {
super(eventBus, view);
getView().setUiHandlers(this);
}
The compile error is on the statement getView().setUiHandlers(this);
The compile error is:
The method setUiHandlers(RequirementsPanelPresenter) is undefined for
the type ApplicationPanelPresenter.ApplicationPanelView
Why is the compiler interpreting "this" as ApplicationPanelPresenter.ApplicationPanelView? How did my change introduce this error and how can I fix it?
Additional Context
The getView() method is defined in a parent class and returns a type V extends View.
The setUiHandlers method comes from extended interface HasUiHandlers. The method parameter is type C extends UiHandlers. The interface that RequirementsPanelPresenter is implementing, RequirementsPanelUiHandler, extends UiHandlers.
At a glance, I'd expect it to be
public abstract class ApplicationPanelPresenter<
V extends ApplicationPanelPresenter.ApplicationPanelView>
extends PresenterWithBreadCrumb<V> {
Your code is too complex for me to tell at a glance if that'll fix it, though.

Raw Type warning extending a Generic Class

I'm confused by the scenario described below where I am extending a generic class. The class I am extending is below:
public abstract class PresenterWidget<V extends View> extends HandlerContainerImpl
...
At first, I had this working (warning free) using the child class below:
public abstract class SideBarPresenter<V extends SideBarPresenter.MyView> extends PresenterWidget<SideBarPresenter.MyView> {
interface MyView extends View {
void doSomething();
}
...
But I want to convert MyView to an abstract class so I can implement a method. The way I think it makes sense is below.
public abstract class SideBarPresenter<V extends SideBarPresenter.MyView> extends PresenterWidget<SideBarPresenter.MyView> {
abstract class MyView implements View {
void doSomething() {}
}
...
The problem is this produces 2 warnings, both stating:
SideBarPresenter.MyView is a raw type. References to generic type
SideBarPresenter.MyView should be parameterized
Should I just ignore this warning or is there a better way to do this?
You should make MyView a static class. Otherwise its actually an inner class of a SideBarPresenter instance and that's probably where your generics warning is coming in. Inner interfaces are static by default.

Generic interface in Java

Is it possible to have something like that? I'm trying to force any class extending this one to implement an interface that extends BaseHomeListView
public abstract class BaseHomeFragment<T extends BaseHomeListView> extends BaseRecyclerViewFragment implements T
I'm trying to implement MVP pattern in Android for some fragments which only display lists.
So basically the view has to rendersList, that's why it is in the base interface, however I still want to allow each fragment to have add more methods as they need
public interface BaseHomeListView<T> extends LoadDataView, LoadMoreView<T> {
void renderList(Collection<T> items);
}
The only sensible thing you can do is the following:
public abstract class BaseHomeFragment<T>
extends BaseRecyclerViewFragment
implements BaseHomeListView<T>
And then if you have something like
public interface FancyHomeListView extends BaseHomeListView<Fancy> {
}
Then you can just have a fragment like
public class FancyHomeFragment
extends BaseHomeFragment<Fancy>
implements FancyHomeListView {
//...
}
Assuming you want to change the implementation of the interface's methods in every subclass, but not the arguments of such methods, or decouple the business code of the fragment's views, it would be more reasonable to add a generic instance of such interface as a member of your fragment class.
public abstract class BaseHomeFragment<T extends BaseHomeListView> extends BaseRecyclerViewFragment {
/*the class information can be used against a factory method to get an instance of the interface*/
private Class<T> myInterfaceClass;
protected T myInterfaceInstance;
public void setMyInterFaceInstance(T instance){
myInterfaceInstance = instance;
}
public BaseHomeFragment(Class<T> initializeClass){
myInterfaceClass = initializeClass;
myInterfaceInstance = interfaceFactory(myInterfaceClass);
}
//TODO: use the interface instance.
}
now, in every subclass, you'll need to add the interface subclass as an argument to super:
public class myAppHomeFragment extends BaseHomeFragment<AppHomeListView>{
public myAppHomeFragment(){
super(AppHomeListView.class);
setMyInterFaceInstance(new AppHomeListView{
//Method overloading
});
}
//TODO: Use the interface's new methods if necessary.
}
a little example of your factory method:
public static <T extends BaseHomeListView> T interfaceFactory(Class<T> aClass){
if(aClass.getSimpleName().equals("someclass")){
//TODO
return new someclass;
}
return null;
}

Cumbersome generics declaration in a huge Java classes hierarchy

I have basically two types of each entity in my project which are distinguisched only by specifying the parent catalog type in the class generics declaration. Catalogs iteself are declared with generics as they can have links to a specific old catalog of the same type.
abstract class AbstractCatalog<T extends AbstractCatalog<T>> {
public abstract T getOld();
}
class Catalog1 extends AbstractCatalog<Catalog1> {
#Override
public Catalog1 getOld() { ... }
}
class Catalog2 extends AbstractCatalog<Catalog2> {
#Override
public Catalog2 getOld() { ... }
}
So far so good but the problem is that it becomes really cumbersome if I add some entities that must contain a link to a catalog of a certain type.
For instance,
abstract class AbstractCatalogHistory<C extends AbstractCatalog<C>, E extends AbstractHistoryEntry<C, E>> {
public abstract Set<E> getEntries();
}
abstract class AbstractHistoryEntry<C extends AbstractCatalog<C>, E AbstractHistoryEntry<C, E>> {
public abstract E getPrior();
}
class Cat1HistoryEntry extends AbstractHistoryEntry<Catalog1, Cat1HistoryEntry> {
#Override
public Cat1HistoryEntry getPrior() { ... }
}
class Cat2HistoryEntry extends AbstractHistoryEntry<Catalog2, Cat2HistoryEntry> {
#Override
public Cat2HistoryEntry getPrior() { ... }
}
class Catalog1History extends AbstractCatalogHistory<Catalog1, Cat1HistoryEntry> {
#Override
public Set<Cat1HistoryEntry> getEntries() { ... }
}
class Catalog2History extends AbstractCatalogHistory<Catalog2, Cat2HistoryEntry> {
#Override
public Set<Cat2HistoryEntry> getEntries() { ... }
}
so it gets much more difficult to get idea of what's going on while looking at such a hierarchy. This example is by no means complete and I have dozens of types that should be nested within those I provided above.
What I'm trying to do by doing this is to take advantage of type safe code which can be verified at compile time. But at the same time such a code becomes completely messy as I have to specify longer generics chains while adding new types to the hierarchy.
Is there a way to handle such generics explosion?
Your example doesn't make it entirely clear why you need to have separate classes for Catalog1 and Catalog2, but let's assume this is set.
However, even so I see no reason why everything else referencing these catalogs would require this kind of duplication. If you just want to make sure it's associated with the right catalog type, then this is the only generic parameter you should really need:
class CatalogHistory<C extends AbstractCatalog<C>> {
public Set<HistoryEntry<C>> getEntries();
}
class HistoryEntry<C extends AbstractCatalog<C>> {
public HistoryEntry<C> getPrior();
}
But what if you are actually doing different things in e.g. Cat1HistoryEntry and Cat2HistoryEntry so you need the separate classes? In that case you can obviously not get around having the abstract base class and two concrete implementations, but I see no need to introduce generic types and then nail them down to the concrete types the way you do:
abstract class AbstractHistoryEntry<C extends AbstractCatalog<C>> {
public abstract AbstractHistoryEntry<C> getPrior();
}
class Cat1HistoryEntry extends AbstractHistoryEntry<Catalog1> {
#Override
public Cat1HistoryEntry getPrior() { ... }
}
class Cat2HistoryEntry extends AbstractHistoryEntry<Catalog2> {
#Override
public Cat2HistoryEntry getPrior() { ... }
}
There are a few things going on here. First, consider AbstractHistoryEntry. If you have one of those, you are working on a generic level and should not care that getPrior returns this or that concrete subtype - all you need to know is that it returns another AbstractHistoryEntry object referencing the same catalog.
If you have a concrete Cat1HistoryEntry reference however, you can still get the full type safety of getting another Cat1HistoryEntry out of getPrior thanks to the covariance of return types in Java.
Now it gets slightly more complicated - Let's try to pull the same trick with AbstractCatalogHistory:
abstract class AbstractCatalogHistory<C extends AbstractCatalog<C>> {
public abstract Set<? extends AbstractHistoryEntry<C>> getEntries();
}
class Catalog1History extends AbstractCatalogHistory<Catalog1> {
#Override
public Set<Cat1HistoryEntry> getEntries() { ... }
}
class Catalog2History extends AbstractCatalogHistory<Catalog2> {
#Override
public Set<Cat2HistoryEntry> getEntries() { ... }
}
As you can see, both concrete subclasses still return a set of the concrete types Cat1HistoryEntry and Cat2HistoryEntry. The abstract base type now needs to express a common supertype for those sets so that you can work with the result in a generic way. This is done by introducing covariance.
Setters
Setters complicate the matter a bit. Basically, if you have a generic container / collection like a List<T> or an AbstractCatalogHistory<C>, and you want to allow both adding and retrieving items, you can no longer have variance in the item type if you want type safety.
For example, if you had a setter in AbstractCatalogHistory<C> which allows you to add any AbstractHistoryEntry<C> items to the history, then you have a problem, because if your AbstractCatalogHistory<C> is actually a Catalog1History then you only want Cat1HistoryEntry items in there!
This is the same problem as with generic lists: A List<Cat> is not a List<Mammal> because you can add an elephant to a List<Mammal>, but you shouldn't be able to add an elephant to a List<Cat>.
If you insist that a history for Catalog1 must consist only of Cat1HistoryEntry items, then a solution would be to only add a setter to Catalog1History, and none to AbstractCatalogHistory<C>. That way the generic classes would only be used for reading the history, not writing it.
However, going back to the beginning of my answer: If you don't actually don't need the dual concrete classes, the solution remains very simple. Unfortunately you still didn't explain why or if you need those. If all you really want is the Catalog1 / Catalog2 distinction, and you don't actually need a different implementation for e.g. Cat1HistoryEntry and Cat2HistoryEntry, then the following should suffice:
class CatalogHistory<C extends AbstractCatalog<C>> {
public Set<HistoryEntry<C>> getEntries();
public void addEntry(HistoryEntry<C> entry);
}
class HistoryEntry<C extends AbstractCatalog<C>> {
public HistoryEntry<C> getPrior();
public void setPrior(HistoryEntry<C> prior);
}

Categories