dev@jsr311.java.net

Re: Proposal for rework of spi package (was Re: "Dual dispatch")

From: Dhanji R. Prasanna <dhanji_at_gmail.com>
Date: Thu, 26 Apr 2007 20:26:05 +1000

On 4/26/07, Marc Hadley <Marc.Hadley_at_sun.com> wrote:
>
> On Apr 21, 2007, at 12:44 PM, Marc Hadley wrote:
> >
> >> I would favor the registry of externalizers discussed in another
> >> thread (registration with annotations), something like:
> >>
>
This would allow
> us to drop the ServiceFinder, ServiceConfiguration,
> TypeStreamingFactory and HeaderFactory classes from the API.


Big ++.


> @UriTemplate("/things/{thing_id}")
> public class ThingResource {
>
> public Thing(@UriParam("thing_id") String id) {...}
>
> @HttpMethod
> Thing get() {...}
> }


Off-topic, I would like to see @HttpMethod(GET) rather than a magic
method-name.

and a TypeStreamingProvider for Thing
>
> @Externalizer(classes={Thing.class}, type="application/thing")
> public class ThingExternalizer implements
> TypeStreamingProvider<Thing.class> {


Is there a case for multiple mediatypes too? for example:

@Externalizer(entity = Thing.class, mediaType = { "text/html", "text/xhtml"
})

I can see this being quite useful.
(note that you dont need braces {} when referring to a single element, it is
autoboxed into an array)

   Thing readFrom(Class<Thing> type, MediaType mediaType,
> MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
> throws IOException {
> ...
> }
>
> void writeTo(Thing t, MediaType mediaType, MultivaluedMap<String,
> String> httpHeaders, OutputStream entityStream) throws IOException {
> ...
> }
> }


Just a lateral suggestion, but I'd like to use java "over-the-wire"
terminology for the aforementioned methods:
- marshall/unmarshall
- serialize/deserialize
- readExternal/writeExternal

 The
> advantage is that the specification wouldn't need to tie down the
> method used as is currently the case with ServiceFinder.


+1. I think service location patterns belong with the dodo (and I don't mean
here in Australia =)

One downside I see is that this approach splits the metadata between
> two classes - you can't tell just by looking at the ThingResource
> class what media types are supported since that information is
> contained in the set of TypeStreamingProviders.


Yea I did think about this quite a bit before posting the @Externalizer
suggestion. There are a few solutions:

- Expose registered externalizers via a global injectable registry
(@Externalizers Map<Class<?>, Class<? extends TypeStreamingProvider>)
- Force annotation of the resource type with an @Externalizer (explicit
hook). This has the advantage of being able to override default
externalizers on a per-URI or per-method basis. And the disadv of being
un-enforceable and possibly violating Least Surprise (if the annotation is
unintentionally omitted).
- Don't worry about it--they are disparate concerns

However it does
> separate the two concerns nicely so you could add support for an
> additional format just by dropping in a new TypeStreamingProvider.


We would have to be *very* careful about implicit overrides, registration
order on overlapping keys, dual registrations to the same keys, etc.


> The specification would define a set of externalizers that an impl
> would be required to implement so an application only needs to add
> externalizers for custom types.


Good call. It might be worthwhile to start another thread listing what
externalizers we should require out of the box.

Dhanji.