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.
You could have
Callback<? extends B<String, ?>, ? extends C<String, ?>> result
= instance.method();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With