users@jersey.java.net

Re: [Jersey] Polymorphic deserialization of JSON?

From: Craig McClanahan <Craig.McClanahan_at_Sun.COM>
Date: Sat, 09 May 2009 19:43:45 -0700

Chad McHenry wrote:
> 2009/5/9 Felipe Gaścho <fgaucho_at_gmail.com <mailto:fgaucho_at_gmail.com>>
>
> I am doing that.. with subclasses of JPA entities.. it works ..
>
> like that:
>
> http://fgaucho.dyndns.org:8080/footprint-service/user/read/2
> http://fgaucho.dyndns.org:8080/footprint-service/user/edit/2
>
> notice the two service calls reads the same entity from the database,
> but in one path I have a partial view on the entity, while in the
> other path I have the complete representation...
>
>
> Thanks for sharing your code Filipe. As I feared, I'm looking for a
> solution to a different problem.
>
> Using shapes as an example, I would like to be able to send POST and
> PUT messages to a Jersey Resource which accepts a "Shape" as an
> argument, but instead of deserializing a Shape, I would like the
> unmarshaller to recognize the descriminator in the incoming data, and
> deserialize a Circle or Rectangle.
>
> So that I can POST both Circles and Rectangles to the same URL but the
> app will deserialize the correct subtype:
>
> This is what I would _like_ to see, but does not work yet.
>
> class Shape { public String shapeType; }
> class Circle extends Shape { public int radius; }
> class Rectangle extends Foo { public int width; public int height; }
>
> @Path("/shape")
> class ShapeResource {
> ...
> @POST
> public Foo create(Shape shape) {
> log.debug(shape.getClass());
> }
> ....
>
> curl -X POST -H 'Content-type: application/json' \
> -d '{"shapeType":"circle", "radius":33}' localhost/app/shape
> [debug] Circle
>
> curl -X POST -H 'Content-type: application/json' \
> -d '{"shapeType":"rectangle", "width":5,
> "height":3}' localhost/app/shape
> [debug] Rectangle
>
> ====
>
> The issue I see is that by declaring a method that accepts a "Shape",
> the JSON unmarshaller looks only for the properties of shape and
> discards the interesting bits about rectangles and circles - which is
> why I can not use a JAXB @XMLAdapter annotation.
>
> I have considered separate URLs for each subtype, and may have to use
> them if I cannot find a way to unmarshal the subclasses.
>
> @POST
> @Path("/rectangle")
> public Foo createRectangle(Rectangle shape) {
> log.debug(shape.getClass());
> }
>
> @POST
> @Path("/circle")
> public Foo createCircle(Rectangle shape) {
> log.debug(shape.getClass());
> }
>
> curl -X POST -H 'Content-type: application/json' \
> -d '{"shapeType":"circle", "radius":33}' localhost/app/shape/circle
> [debug] Circle
>
> curl -X POST -H 'Content-type: application/json' \
> -d '{"shapeType":"rectangle", "width":5,
> "height":3}' localhost/app/shape/rectangle
> [debug] Rectangle
>
An alternative that will get you RESTful brownie points :-) would be to
use a different media type for a Rectangle versus a Circle. RFC 4288[1]
suggests using "application/vnd.xxxxxxx" for application specific media
types, and coupling that with the notion of adding "+json" or "+xml" to
the media type to indicate the syntax gives you, perhaps, something like
this:

@POST
@Path("/shape")
@Consumes("application/vnd.com.example.shapes.Rectangle+json")
public Foo createRectangle(Rectangle shape) {
    ...
}

@POST
@Path("/shape")
@Consumes("application/vnd.com.example.shapes.Circle+json")
public Foo createCircle(Circle shape) {
    ...
}

You can keep a discriminator in the representation if you want, but are
not required to have one since the media type performs the same role.

Craig McClanahan

[1] http://tools.ietf.org/html/rfc4288
>
>
>
>
> I am trying to finish the articles about that.. despoite the flu and
> the time :) eheh
>
> Meanwhile, you can checkout my code from footprint:
>
> svn checkout https://footprint.dev.java.net/svn/footprint/trunk
> footprint --username guest
> cd footprint
> mvn clean install
>
> and then you have the EAR file in the footprint-service/target
> folder.. just start the database, the glassfish and then deploy this
> ear....
>
> and keep asking here if you like the solution and if you have
> questions about it......
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> <mailto:users-unsubscribe_at_jersey.dev.java.net>
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
> <mailto:users-help_at_jersey.dev.java.net>
>
>