users@jersey.java.net

Re: [Jersey] Resource and XML Schema versioning...

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Thu, 26 Feb 2009 09:22:52 +0100

On Feb 25, 2009, at 6:08 PM, Rabick, Mark A (MS) wrote:

>> As far as the URI-based content negotiation, are you suggesting I
>> could couple the URI 'versioning' (../v1/...) in addition to custom/
>> specific media types when the client can't send an "Accept:
>> application/foo-vi?
>>
>
> I think a suffix is better e.g. ".foo-v1" or ".foo-v2". Then it is
> easier to use existing Jersey functionality or write your own filter.
>
> Are you talking about a suffix in a URI fragment? For example, if I
> have 2 versions of 'Foo' JAXB objects.
>

A suffix at the end of the URI path, but not part of the application
and @Path.


> Ie. http://host:8080/fooapplication/foo.foo-v1/
>
> public class FooV1Resource {
>
> @GET @Path("/foo.foo-v1/{id}")
> @Produces("application/foo-v1")
> public FooV1(String @PathParam("id") String fooId) {
>
> FooV2 foo2 = FooDatabase.getFooById(fooId);
> FooV1 foo1 = convertFoo2ToFoo1(foo2)
> return foo1;
> }
> }
>
> Ie. http://host:8080/fooapplication/foo.foo-v2/
>
> public class FooV2Resource {
>
> @GET @Path("/foo.foo-v2/{id}")
> @Produces("application/foo-v2")
> public FooV2(String @PathParam("id") String fooId) {
> FooV2 foo2 = FooDatabase.getFooById(fooId);
> return foo2;
> }
> }
>
> With the appropriate ContextResolvers based on the media types, of
> course...
>
> What 'existing Jersey functionality' are you referring to that
> suffixes would help with?
>

See:

https://jersey.dev.java.net/source/browse/*checkout*/jersey/tags/
jersey-1.0.2/api/jersey/com/sun/jersey/api/core/
ResourceConfig.html#getMediaTypeMappings()

Paul.


> -----Original Message-----
> From: Paul Sandoz [mailto:Paul.Sandoz_at_Sun.COM]
> Sent: Wednesday, February 25, 2009 3:23 AM
> To: users_at_jersey.dev.java.net
> Subject: Re: [Jersey] Resource and XML Schema versioning...
>
>
> On Feb 24, 2009, at 4:08 PM, Rabick, Mark A (MS) wrote:
>
>> Paul/Craig,
>>
>> Thanks for the great suggestions:
>>
>>> Once you have the media types it is possible if you wish to support
>>> URI-based content negotiation if the client cannot send an accept
>>> header.
>>
>>> JAX-RS has support for resolving JAXBContext for media type and Java
>>> type. See the ContextResolver [1].
>>
>>> Thus you could do:
>>
>>> @Provider
>>> @Produces("application/foo-v1")
>>> public class Verson1ContextResolver implements
>> ContextResolver<JAXBContext> {
>>> public JAXBContext getContext(java.lang.Class<?> type) {
>>> ...
>>> }
>>> }
>>
>>
>>> I am not sure of the exact details of supporting two different
>>> serializations from the same object. IMHO it seems, without
>>> understanding too much about your use-case, easier to keep new and
>> old
>>> versions separate (different packages). That way you do not have to
>>> work out backwards dependencies, plus think about the case when you
>>> require 3 versions etc.
>>
>> As far as the URI-based content negotiation, are you suggesting I
>> could couple the URI 'versioning' (../v1/...) in addition to custom/
>> specific media types when the client can't send an "Accept:
>> application/foo-vi?
>>
>
> I think a suffix is better e.g. ".foo-v1" or ".foo-v2". Then it is
> easier to use existing Jersey functionality or write your own filter.
>
>> Second, the generated application.wadl just indicates on methods that
>> return application/xml:
>>
>> <response>
>> <representation mediaType="application/xml"/> </response>
>>
>> How can I get the JAXB context to genarate an XSD for each schema
>> (v1,v2)
>>
>
> You will require two separate JAXB packages corresponds to the
> beans of each schema. Then you can use the JAXB compilation tools,
> xjc.
>
>> and get the wadl to include corresponding XSD in the generated
>> response element in the wadl?
>>
>
> See here:
>
> http://wikis.sun.com/display/Jersey/WADL
> http://wikis.sun.com/display/Jersey/
> SupportedJavadocTagsForExtendedWADL
>
>
>>> I am not sure of the exact details of supporting two different
>>> serializations from the same object. IMHO it seems, without
>>> understanding too much about your use-case, easier to keep new and
>> old
>>> versions separate (different packages).
>>
>> Unfortunately, I don't have specific use-case scenarios yet, just a
>> requirement to preserve backward compatibility for legacy service
>> clients... even though we don't have any 'legacy' clients yet (no
>> actual clients yet), so I'm trying to at least architect my service
>> framework to better support that in the future. The short of if is
>> that I have 1 set of persistence objects (entity beans) at any given
>> time in the most recent version. If I embed JAXB (javax.xml.bind)
>> annotations in those persistence objects, lets just focus on 1 right
>> now (Foo.java). If it has an attribute:
>>
>> @XmlElement(required=true) protected String fooName; (v1)
>>
>> <ns2:foo>
>> ...
>> <fooName>Name</fooName>
>> ...
>> </ns2:foo>
>>
>> A simple case might be a change to:
>>
>> @XmlElement(required=true) protected String fooFullName; (v2)
>>
>> <ns2:foo>
>> ...
>> <fooFullName>Name</fooFullName>
>> ...
>> </ns2:foo>
>>
>> At deployment time, I only have the (v2) annotated Foo.java, but I
>> need to support clients that could ask for v1 schema bound Foo
>> objects.
>>
>
> Then you need to keep the old JAXB objects around. I strongly
> recommend not trying to retain one set of JAXB objects that support
> many versions as you are going to make things very difficult for
> yourself. You simply do not know what might change in the future and
> having to retain 'n' number of changes with one JAXB view will make it
> rally hard on the developer to know what is going on.
>
> If you essentially "fork" your JAXB objects when you need to make a
> backwards incompatible changes and add a new media type it becomes
> much easier for you to manage.
>
> Another alternative is to "fork" your application as Kevin suggests.
>
>
>> The XmlElement annotation processing would use the attribute's
>> name as the xml element. That was my question about an external
>> JAXB configuration? I need the Foo.java to talk to our hibernate
>> JPA based DAOs and that is the object that I get returned from our
>> JPA/DB calls. I would need to produce output in foo-v1.xsd AND foo-
>> v2.xsd. Would you recommend a 'transfer object' pattern and based
>> on URI and accept header negotiation, keep multiple versions of Foo
>> for use by Jersey? That is, I would have to write a façade of sorts
>> to map the incoming foo-v1.xsd requests to Foo.java and then back
>> from Foo.java to foo-v2.xsd with annotated FooV1.java and FooV2.java
>> classes that reflect the different 'versions' of Foo?
>>
>
> I would recommend keep two separate packages for each JAXB version.
>
> com.beans.v1.Foo
>
> com.beans.v2.Foo
>
> And dealing with v1.Foo and v2.Foo in separate resource methods. The
> logic to map the v1 or v2 Foo instances to the database can also be
> associated with the version. That way you keep things very clean and
> isolated. I think it is an implementation detail if v2 shares logic
> from v1 for certain cases, but i would not necessarily assume that or
> let that assumption influence your architecture because you simply do
> not know what changes you might have to make. To quote the grizzled
> Rumsfeld, change is a "known unknown".
>
> Paul.
>> Thanks again for all of your hard work and prompt responses!
>>
>> --mark
>>
>> _______________________________________________
>> Mark A. Rabick
>> Software Engineer
>> Em: mark.rabick_at_ngc.com
>>
>