Let's say I need a class that is bounded to a generic Comparable type:
class A<T extends Comparable<T>> {
// this is just an example of usage of T type
List<T> comparables;
int compareSomething(T smth) {
return comparables.get(0).compareTo(smth);
}
}
The class has a method with own generics in signature:
<V> Future<V> submit(Callable<V> task) {
return someExecutorService.submit(task);
}
Now, is there a possibility to restrict the input of the submit method to accept only Callables that also implement T? I first tried this:
<V, W extends T & Callable<V>> Future<V> submit(W task) {
if(compareSomething(task) != 0)
throw new RuntimeException("");
return someExecutorService.submit(task);
}
but found out it's not possible (for reasons described here). Is there any elegant possibility to bypass it?
EDIT: The one ugly possibility I can think about is to split the encapsulation in two different types and pass an object pair in submit:
class A<T extends Comparable<T>> {
// this is just an example of usage of T type
List<T> comparables;
int compareSomething(T smth) {
return comparables.get(0).compareTo(smth);
}
<V> Future<V> submit(Callable<V> task, T comparable) {
if(compareSomething(comparable) != 0)
throw new RuntimeException("");
return someExecutorService.submit(task);
}
}
The main disadvantage is that the method signature becomes more complicated, also I will need some one-to-one mapping of Ts to Callables for some latter code. Maybe one can suggest a pattern that solves it in an appropriate way?..
EDIT, take two: Let me explain briefly what I'm trying to achieve. I'm working on a custom thread pool implementation that is able to perform some kind of special task scheduling. To do so, this service accepts only one special sort of Callable tasks. Those Callables have to implement a custom interface that is similar to the Comparable one. By comparing pairs of tasks using methods in this interface, the service will:
- Block the incoming task if it is blocked by any running task.
- Invoke pending tasks on completion of a done task's
Future. - Determine the execution order of pending tasks by comparing them.
The blocking/comparison logic should be provided by the tasks themselves. This way the thread pool class should only define what special kind of Comparables the pool object is accepting, and it doesn't care at all what kind of Callables they really are and what is their return type.
EDIT, take three: Based on Erick Robertson's answer, it's now possible to prevent submitting of smelly tasks:
public static void test(String[] args) {
A<Valid> scheduler = new A<>();
scheduler.betterSubmit(new Valid()); // applies to method signature
scheduler.betterSubmit(new Forbidden()); // rejected on compile time
scheduler.betterSubmit(new ConformWithValid()); // still appliable because all required interfaces implementations recognised
}
// just a bunch of test classes
private static class Valid implements Comparable<Valid>, Callable<Void> {
@Override
public int compareTo(Valid o) {
return 0;
}
@Override
public Void call() throws Exception {
return null;
}
}
private static class Forbidden implements Comparable<Forbidden>, Callable<Void> {
@Override
public int compareTo(Forbidden o) {
return -1;
}
@Override
public Void call() throws Exception {
return null;
}
}
private static class ConformWithValid implements Comparable<Valid>, Callable<Boolean> {
@Override
public int compareTo(Valid o) {
return 1;
}
@Override
public Boolean call() throws Exception {
return Boolean.FALSE;
}
}
Nice and easy! Hope some day this will help someone in the same situation as mine. :-)