dev@jsr311.java.net

Re: JSR311: ProviderFactory API needs a bit refactoring?

From: Marc Hadley <Marc.Hadley_at_Sun.COM>
Date: Wed, 07 Nov 2007 08:37:49 -0500

On Nov 7, 2007, at 2:45 AM, Liu, Jervis wrote:
>>
>> Another thing, I wonder if we should define a sort order such
>> that an
>> entity provider that specifies "text/plain" is chosen ahead of an
>> entity provider for the same type that specifies "text/*". I'm not
>> sure how much use it would be but I don't really like the current
>> unspecified order.
>>
> Hasnt this been defined by spec already? Section 3.1.1:
>
> "When choosing an EntityProvider an implementation sorts the
> available providers according to the
> media types they declare support for. Sorting of media types follows
> the general rule: x/y < x/* < */*, i.e. a
> provider that explicitly lists a media types is sorted before a
> provider that lists */*. Quality parameter values
> are also used such that x/y;q=1.0 < x/y;q=0.7."
>
Yes you're right. I thought the spec already covered that but I
couldn't find it when I looked.

Thanks,
Marc.

>>
>> On Nov 6, 2007, at 11:30 AM, Marc Hadley wrote:
>>
>>> 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.
>>>
>>>
>>
>> ---
>> Marc Hadley <marc.hadley at sun.com>
>> CTO Office, Sun Microsystems.
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_jsr311.dev.java.net
>> For additional commands, e-mail: dev-help_at_jsr311.dev.java.net
>>
>
> ----------------------------
> 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.