dev@jsr311.java.net

Re: JSR311: ProviderFactory API needs a bit refactoring?

From: Marc Hadley <Marc.Hadley_at_Sun.COM>
Date: Tue, 06 Nov 2007 11:30:56 -0500

Thanks for bringing this up, we were about to run into a similar
problem fixing issue 20[1] in Jersey. I've created issue 25[2] to
track it.

I agree that we need to tweak the SPI to support selection by media
type and read vs write but I think there's a potential subtle problem
with the method signature you suggest: its possible to obtain an
entity provider that supports a particular media type for read but its
not clear from the API what expectation a user of the entity provider
should have wrt writes. E.g. if I get an entity provider that reads
XML, should I expect that I can use the same provider instance to
write XML also ? I think there are three ways we could approach this:

1. Add warnings to the specification and Javadoc that an
EntityProvider might not support the same media types for read and
write. Pros: simple, keeps everything in one interface. Cons:
potentially confusing, doesn't separate reading and writing concerns,
people don't always read warnings.
2. Require EntityProviders to support the same media types for read
and write. Pros: simple, no need for the factory method to have a read/
write parameter. Cons: restrictive, may not always be possible to read
everything you can write or write everything you can read.
3. Split the EntityProvider SPI into two interfaces (e.g.
EntityReader<T> and EntityWriter<T>),and have two methods in
ProviderFactory (createEntityReader(Class<T>, MediaType). Pros: Keeps
reading and writing separate, possible to write an entity provider
that only does one thing, removes potential confusion since there no
way to try to reuse a writer as a reader or vice verse. Cons: extra
interface and methods, more complex at first glance.

BTW, I don't think there's any need for an array of media types in the
createEntityProvider method: for requests the media type is single
valued, for responses its the responsibility of either the user to
specify the media type (via Response or using ProduceMime) or the
client of the ProviderFactory (the runtime) to select a specific media
type from the list of acceptable types.

Another question is whether EntityProvider needs a supports(MediaType)
method similar to the existing supports(Class<?> ? This could be used
when the Produce/Consume specifies a wilcard type, e.g. "text/*" or
could be used to allow a provider to reject types when parameter
values are not supported ?

Thoughts, opinions ?
Marc.

[1] https://jersey.dev.java.net/issues/show_bug.cgi?id=20
[2] https://jsr311.dev.java.net/issues/show_bug.cgi?id=25

On Nov 6, 2007, at 12:19 AM, Liu, Jervis wrote:

> Hi, It seems to me that the javax.ws.rs.ext. ProviderFactory API
> needs a bit refactoring in order to accommodate a more complex
> EntityProvider searching algorithm. For example, what we have
> currently in ProviderFactory is as below:
>
> public abstract class ProviderFactory {
> public abstract <T> EntityProvider<T>
> createEntityProvider(Class<T> type);
> }
>
> I.e., given a Java type then ProviderFactory returns an instance of
> EntityProvider that supports this Java type. However if we look into
> EntityProvider API, we will find a parameter of Java class is not
> enough for ProviderFactory to identify an EntityProvider to use for
> following reasons:
>
> a). EntityProvider can be annotated with @ProduceMime/_at_ConsumeMime
> and an EntityProvider can support different mime types for produce
> and consume. In this case when we ask ProviderFactory to return us a
> most appropriate EntityProvider, we really need to tell
> ProviderFactory the EntityProvider being requested is used for
> producing or consuming.
>
> b). ProviderFactory also needs to know the mine types of the
> request, this has been clearly stated in the spec, section 3.1.3:
>
> "2. Select the set of EntityProvider classes that support the media
> type of the request,"
>
> Enclosed below is a ProviderFactory I wrote that can return an
> instance of EntityProvider based on three parameters. Let me know if
> this is the intended way to use ProviderFactory and EntityProvider
> APIs.
>
> public class ProviderFactoryImpl extends ProviderFactory {
> public <T> EntityProvider<T> createEntityProvider(Class<T> type,
> String[] requestedMineTypes,
> boolean
> isConsumeMime) {
>
> for (EntityProvider<T> ep : entityProviders) {
> String[] supportedMimeTypes = {"*/*"};
> if (isConsumeMime) {
> ConsumeMime c =
> ep.getClass().getAnnotation(ConsumeMime.class);
> if (c != null) {
> supportedMimeTypes = c.value();
> }
> } else {
> ProduceMime c =
> ep.getClass().getAnnotation(ProduceMime.class);
> if (c != null) {
> supportedMimeTypes = c.value();
> }
> }
>
> if (matchMineTypes(supportedMimeTypes,
> requestedMineTypes) && ep.supports(type)) {
> return ep;
> }
> }
>
> return null;
> }
>
>
> private boolean matchMineTypes(String[] supportedMimeTypes,
> String[] requestedMimeTypes) {
> .
> }
> }
>
> Thanks,
> Jervis Liu
>
> ----------------------------
> IONA Technologies PLC (registered in Ireland)
> Registered Number: 171387
> Registered Address: The IONA Building, Shelbourne Road, Dublin 4,
> Ireland
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_jsr311.dev.java.net
> For additional commands, e-mail: dev-help_at_jsr311.dev.java.net
>

---
Marc Hadley <marc.hadley at sun.com>
CTO Office, Sun Microsystems.