Avoiding making classes generic by using unchecked type casts

254 Views Asked by At

Let's say I create a package process with a public class Processor, which has a constructor that expects a parameter of type Container<I>. The class Container<I> lies in a different package beyond my control and contains objects of arbitrary type I. The container with the contained items is passed around between multiple classes of the package process.

The items are processed via methods of the interface Processable. They can be retrieved by the user of process via the method getProcessedItem(Property property). This method returns a processed item with the property property which is ensured to be contained by the passed container and can therefore be cast to the type parameter of the container.

example class:

package process;

import container.Container;

public class Processor<I extends Processable> {
    private final ItemProcessor itemProcessor;

    public Processor(Container<I> container){       
        this.itemProcessor = new ItemProcessor(container);
    }

    @SuppressWarnings("unchecked")
    public I getProcessedItem(Property property){
        return (I)itemProcessor.getProcessedItem(property);
    }

}

Is it generally a good idea to make an unchecked type cast in a situation like this?

The only reasonable alternative I figured out so far is to make all classes in the package process that have to hold a reference to the parameterized container (like ItemProcessor) also generic just for the sake of preserving the type information needed in getProcessedItem(Property property).

EDIT: To clarify the functionality of the container class in my example:

I wanted the container class to represent some rather primitive collection-like class which should merely make it possible for the processor to retrieve the items it has to process.

That means ItemProcessor and classes used by ItemProcessor should be able to handle the processable items (once they are retrieved from the container) as they like (e.g. store them in lists or other data structures). And finally it should be possible to request a processed item based on a certain processor-specific property. For example:

getProcessedItem(Property.MOST_RECENTLY_PROCESSED)

Like java's standard collection classes (e.g. ArrayList) Container<I> does not strictly guarantee that it only contains I and its descendants. This means once an item of the container is used as a Processable, while actually not being a Processable, a cast exception occurs.

In the version of the Processor class above no exception is immediately thrown when an item requested via getProcessedItem is not compatible to type I (due to the unchecked cast). But also if I made ItemProcessor generic (ItemProcessor<I>) and made its getProcessedItem return I instead of using the unchecked cast, no exception would be thrown at that point. Therefore I am also unsure if it would be better to make a runtime type check using a Class<I> object in getProcessedItem. The Class<I> object would have to be explicitly served by the caller as a parameter or via the given container. I feel like it should not be the processor's concern to ensure that the items in the container are actually compatible with I, because the processor is not responsible for the validness of the content of the given container.

2

There are 2 best solutions below

0
On

I think your SuppressWarnings defeats the purpose of generics. What you should do is to make getProcessed item generic as well.

public class ItemProcessor<I extends Processable> {
    public I getProcessedItem() {
       return somethingWhichIsProcessable;
    }
0
On

The Class class has a cast() method on it that generates no warnings...

However, your model is wrong. You should be asking container for the item, not an arbitrary item processor. You're breaking encapsulation. The whole ItemProcessor smells of it in fact. You should consider a polymorphic solution, where objects act upon themselves, rather than a model where an external actor acts upon objects externally.