Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Factory and generics

Tags:

java

generics

I have the following classes:

public interface IDataSource<T> {
  public List<T> getData(int numberOfEntries);
}

public class MyDataSource implements IDataSource<MyData> {
  public List<MyData> getData(int numberOfEntries) {
    ...
  }
}

public class MyOtherDataSource implements IDataSource<MyOtherData> {
  public List<MyOtherData> getData(int numberOfEntries) {
    ...
  }
}

I would like to use a factory that return the correct implementation based on the data type. I wrote the following but I get "Unchecked cast" warnings:

public static <T> IDataSource<T> getDataSource(Class<T> dataType) {
    if (dataType.equals(MyData.class)) {
        return (IDataSource<T>) new MyDataSource();
    } else if (dataType.equals(MyOtherData.class)) {
        return (IDataSource<T>) new MyOtherDataSource();
    }

    return null;
}

Am I doing it wrong? What can I do to get rid of the warnings?

like image 692
CrazyDoggg Avatar asked Oct 18 '13 23:10

CrazyDoggg


2 Answers

I am not aware of any way to get rid of those warnings without @SuppressWarnings("unchecked").

You are passing in a Class object so T can be captured. But you are forced to check the Class at runtime to determine which IDataSource<T> to return. At this time, type erasure has long since occurred.

At compile time, Java can't be sure of type safety. It can't guarantee that the T in the Class at runtime would be the same T in the IDataSource<T> returned, so it produces the warning.

This looks like one of those times when you're forced to annotate the method with @SuppressWarnings("unchecked") to remove the warning. That warning is there for a reason, so it is up to you to provide and ensure type safety. As written, it looks like you have provided type safety.

@SuppressWarnings("unchecked")
public static <T> IDataSource<T> getDataSource(Class<T> dataType) {
like image 160
rgettman Avatar answered Sep 28 '22 09:09

rgettman


You're doing it right, and you should simply suppress the warnings. Factories are one of the tricky areas in generics where you really do need to manually cast to a generic type, and you have to ensure via whatever means that the returned value matches the Class<T> you pass in. For example, in this case you're hard-coding a couple of IDataSource implementations, so I would recommend writing unit tests that verify that the types are correct so that if the MyData implementation changes in an incompatible way, you'll get an error on build.

Just annotate the getDataSource method with @SuppressWarnings("unchecked"), and it's always a good idea to add an explanatory comment when suppressing warnings.

like image 38
chrylis -cautiouslyoptimistic- Avatar answered Sep 28 '22 09:09

chrylis -cautiouslyoptimistic-