Actually the latest example is what I'm looking at - the InvocationCallback generic type itself (and not the generic type of the response inside the InvocationCallback generic type). With my change the implementations can all rely on the same type-inference code implemented in the GenericType, like this:
submit(InvocationCallback<T> callback) {
// ...execute request..
Class<?> responseClass = callback.getRawType();
Type responseType = callback.getType();
// ...read the response entity as the proper type and invoke the callback...
}
Without extending InvocationCallback from GenericType (and with a lack of any decent type-inference utilities in Java SE), all implementations would need to find their own ways of computing the actual callback response type, which is not as straightforward as it may seem.
For instance, there is even a case, when the type cannot be computed at all. E.g.:
public class MyGenericCallback<T> implements InvocationCallback<T> { ... }
MyGenericCallback<String> callback = new MyGenericCallback<String>(); // generic response type information is lost here...
client.target(...).request().async().get(callback); // fails to reify...
FWIW, if you tried to do the above with a GenericType sub-class, your code would fail immediately at instance construction, while with the interface it would only fail after submitting the request (possibly after the request has been sent and response received - depending on the implementation).
But if more people in EG think that we should switch back to interface, I would make the change.
Marek
On Jun 28, 2012, at 12:22 AM, Bill Burke wrote:
> One more thing I'd like to add:
>
> I don't think the problem you describe exists anyway. Consider this:
>
> class MyCallback implements InvocationCallback<List<Foo>>
> {
> public void complete(List<Foo> foo) {
> ...
> }
>
> The type information here can be obtained at runtime and the entity can be correctly unmarshalled. We already do this for MessageBodyReader/Writer.
>
> I also submitted a JIRA so that this doesn't fall through the cracks:
>
> http://java.net/jira/browse/JAX_RS_SPEC-221
>
>
>
> On 6/27/12 12:19 PM, Bill Burke wrote:
>>
>>
>> On 6/27/12 5:33 AM, Marek Potociar wrote:
>>> The problem is not with the generic entity type - the problem is with
>>> getting the generic callback type information as such so that the
>>> response data can be properly unmarshalled based on the callback generic
>>> type information.
>>>
>>
>> Of course...Which is why we have GenericType for this type of scenario
>>
>>> I didn't want to have all JAX-RS implementations copy the internal
>>> algorithms implemented in the GenericType.
>>
>> Why would they need to do this? Just use GenericType.
>>
>>> So I had to choose between
>>> changing it to an subclass of a GenericType and adding Class<?>
>>> getRawType() and Type getType() methods to the interface and let users
>>> implement it with every single InvocationCallback instance. I chose the
>>> first option as I assume users would not want to spend time implementing
>>> those methods over and over again. I also assume that in most cases the
>>> callback implementation will be an anonymous sub-class. Those few other
>>> cases where the callback would want to inherit from another class can be
>>> resolved by delegation.
>>>
>>> With the change, the type calculation is reused, users don't need to do
>>> anything extra to provide it, and the most common use case scenarios
>>> remain simple. I think this is the most efficient solution. Also, since
>>> the InvocationCallback conveys the response type information, the
>>> solution is also very natural.
>>>
>>
>> I really really disagree. Abstract classes severely constrain your
>> options when class designing so what you are doing is really bad. How
>> would you handle generic types in a regular client request? Answer is,
>> you'd use a GenericType
>>
>> i.e.
>>
>> Response response = client.target("...").request().get();
>> List<Foo> list = response.readEntity(new GenericType<List<Foo>>(){});
>>
>> Why is InvocationCallback a special case? So, do the same thing for
>> InvocationCallback...
>>
>> public class MyCallback implements InvocationCallback<Response>
>> {
>>
>> public void complete(Response response) {
>> List<Foo> list = response.readEntity(new
>> GenericType<List<Foo>>(){});
>> }
>> }
>>
>> Or,
>>
>> public class MyCallback implements InvocationCallback<Response>
>> {
>> private Type type;
>> public MyCallback(Type type)
>> {
>> this.type = type;
>> }
>>
>> public void complete(Response response) {
>> List<Foo> list = response.readEntity(new GenericType(type));
>> }
>> }
>>
>> You're overthinking this... Get some sleep, have a coffee, maybe a
>> snack, kiss your wife, then revisit this problem and you'll see what I
>> mean.
>>
>> Bill
>>
>
> --
> Bill Burke
> JBoss, a division of Red Hat
> http://bill.burkecentral.com
>
>