Reputation: 41
I have a bunch of simple interfaces:
interface County extends Line{}
interface Country<C extends Line> extends LineContainer<C> {}
interface Line {}
interface LineContainer <L extends Line> {
public List<L> getLines();
}
And a Service Method
public static <L extends Line,C extends LineContainer<L>> C getContainer( Class<C> containerType, Class<L> lineType ){
...somthing...
Calling the Service Method
Country<County> c = getContainer( Country.class, County.class );
faces no error, but the checker says:
Type safety: The expression of type Country needs unchecked conversion to conform to Country
I don't understand that: By calling the service method with County as the L-LineType and C is the Container for L and C is given by Country as the C-Type, thus, I expected type inference would conclude, that a Country object will be served.
Can anyone explain, why I am wrong and if and how I can achieve what I want to?
Background: The idea is - as a user of the service - i can freely combine containers and lines just as needed (as long as the service provider can serve these)
Upvotes: 4
Views: 373
Reputation: 41
I think I solved it...
The main mistake in my question was, that I wanted to define the line elements in the container. Now I define in Line to what Header it belongs.
interface Line<R> {}
Than, I define a LineContainer, that serves Lines from the defined Type
interface LineContainer<H, L extends Line<H>> {
public List<L> getLines();
}
Now I can define a generic service method (looks slightly different to my approach above):
public static <H,L extends Line<H>,C extends LineContainer<H,L>> C getContainer( Class<C> containerType, Class<L> lineType ){
// ...something...
}
Defining Country and County like this:
interface County extends Line<Country>{}
interface Country extends LineContainer<Country,County>{};
I can now use without any problems:
LineContainer<Country,County> container = getContainer( Country.class, County.class );
Another Example with LineContainer and Line:
interface Note extends Line<Gamut>{}
interface Gamut extends LineContainer<Gamut,Note>{};
LineContainer<Gamut,Note> container = getContainer( Gamut.class, Note.class );
The Service Method has to check, if the required types can be served, but the user of the service cannot combine types that are not comaptible:
NOT ALLOWED
LineContainer<Gamut,County> container = getContainer( Gamut.class, County.class );
as County is not a "Line" of Gamut...
Upvotes: 0
Reputation: 8363
This is because the compiler isn't sure that Country.class
matches the signature Country<County>
. Country.class
is considered raw type.
If you write this:
public static <L extends Line, C extends LineContainer<L>> C getContainer(C container, Class<L> lineType) {
return null;
}
and:
Country<County> c = getContainer(new Country<County>() {
@Override
public List<County> getLines() {
return null;
}
}, County.class);
Obviously this works.
Now imagine I split the same code into another way:
Country foo = new Country<County>() {
@Override
public List<County> getLines() {
return null;
}
};
Country<County> c = getContainer(foo, County.class);
This will again give warning at compile time, because of raw type.
Upvotes: 1
Reputation: 170
The Problem with your code is that Country can have a Generic Type C which extends Line, however using your method.
getContainer( Country.class, County.class );
This method doesn't tell you that this Country.class has the C type of County.. therefore in theory your return C would be Country.
Unfortunately there is no real fix for this other than to either suppress the warning. Or you don't use a parameter in Country and make C fixed to County.
public interface Country extends LineContainer<County>
You also could use actual objects or suppliers etc.
Upvotes: 0