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:
>>
>> @URITemplate(...)
>> @Externalizer(Class<T>, Class<? extends
>> TypeStreamingProvider<T>>) //example psuedo-signature
>> public class InvoicesService {
>> //..
>> }
>>
> An annotation approach could also be good, in fact an annotation
> could be used to generate the ServiceFinder configuration files
> during apt processing.
>
Thinking about this some more I think we could rework the sketch2 spi
package quite a bit using these ideas (annotation based serializer
generation and including media type as a key). As several people have
commented I think this will make it less of an SPI so we should
consider renaming the package or merging it into one of the other
packages.
Rather than configure TypeStreamingProviders in a config file as
described in the ServiceFinder Javadoc we could instead use an
annotation on the TypeStreamingProvider impl class. This would allow
us to drop the ServiceFinder, ServiceConfiguration,
TypeStreamingFactory and HeaderFactory classes from the API.
Here's an example of how it could work, suppose you have a domain
class Thing and you want to exchange serializations of it using media
type "application/thing". You write a resource class that exposes the
appropriate methods:
@UriTemplate("/things/{thing_id}")
public class ThingResource {
public Thing(@UriParam("thing_id") String id) {...}
@HttpMethod
Thing get() {...}
}
and a TypeStreamingProvider for Thing
@Externalizer(classes={Thing.class}, type="application/thing")
public class ThingExternalizer implements
TypeStreamingProvider<Thing.class> {
boolean supports(Class<?> clazz, MediaType type) {
return true; // always true since annotation above defines both
class and type statically
}
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 {
...
}
}
An implementation can use an annotation processing tool to gather a
list of TypeStreamingProviders during processing and generate
whatever artifacts the impl needs to find the classes at runtime. The
advantage is that the specification wouldn't need to tie down the
method used as is currently the case with ServiceFinder.
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. However it does
separate the two concerns nicely so you could add support for an
additional format just by dropping in a new TypeStreamingProvider.
For more generic entity types like JAXB objects you could build a
general purpose externalizer that would support any JAXB class like
this:
@Externalizer // no properties since set of classes and media types
is open
public class JAXBExternalizer implements
TypeStreamingProvider<Object.class> {
boolean supports(Class<?> clazz, MediaType type) {
if (isJAXBClass(clazz)) // e.g. look for @XmlRootElement on class
return true;
return false;
}
Object readFrom(Class<Object> type, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException {
...
}
void writeTo(Object t, MediaType mediaType, MultivaluedMap<String,
String> httpHeaders, OutputStream entityStream) throws IOException {
...
}
}
For truly generic types like String you can build an externalizer
like this:
@Externalizer(classes={String.class})
public class JAXBExternalizer implements
TypeStreamingProvider<String.class> {
boolean supports(Class<?> clazz, MediaType type) {
return true; // always true since can serialize any string
regardless of media type
}
String readFrom(Class<String> type, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException {
...
}
void writeTo(String t, MediaType mediaType, MultivaluedMap<String,
String> httpHeaders, OutputStream entityStream) throws IOException {
...
}
}
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.
Thoughts, comments ?
Marc.
---
Marc Hadley <marc.hadley at sun.com>
CTO Office, Sun Microsystems.
- application/pkcs7-signature attachment: smime.p7s