I am trying to use bounded types with generics to create generic objects of subclasses (these implement an interface). But I am getting type mismatch errors when initializing objects with the subclasses.
Here is the interface:
public interface ScannableEntity { }
Here’s the class that implements this interface:
public final class Attachment implements ScannableEntity { . . . }
Now I created 2 classes (SegmentPageScanResult and ItemProcessor) with the bounded generic type as:
@Builder public class SegmentPageScanResult<TEntity extends ScannableEntity> { . . . }
and
public class ItemProcessor<TEntity extends ScannableEntity> { void submitAndExecute(SegmentPageScanResult<TEntity> pageScanResult) { . . . } }
When I am trying to initialize the SegmentPageScanResult and try calling submitAndExecute
method of ItemProcessor from a Unit test as follows:
@ExtendWith(MockitoExtension.class) public class ScanTest { @Mock private ItemProcessor<Attachment> itemProcessor; @Test public void testDoScan() { Attachment mockRecord = new Attachment(); SegmentPageScanResult<Attachment> segmentPageScanResult = SegmentPageScanResult.builder() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .scannedItems(ImmutableList.of(mockRecord)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .isLastPage(true) ^^^^^^^^^^^^^^^^^ .build(); ^^^^^^^^^ verify(itemProcessor).submitAndExecute(segmentPageScanResult); } }
I get the error –
Required type: SegmentPageScanResult<Attachment> Provided:SegmentPageScanResult<ScannableEntity>
Can someone please help me understand why I am not able to initialize the generic object with the class implementing the interface?
Advertisement
Answer
I think you might have done:
ItemProcessor<Attachment> itemProcessor = new ItemProcessor<>();
And you also have:
SegmentPageScanResult<ScannableEntity> segmentPageScanResult = ...
So when you call:
itemProcessor.submitAndExecute(segmentPageScanResult, TEST_SEGMENT_ID, TEST_SCAN_ID);
There is a mismatch between the type of the itemProcessor (Attachment) and SegmentPageScanResult (ScannableEntity). So you probably need to create the ItemProcessor and the SegmentPageScanResult with the same type parameter.
EDIT: It’s not completely clear what you are trying to achieve but maybe this can help:
public class ItemProcessor<T extends ScannableEntity> { private List<T> items; void submitAndExecute(SegmentPageScanResult pageScanResult) { pageScanResult.setScannedItems(items); } } public class SegmentPageScanResult { private final List<ScannableEntity> items = new ArrayList<>(); public void setScannedItems(List<? extends ScannableEntity> items) { this.items.addAll(items); } }
So the SegmentPageScanResult no longer has a type parameter because it only handles ScannableEntity instances. To allow setting different types from each ItemProcessor, the method parameter allows subtypes with List<? extends ScannableEntity>