Reputation: 3321
I have a generic class:
public class Facet<C extends Component>
{
private final C child;
public Facet(C child) { this.child = child; }
public C getChild() { return this.child; }
public UIComponent getViewComponent() {
return PrimeFacesComponentFactory.create(facesContext, this.getChild());
}
}
I have a component factory that also has a bunch of methods, several of which look like this:
public static UIComponent create(FacesContext fc, Component component) {
throw new UnsupportedOperationException("Method not yet implemented for class: " + component.getClass().getName());
}
public static UIRow create(FacesContext fc, Row modelRow) { ... }
public static UIColumn create(FacesContext fc, Column modelColumn) { ... }
NOTE: in each of the factory methods the 2nd argument is an object that extends Component and what is returned is always a subclass of UIComponent. The first factory method (the one that throws the exception) is intended to be a "catch all," which is invoked if there is no specific factory method written for a particular component.
What I'm trying to do: the correct factory method should be invoked depending on what type of component facet's child is. What's happening is that the first factory method is always invoked (e.g. the one that throws the exception). This is counterintuitive to me, since the type of C is known at runtime and C is "some specific type that extends Component."
Debugging, I set a breakpoint at Facet#getViewComponent
, invoking it when I knew that facet.getChild()
would return an object of type Row. So in this example C was Row. It surprised me to see that when the factory method was invoked e.g.
PrimeFacesComponentFactory.create(facesContext, facet.getChild());
program execution flowed to the "catch all" factory method! If, however, I explicitly cast facet.getChild() as follows:
PrimeFacesComponentFactory.create(facesContext, (Row)facet.getChild());
then the specific method was invoked. Weird, because I simply/redundantly cast a Row to a Row.
I've read some about why this is happening, but it's still hazy and counterintuitive to my mind. At any rate, how can I resolve this problem?
Upvotes: 2
Views: 268
Reputation: 279880
With the following declaration
public C getChild() { return this.child; }
public UIComponent getViewComponent() {
return PrimeFacesComponentFactory.create(facesContext, facet.getChild());
}
assuming facet
is meant to be this
, at compile time, the only thing that is known about the type parameter C
is that it extends Component
. So the compiler binds this method call with the method declared to accept a Component
.
public static UIComponent create(FacesContext fc, Component component) {
throw new UnsupportedOperationException("Method not yet implemented for class: " + component.getClass().getName());
}
Upvotes: 0
Reputation: 56536
The overload resolution happens once, at compile-time, for the Facet
class, not for each C
in Facet<C>
, and not at run time. A potential solution is to make your catch-all method smarter:
public static UIComponent create(FacesContext fc, Component component) {
if (component instanceof Row)
return create(fc, (Row)component);
else if (component instanceof Column)
return create(fc, (Column)component);
// include other types, and lastly
else
throw new UnsupportedOperationException("Method not yet implemented for class: " + component.getClass().getName());
}
Upvotes: 3