Hi Benson
In MessageBodyWriter.writeTo() it's actually Class<?> which is in the
signature. And there's no return value.
We could've implemented just MessageBodyWriter as opposed to MessageBodyWriter<Object> but it would stiill cause warning in the user
test code....
I can agree that implementing MessageBodyWriter<Object> delegates the type-safety checks to the actual provider and thus makes that
<T> thing useless. But for providers choosing to implement MessageBodyWriter<Book> the runtime will now ensure the class of the
object to be written is assignable to Book.class (now that we've implemented the message body provides sorting requirement from
JAXRS 1.1).
Please don't get me wrong, may be it would be the best option indeed to go ahead with passing Object.class
MessageBodyWriter<Object> - but I'm afraid it will turn the bunch of user providers out there broken...
thanks, Sergey
----- Original Message -----
From: "Benson Margulies" <[email protected]>
To: <[email protected]>
Sent: Monday, September 07, 2009 1:06 PM
Subject: Re: JAX-RS and generics
Sergey,
With Java generics, there's a pattern:
<T> public T gloop(Class<T> type, whatever)
That pattern requires that you pass in the class of what you expect to get
out.
If XXXProvider implements MessageBodyReader<T>, then it must have a
implement the read API against the same T. You can't, legitimately, cast it
to MessageBodyReader<Book>.
So, if AegisProvider implements MessageBodyReader<Object>, and you want to
write clean code that does not get warnings, you have to write:
Object o = p.read(Object.class, ...)
If it implements MessageBodyReader<T>, you then AegisProvider<Book> does
Book b = p.read(Book.class, ...)
Now, if the people who invented JAX-RS have decided to ignore this pattern
and force us to write code that needs @SuppressWarning("unchecked"), well,
I'm sad but I'll stop sending email. Since my generic AegisProvider passes
tests, however, ...
On Mon, Sep 7, 2009 at 5:50 AM, Sergey Beryozkin <[email protected]>wrote:
https://jsr311.dev.java.net/nonav/javadoc/javax/ws/rs/ext/MessageBodyWriter.html#writeTo(T,%20java.lang.Class,%20java.lang.reflect.Type,%20java.lang.annotation.Annotation[],%20javax.ws.rs.core.MediaType,%20javax.ws.rs.core.MultivaluedMap,%20java.io.OutputStream)<https://jsr311.dev.java.net/nonav/javadoc/javax/ws/rs/ext/MessageBodyWriter.html#writeTo%28T,%20java.lang.Class,%20java.lang.reflect.Type,%20java.lang.annotation.Annotation%5B%5D,%20javax.ws.rs.core.MediaType,%20javax.ws.rs.core.MultivaluedMap,%20java.io.OutputStream%29>
type - the class of object that is to be written.
So I don't think we should pass Object.class for MessageBodyWriter<Object>.
If one would like to avoud doing casts during testing then it should be just
MessageBodyWriter<Book> and I'm pretty sure the runtime will pass
Book.class.
Cheers, Sergey
On Sat, Sep 5, 2009 at 1:57 PM, Benson Margulies <[email protected]
>wrote:
JAX-RS defines two fundamental interfaces: MessageBodyReader<T> and
MessageBodyWriter<T>, and providers implement.
I claim that GENERIC providers that work for any object (like those
corresponding to data bindings) should, themselves, be GENERIC, and
implement MessageBodyX<T>, not MessageBodyX<Object>.
Allow me to modulate this claim. I thought about it some more.
If you want to define a class as 'implements MessageBodyX<Object>', fine.
However, the right thing to pass to the Class<T> argument will ALWAYS be
Object.class. If you want to cue in the code to the sort of object in
flight, use the Type argument further down the parameter list.
I claim this because the whole API structure of MessageBodyX assumed
this.
It uses Class<T> in a way that requires constant
@SupressWarnings("unchecked") if the base is MessageBodyX<Object>.
To put my money where my mouth is, as it were, I implemented this for the
Aegis providers. When I did this, I discovered that the JAX-RS runtime
code
couldn't handle generic type providers. When the provider type is, say,
AegisElementProvider<Book>
then implemented interface comes up as MessageBodyReader<T>, not
MessageBodyReader<Book>. So it is a TypeVariable, not a class or a
ParameterizedType.
I fixed the provider selection code to cope, but I didn't write the
additionally complex code to look at bounds and insist that if there is a
bound the type at hand be within it.