Reputation: 3015
I have an interface like this:
public interface BatchSynchronisedPool<R extends Runnable> {
void execute(R runnable, Object batchIdentifier);
public <T> Future<T> submit(Callable<T> callable, Object batchIdentifier);
}
I want to infer an upper bound for Callable, but still want to be able to keep the <T>
argument on the method:
public interface BatchSynchronisedPool<R extends Runnable, C extends Callable> {
void execute(R runnable, Object batchIdentifier);
public <T> Future<T> submit(C<T> callable, Object batchIdentifier);
}
Obviously that doesn't work, because the type of C
I specify may only take a specific range of T
arguments. However, now you have the general just of what I am trying to do, is there a possible solution, or am I stuck always having to submit a callable? (Or remove generics altogether and perform an unsafe cast)
Upvotes: 4
Views: 193
Reputation: 26520
I'm not 100% certain, but don't think that you can do what you're trying to do here. Since C
is not generic, you can't use C<T>
. Lots of code below, but tl;dr take option 3. All that really changes in the end is how many BatchSynchronisedPool
objects you'll need to create, which is not really a considerable overhead...
1. Keep the <T>
generic type parameter on the method, submit a Callable<T>
and perform a runtime check of the types, like your original solution, in the class that implements this interface.
public interface BatchSynchronisedPool<R extends Runnable> {
void execute(R runnable, Object batchIdentifier);
public <T> Future<T> submit(Callable<T> callable, Object batchIdentifier);
}
public class MyBSP<R, C> implements BatchSynchronisedPool<R, C> {
void execute(R runnable, Object batchIdentifier) { ... }
public <T> Future<T> submit(Callable<T> callable, Object batchIdentifier) {
// Check types.
if (!(callable instanceof MyDesiredCallableClass)) {
throw new IllegalArgumentException("Types don't match.");
}
// Do work.
T result = callable.call();
...
}
}
public class MyUsageClass {
public static void main(String[] args) {
// Submit string.
MyBSP<Runnable> bsp = new MyBSP<Runnable>();
bsp.submit(new StringCallable(), someObject1);
// Submit integer.
bsp.submit(new IntegerCallable(), someObject2);
}
}
2. Keep the <T>
generic type parameter on the method, submit a C
and perform a cast, like you've suggested, in the class that implements this interface.
public interface BatchSynchronisedPool<R extends Runnable, C extends Callable> {
void execute(R runnable, Object batchIdentifier);
public <T> Future<T> submit(Class<T> cls, C callable, Object batchIdentifier);
}
public class MyBSP<R, C> implements BatchSynchronisedPool<R, C> {
void execute(R runnable, Object batchIdentifier) { ... }
public <T> Future<T> submit(Class<T> cls, C callable, Object batchIdentifier) {
// Do work... with a cast.
T result = cls.cast(callable.call());
...
}
}
public class MyUsageClass {
public static void main(String[] args) {
// Submit string.
MyBSP<Runnable, Callable> bsp = new MyBSP<Runnable, Callable>();
bsp.submit(new StringCallable(), someObject1);
// Submit integer.
bsp.submit(new IntegerCallable(), someObject2);
}
}
3. Create a new BatchSynchronisedPool
for each type T
that you're trying to submit by specifying T
as a generic type parameter for the class. Then each time you want to call submit
on a different type, you'd need to generate a new instance of BatchSynchronisedPool
.
public interface BatchSynchronisedPool<T, R extends Runnable, C extends Callable<T>> {
void execute(R runnable, Object batchIdentifier);
public Future<T> submit(C callable, Object batchIdentifier);
}
public class MyBSP<T, R, C> implements BatchSynchronisedPool<T, R, C> {
void execute(R runnable, Object batchIdentifier) { ... }
public Future<T> submit(C callable, Object batchIdentifier) {
// Do work. Types are okay; no checking or casting needed!
T result = callable.call();
...
}
}
public class MyUsageClass {
public static void main(String[] args) {
// Submit string.
MyBSP<String, Runnable, Callable<String>> stringBsp = new MyBSP<String, Runnable, Callable<String>>();
stringBsp.submit(new StringCallable(), someObject1);
// Submit integer.
MyBSP<Integer, Runnable, Callable<Integer>> integerBsp = new MyBSP<Integer, Runnable, Callable<Integer>>();
integerBsp.submit(new IntegerCallable(), someObject2);
}
}
Upvotes: 4