I am trying to create a library with a container that frees instances of the objects contained in it according to the descriptors it passed. I would like the descriptor to determine the type of the returned object, but the descriptor can specify a limited type. How to implement this? For example, the closest I can get:
/*Block 1 - First Attempt. Compiles, but forces user to cast*/ interface ItemDescriptor<I> { Class<? extends I> getType(); } interface ArchiveContainer<I, D extends ItemDescriptor<? extends I>> { Iterable<? extends D> getDescriptors(); I getItem(D descriptor); }
The above code compiles, but the ChannelArchive getItem problem may return a SeekableByteChannel . The user of this library knows this at compile time (because they know a parameter of type descriptor), so I try not to add a parameter of a method of type Class to force the user to explicitly map the return value to SeekableByteChannel if necessary. I cannot figure out how to get getItem in order to return a specific ByteChannel subtype without forcing the user to quit. I want to do this:
ChannelArchive archive = ...; ChannelItemDescriptor<SeekableByteChannel> desc = ...; ChannelItemDescriptor<ByteChannel> otherDesc = ...; SeekableByteChannel sbc = archive.getItem(desc); SeekableByteChannel sbc = archive.getItem(otherDesc);
I can add the parameter Class<? extends I> Class<? extends I> for each method, but the method code completely ignores the parameter of the Class method! The only goal is to help developers deduce types. I think this just obfuscates the code so much that it would be easier to just use the user instanceof validation and drop.
I tried this:
class ChannelArchive implements ArchiveContainer<ByteChannel, ChannelItemDescriptor<? extends ByteChannel>> {
but this does not work: ChannelArchive is not abstract and does not override abstract method getItem(ChannelItemDescriptor<? extends ByteChannel>) in ArchiveContainer . I suppose this is because the parameter of the second type <II extends ByteChannel> differs by erasing the type than <? extends ByteChannel> <? extends ByteChannel> ?
I also tried this by compiling:
interface ArchiveContainer<I, D extends ItemDescriptor<? extends I>> { Iterable<? extends D> getDescriptors(); <II extends I, DD extends ItemDescriptor<II>> II getItem(DD descriptor); } class ChannelArchive implements ArchiveContainer<ByteChannel, ChannelItemDescriptor<? extends ByteChannel>> { @Override <II extends ByteChannel, DD extends ItemDescriptor<II>> II getItem(DD descriptor) {...} }
Although it compiles, it will not work because I need a ChannelItemDescriptor inside this method, and the result will defeat the goal of using the added generic type safety.
I do not understand why I cannot do this because the correct types are known at compile time. What I really need in this interface is the ArchiveContainer , a parameter of a parameterized type, for example: <II extends I, DD extends D<II>> . What am I doing wrong?
NOTE. I don't actually use ByteChannel and SeekableByteChannel , but what I use is pretty similar.
In order to ruch, I settled on the code in block 4. In my case, it is very unlikely that the user would send the wrong ItemDescriptor swap in the getItem call, especially because all the descriptors were returned from the ArchiveContainer itself via getDescriptors !