users@jersey.java.net

[Jersey] Re: Question about MessageBodyReader interface

From: Tatu Saloranta <tsaloranta_at_gmail.com>
Date: Thu, 18 Apr 2013 08:44:45 -0700

On Wed, Apr 17, 2013 at 11:10 PM, George Cao <matrix3456_at_gmail.com> wrote:

> I really want to do is define the provider for self-defined media type,
> let's say application/x-protobuf, so I need to provide the implementations
> of MessageBodyReader or messageBodyWriter to make it work. This is the per
> application/x-protobuf provider, right?
>
>

Yes.



> This provider should read subclasses of MessageLite from the input stream.
> MessageLite is the super class of all protobuf generated entities. But the
> subclasses are open-ended.
>
> So I guess I have three options to implement the provider as following
>
> class ProtobufReaderProvider implements MessageBodyReader<Object>
> class ProtobufReaderProvider implements MessageBodyReader<MessageLite>
> class ProtobufReaderProvider implements MessageBodyReader
>
> At the runtime, I want to de-serialize a concrete class, say Message which
> defined as
>
> class Message implements MessageLite;
>
> Then Message.class cannot applied to any of the required Class<T> type
> parameter in the readFrom method argument list of the three possible
> implementations.
>
> Did I missed something? Please help!
>
>

Class<T> is just compiler-usable syntactic sugar; and is type-erased during
runtime. So the only problem is that you may need to add some casting,
depending on what type parameter you chose. The way JAX-RS implementations
handle MBR/MBW is dynamic, i.e. equivalent to assuming they all have '?'
(or Object) as type parameter.
Class parameter is there for your own use (to know what to deserialize).
And I think that it probably should have been left as Class<?>; but I don't
know the history for how signatures were chosen (my guess: just seemed like
the right thing to do at the time -- has happened to me occasionally).

So typically I have used `Object` as type parameter. It does not matter
much either way, but at least does not require even more casts. All of the
choices would, however, work since no casts are added. There is difference
here between, say:

   public void method1(T value) { ... }
   public void method2(Class<T> value) { ... }

because in the first case, compiler will add casts to wherever 'value' is
used; but NOT for the second case: due to type erasure, there is nothing to
cast. There is absolutely no runtime difference induced by different type
parameterization.

Does this make more sense?

-+ Tatu +-



>
>
>
>
> 2013/4/18 Tatu Saloranta <tsaloranta_at_gmail.com>
>
>> No. Typically you do not implement MessageBodyReaders or -Writers
>> yourself, but they are either provided by Jersey (or other JAX-RS
>> implementations), or external providers. These are usually per-dataformat
>> (JSON, XML etc) providers.
>> It could be argued that type parameter for these types is useless... it
>> really does not buy much anything, since JAX-RS dispatchers need dynamic
>> handling and end up casting things anyway.
>>
>> -+ Tatu +-
>>
>>
>> On Wed, Apr 17, 2013 at 9:00 PM, George Cao <matrix3456_at_gmail.com> wrote:
>>
>>> Hi All,
>>> I am using Jersey framework 1.17 for my RESTful servces.
>>>
>>> But I got a question about the design of the MessageBodyReader interface.
>>>
>>> public interface MessageBodyReader<T> {
>>> boolean isReadable(Class<?> type, Type genericType,
>>> Annotation annotations[], MediaType mediaType);
>>>
>>> T readFrom(Class<T> type, Type genericType,
>>> Annotation annotations[], MediaType mediaType,
>>> MultivaluedMap<String, String> httpHeaders,
>>> InputStream entityStream) throws IOException,
>>> WebApplicationException;
>>>
>>> }
>>>
>>> Seems that we need write exactly one MessageBodyReader implementation
>>> per Class because of the type parameter T of the readFrom method argument
>>> list, right?
>>>
>>> The problem here is that Class<S> or Class<?> cannot assigned to
>>> Class<T>, even though S is a subclass of T.
>>>
>>> So I am wondering how to write a MessageBodyReader that can read all the
>>> classes that are subclasses of one specific class C instead write lots of
>>> concrete implementations?
>>>
>>
>>
>