I'm having trouble declaring a fully generic type for the output of a method. Here's the situation:
class A<S,T>{
public Callback<B<S,T>,C<S,T>> method();
}
in my code I have one of these;
A<String, ?> instance;
however, when I call
result = instance.method()
the only way to make the compiler happy is to declare
Callback<?, ?> result = instance.method()
But I would really like to be more specific with my generics and declare
Callback<B<String, ?>,C<String, ?>> result = instance.method()
however, since each wildcard is separate, the compiler complains that this is incorrect, stating that it cannot convert from
Callback<B<String,capture#3-of ?>,C<String,capture#3-of ?>>
Is there any way of declaring this situation correctly?
FYI, classes A, B, and C are from external libraries. I tried to declare my instance as
A<String, Object>
but it's also the result of a method from a fourth class that I have no control over:
class D<T>{
public A<T, ?> getObject();
}
D<String> start = new D<String>();
A<String, ?> = start.getObject();
...
This is indeed an awkward situation, a result of the limitations of wildcard capture and a less than ideal return type from D.getObject
.
There are a few workarounds but none are pretty. The first is to simply do an unchecked cast:
@SuppressWarnings("unchecked") //it's okay for the two captures not to match
Callback<B<String, ?>, C<String, ?>> result =
(Callback<B<String, ?>, C<String, ?>>)instance.method();
EDIT: Some compilers will (more correctly) require a double cast through Callback<?, ?>
:
@SuppressWarnings("unchecked") //it's okay for the two captures not to match
Callback<B<String, ?>, C<String, ?>> result =
(Callback<B<String, ?>, C<String, ?>>)(Callback<?, ?>)instance.method();
You could also use a helper method - this is a common solution to wildcard capture issues:
static <T> void helper(A<String, T> a) {
Callback<B<String, T>, C<String, T>> result = a.method();
//logic
}
...
helper(instance);
UPDATE:
In fact you can combine these two approaches to at least isolate the ugliness into a single helper method:
static <S, T> Callback<B<S, ?>, C<S, ?>> disentangleCallback(
Callback<B<S, T>, C<S, T>> callback
) {
@SuppressWarnings("unchecked") //it's okay for the two captures not to match
final Callback<B<S, ?>, C<S, ?>> withWidenedTypes =
(Callback<B<S, ?>, C<S, ?>>)(Callback<?, ?>)callback;
return withWidenedTypes;
}
And then use it like this:
Callback<B<String, ?>, C<String, ?>> result =
disentangleCallback(instance.method());
Or else a similar method that simply takes an A<S, T>
and returns a Callback<B<S, ?>, C<S, ?>>
by calling method
itself, then casting.
Another idea: if the second type argument of A
is always an unknown, it might be easier to just remove it and widen the return type of method
:
class A<S> {
public Callback<B<S, ?>, C<S, ?>> method() { ... }
}
I realize that would be an unfortunate concession, but it makes sense if T
is never actually useful.