Not able to create generic bounded class objects with interface - java

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?

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>

basically the answer is simple: here you specified that a class of type ScannableEntity will come. but you used SegmentPageScanResult, You used the ScannableEntity interface itself, I think that if you use the Attachment class that implements the interface class, not the interface class, the problem will be fixed, for example: You can use it as SegmentPageScanResult.

Related

JDBI3 Returning a Parameterized Class

I have an abstract EntryPoint class that looks like this:
public abstract class EntryPoint<T extends Tag> implements Serializable {
public EntryPoint(){}
protected ArrayList<T> tiedTags;
public abstract ArrayList<T> getTiedTags();
public abstract void setTiedTags(List<T> tiedTags);
}
I then have subclasses of this EntryPoint class that each accept only one kind of Tag. For instance an SNMPEntryPoint only stores SNMPTags. The subclasses provide implementations of the abstract methods:
public class SNMPEntryPoint extends EntryPoint<SNMPTag> implements Serializable {
//Default Constructor for Serialization
public SNMPEntryPoint(){}
#Override
public ArrayList<SNMPTag> getTiedTags(){ return tiedTags; }
//etc
}
Is there a means to create a JDBI query that returns a List of parameterized classes? At the moment, this is what I'm doing:
public List<SNMPEntryPoint> getSNMPEntryPoints(){
try(Handle handle = daoFactory.getDataSourceController().open()) {
return handle.createQuery("SELECT * FROM dbo.EntryPoints WHERE Active = 1 AND SiteID = :sID AND Protocol = 'SNMP'")
.mapToBean(SNMPEntryPoint.class)
.list();
}
catch(Exception e){
if(sysconfig.getVerbose()){ e.printStackTrace(); }
}
return null;
}
But this feels like a raw use of the class. So I guess my question is, if I use this code to generate SNMPEntryPoints and then call getTiedTags or setTiedTags on those EntryPoints, will that work? Am I breaking any coding conventions by creating my SNMPEntryPoint objects in this way?
Just wanted to close this out. My classes weren't actually parameterized. As you can see above they extend the parameterized abstract class however SNMPEntryPoint doesn't actually take any parameters, so there's no need to do anything differently from what I'm doing above.
HOWEVER, if you do need to return a parameterized generic from JDBI you can do so using the details found here.

Java generic : Restricting a class to specific implementations.

I have the following class hierarchy:
public abstract class Config<T> implements Proxy<T> {
public abstract T parse();
public T get() {....}
}
public class IntegerConfig<Integer> extends Config<Integer> {
public Integer parse() {...}
}
public class LongConfig<Long> extends Config<Long> {
public Long parse() {...}
}
public class IntegerListConfig<List<Integer>> extends Config<List<Integer>> {
public List<Integer> parse() {....}
}
And so on...
I'd like to introduce a new class:
public class ConfigMutation<T> implements Proxy<T> {
public ConfigMutation(....) {
//// create a concrete implementation of Config<T> according to actual parameterized type
}
}
Essentially, I'd like to avoid repeating the entire class hierarchy of Config, and support in ConfigMutation all types that have parameterized implementations in Config class hierarchy.
Couldn't find a way to do it. (Class<T>)((ParameterizedType)getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0] obviously returns T, and not the actual type.
Also, once this problem is solved, I'd be happy if someone could suggest some factory pattern with generic types, so when I'm instantiating a Config derived class inside ConfigMutation, I wouldn't have to do it with a huge if...else block on actual type.
Thanks,
Lior
Change your ConfigMutation class to :
public class ConfigMutation<U,T extends Config<U>> implements Proxy<U> {
public ConfigMutation() {
}
}
You can then use ConfigMutation as :
ConfigMutation<Integer,IntegerConfig> mutation;
You won't be able to do something as follows which is what you want :
ConfigMutation<String,IntegerConfig> mutation;
That said, there is a change you need to make to your concrete Config implementers as well. For example, change IntegerConfig to :
public class IntegerConfig extends Config<Integer> {
public Integer parse() {...}
}
The Integer in IntegerConfig<Integer> will be considered as a type parameter and not the Integer class which is not what you want. (An IDE should give you a warning for this; The type parameter Integer is hiding the type Integer)

How can I define class using multiple generic?

I want to create object like belows :
private MyHashTable<AVLtree<TreeData>, TreeData> hashTable = new MyHashTable<>();
AVLtree and TreeData is what I defined, not java built in class.
But, I have no idea how to define MyHashTable class using generic.
What I can think about is
public class MyHashTable<S<T>,T> but it doesn't work.
You can declare like this
public class MyObject<T> {
}
public class MyHashTable<S extends MyObject<T>, T> {
}
In this case you can use
public class MyHashTable<S extends AVLTree<T>, T> {
}
Hope this help.

Generics: Treeset add a Subclass

I'm stuck in the following situation. I got an abstract class called Fusion which should have a TreeSet of so called ClusteringObjects (which is an abstract class as well). Therefore I set the type to
public abstract class Fusion {
protected TreeSet<? extends ClusteringObject> metadata;
//CODE
}
In a subclass of Fusion (called TemporalFusion) I want to add TemporalClusteringObjects (subclass of ClusteringObject) to the TreeSet but this doesn't work.
public class TemporalFusion extends Fusion {
public TemporalFusion(Model metadataModel, String fusionId) {
//CODE ...
metadata = new TreeSet<TemporalClusteringObject>(new TimestampComparator());
}
public void add(int metadataIndex, ParsedMetadata singleMetadata) {
//create temporalClusteringObject (works fine)
metadata.add(temporalClusteringObject);
}
}
The add gives following failure:
The method add(capture#2-of ? extends ClusteringObject) in the type TreeSet<capture#2- of ? extends ClusteringObject> is not applicable for the arguments (TemporalClusteringObject)
Is there a generic solution to this problem where not every subclass of Fusion has to implement its own metadata TreeSet with it's own entry type inherit by ClusteringObject?
The metadata member should use a concrete generic. Either just set it to ClusteringObject or declare a class generic for Fusion.
Example:
public abstract class Fusion<T extends ClusteringObject> {
protected TreeSet<T> metadata;
...
Then declare the derived class like this:
public class TemporalFusion extends Fusion<TemporalClusteringObject> {
It should work then.

Java generics in an interface

I have run into a problem with generics in Java and I can't find a solution or example online of someone using generics in a similar fashion. I have a set of methods that are in the same request/response structure. For example, a user populates fields in the Request object, passes the object to a helper method, and they are returned a Response object. All of my request objects extend from a common Request super class (and similarly, Response objects from a Response super class). I would like my helper classes to also have a consistent structure so I have used an interface. Here is some code to illustrate...
Request super class:
public class SuperRequest {
// ...
}
Example Request subclass:
public class SubRequest extends SuperRequest {
// ...
}
Response super class:
public class SuperResponse {
// ...
}
Example response subclass:
public class SubResponse extends SuperResponse{
// ...
}
The interface:
public interface SomeInterface {
public <T extends SuperRequest, U extends SuperResponse> U someMethod(T request);
}
As you can see from the interface, I want to pass an object that is a child of SuperRequest and I want to return an object that is a child of SuperResponse. Here is my implementation:
public class SomeImplementation implements SomeInterface {
#Override
public SubResponse someMethod(SubRequest request) {
return null;
}
}
In Eclipse, I get compilation errors because the compiler tells me I have unimplemented methods and the #Override notation "does not override a supertype method".
Can anyone help me here? Is my syntax incorrect or is my understanding of generics a little off? Any help is greatly appreciated!
Try changing your interface and implementation to:
interface SomeInterface<T extends SuperRequest, U extends SuperResponse> {
public U someMethod(T request);
}
class SomeImplementation implements SomeInterface<SubRequest, SubResponse> {
#Override
public SubResponse someMethod(SubRequest request) {
return null;
}
}
As it stands, the implementation of SomeInterface must implement the parameterized method, i.e.:
public <T extends SuperRequest, U extends SuperResponse> U someMethod(T request);
It can't choose a particular Subclass to substitute for T and U.
The interface itself must be generic SomeInterface<T extends SuperRequest, U extends SuperResponse> and the subclass can then choose concrete implementations for T and U.
You have to declare the types as well when you implement the interface. Try this:
public class SomeImplementation implements SomeInterface<SubRequest,SubResponse> {
#Override
public SubResponse someMethod(SubRequest request) {
return null;
}
}

Categories

Resources