users@jersey.java.net

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

From: Rabick, Mark A (MS) <"Rabick,>
Date: Wed, 25 Feb 2009 11:08:07 -0600

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

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?

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