I'm attempting to create a generic JavaFX Service
that will use DbUtils' BeanListHandler
to hand an ObservableList
back to the app GUI thread. The intention is to reuse it to load many tables into many different lists of different bean classes.
The problem I'm having is dealing with the generics in the call()
method for the Task
.
ICINGBean
is an abstract class that all the beans I'm dealing with inherit fromextend.
public class StaticDataFetcher extends Service<ObservableList<? extends ICINGBean>> {
private Class<? extends ICINGBean> beanClass;
@Override
protected Task createTask() {
DataGetter dget = new DataGetter();
dget.setBeanClass(beanClass);
return dget;
}
public Class<? extends ICINGBean> getBeanClass() { return beanClass; }
public void setBeanClass(Class<? extends ICINGBean> beanClass) { this.beanClass = beanClass; }
}
class DataGetter extends Task<ObservableList<? extends ICINGBean>> {
private Class<? extends ICINGBean> beanClass;
@Override
protected ObservableList<? extends ICINGBean> call() {
ObservableList<? extends ICINGBean> staticList;
staticList = FXCollections.observableArrayList();
ResultSetHandler<List<? extends ICINGBean>> handler;
handler = new BeanListHandler<? extends ICINGBean>(beanClass);
try {
List<? extends ICINGBean> resultList;
resultList = EntryPoint.getQRunner().query("SELECT * FROM ?", handler, beanClass.getSimpleName());
staticList = FXCollections.observableList(resultList);
} catch (SQLException ex) {
Logger.getLogger(DataGetter.class.getName()).log(Level.SEVERE, null, ex);
}
return staticList;
}
public Class<? extends ICINGBean> getBeanClass() { return beanClass; }
public void setBeanClass(Class<? extends ICINGBean> beanClass) { this.beanClass = beanClass; }
}
The compile-time error I'm getting is:
.../ICING/src/com/cccg/icing/StaticDataFetcher.java:55: error: unexpected type
handler = new BeanListHandler<? extends ICINGBean>(beanClass);
^
required: class or interface without bounds
found: ? extends ICINGBean
I'm pretty sure I'm just messing up the generics handling royally, but I'm not sure how. I've followed the listed example on the DbUtils example page for using a BeanListHandler, substituting where I thought appropriate to use a generic type with it, but I'm getting nowhere on the error.
Any help is greatly appreciated, thanks!
With the helpful suggestion of Paul Bellora below I was able to solve this. I declared a type parameter for the class and used that along with the diamond operator.
public class StaticDataFetcher<T extends ICINGBean> extends Task<ObservableList<? extends ICINGBean>> {
private Class<T> beanClass;
//...
public StaticDataFetcher(Class<T> beanClass) {
super();
this.beanClass = beanClass;
}
protected ObservableList<? extends ICINGBean> call() {
//...
ResultSetHandler<List<T>> handler;
handler = new BeanListHandler<>(beanClass);
//...
}
}
Thanks for the help everybody, I hope this helps others!
You're not allowed to instantiate a generic type with wildcard type arguments. See my explanation about why in this answer.
A simple solution is to use the diamond operator (Java 7 and later):
handler = new BeanListHandler<>(beanClass);
If that's not available, you need to use a generic helper method:
<T extends ICINGBean> BeanListHandler<T> makeContainer(Class<T> beanClass) {
return new BeanListHandler<T>(beanClass);
}
...
handler = makeContainer(beanClass);