1

I'm trying to find a way to create a service that will receive different object types as JSON and unmarshall them correctly. Until now I was able to achieve single or list object unmarshalling using a custom deserializer and google's gson library but this is really limiting. The only types of services I can create using this can only have a single type of object as a parameter, like so:

@GET
@Path("myService")
@Consumes(MediaType.APPLICATION_JSON)
public Response myService(MyEntity entity) {
    //Random stuff using entity
    return Response.ok().build();
}

However I'm trying to create a service like so:

@GET
@Path("advancedService")
@Consumes(MediaType.APPLICATION_JSON)
public Response advancedService(MyEntity1 entity1, MyEntity2 entity2, @QueryParam("normalParam") int normalParam, @QueryParam("normalBoolean") boolean normalBoolean) {
    //Do stuff using both entity1 and entity2.
    return Response.ok().build();
}

Right now, when I send a JSON through an ajax request, in order for the service to understand the object structure it must be formatted like so:

$.ajax({
    url: 'services/MyServices/myService',
    type: 'GET',
    data: JSON.stringify(myEntityObjectStructure),
    contentType: 'application/json; charset=UTF-8',
    dataType: 'json',
    success: function (result, status, xhr) {
      //blahblah
    }
  });

In the data configuration it needs to read the object structure only, otherwise it gets confused. I'm trying to send a request like this:

$.ajax({
    url: 'services/MyServices/myService',
    type: 'GET',
    data: {
        myEntity1: JSON.stringify(myEntity1ObjectStructure),
        myEntity2: JSON.stringify(myEntity2ObjectStructure),
        normalParam: param1,
        booleanParam: param2
    },
    contentType: 'application/json; charset=UTF-8',
    dataType: 'json',
    success: function (result, status, xhr) {
      //blahblah
    }
  });

But it just won't read the param names and it gets stuck since it thinks it must unmarshall all of the data structure into a single object.

I'm using jersey 2.19. Also I'm looking for a normal solution not a 'hacky' one. I could just as well send the objects as a 'String' and unmarshall it myself but I want to stick to the service standards using annotations and having a custom serializer or some type of web.xml configuration that takes care of the (un)marshalling. I like using gson for its simplicity (especially with date formats and not requiring annotations for field exclusion etc) but I'm open to use Jackson as well.

EDIT: It can also be a POST type of service, I just need it to have 2 different classes as parameters.

PentaKon
  • 4,139
  • 5
  • 43
  • 80

1 Answers1

0

The most beautiful solution in my opinion is to create a parent object, containing everything you want to transport.

@XmlRootElement
class AdvancedServiceInput {
    public MyEntity1 entity1;
    public MyEntity2 entity2;
}

Then receive data by accepting the container objects:

@GET
@Path("advancedService")
@Consumes(MediaType.APPLICATION_JSON)
public Response advancedService(AdvancedServiceInput input, @QueryParam("normalParam") int normalParam, @QueryParam("normalBoolean") boolean normalBoolean) {
    //Do stuff using both input.entity1 and input.entity2.
    return Response.ok().build();
}

What makes this solution beautiful:

  • In general less parameters improves readability. Having a method with lots of parameters makes it difficult to identify, which parameter is used for which perpose. (especially, because java does not allow named parameters)
  • Having a container makes your code easier to extend. If you want to add a third entity-type, you can just extend your container class and you don't have to change (lots of) method signatures.
  • XML and JSON content is supposed to only contain one, single root element. So you might have to use this approach anyways to create valid transport messages.
slartidan
  • 20,403
  • 15
  • 83
  • 131
  • As I said I'm not looking for 'hacky' solutions. Clunking my project with random objects just to work around a problem isn't a solution. As I said I can achieve what I'm looking for using a json string but that's not the point of the question. Is it even possible to have 2 different types of objects in a single service method??? – PentaKon Jul 26 '15 at 14:29
  • @Konstantine This is the most beautiful solution I can imagine. But let's have a look - maybe someone else posts an even more beautiful answer. – slartidan Jul 26 '15 at 14:38
  • Well apparently as seen from the duplicate post, services are not meant to receive different types of objects. Gonna have to find a way to bypass that limitation... – PentaKon Jul 27 '15 at 06:28