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

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

On 4/26/07, Marc Hadley <> 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

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

> 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.