4

I use a RESTful Web Service. In this web service I must pass a bean that I want to save as a parameter.

Here is the server code:

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Unidade inserir(Unidade unidade){
    Session s = ConnectDb.getSession();
    try {
        s.getTransaction().begin();
        s.save(unidade);
        s.getTransaction().commit();
        return unidade;
    } catch (Exception e) {
        e.printStackTrace();
        s.getTransaction().rollback();
        return null;
    } finally {
        s.close(); 
    }
}

I have the following code in the client:

ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource webResource = client.resource("http://localhost:8080/RestauranteWeb/rest/unidades/7");
Builder builder = webResource.accept(MediaType.APPLICATION_JSON); 
GenericType<Unidade> genericType = new GenericType<Unidade>() {};

Unidade u = new Unidade();
u.setUnidSigla("KG");
//How to pass this bean as parameter?

Unidade response = builder.post(genericType);
System.out.println(response);

How can I pass the bean to the method as a parameter?

asteri
  • 11,402
  • 13
  • 60
  • 84
Mateus Viccari
  • 7,389
  • 14
  • 65
  • 101

4 Answers4

3

Using Jackson as a Serializer/DeSerializer

If your Unidade object is annotated with Jackson and/or a Deserializer is registered then you should be able to POST with a BODY that contains the JSON representing the Unidade object. It should be magically deserialized and rebuilt as an object on the server side.

Important

Make sure that you add a Content-Type header in the POST request with a value of application/json. Without this header your Jersey might not know what to do with the body.

You would use the Jackson ObjectMapper to serialize your Unidade object to JSON and send that instead of whatever that GenericType stuff is.

I have both Jersey and RESTEasy implementations that work seamlessly with Jackson in this manner.

Community
  • 1
  • 1
  • But how can i do it using the code above? Or shouldn't i use the Jersey api for the client? – Mateus Viccari Jul 23 '13 at 20:42
  • I am using a the latest version of Apache Commons `HTTPClient` because the Jersey client is single threaded and has some other limitations I don't want to work around. –  Jul 23 '13 at 20:46
2

How can I pass the bean to the method as a parameter?

Checkout the documentation for the post method:

 /**
 * Invoke the POST method with a request entity that returns a response.
 * 
 * @param <T> the type of the response.
 * @param c the type of the returned response.
 * @param requestEntity the request entity.
 * @return an instance of type <code>c</code>.
 * @throws UniformInterfaceException if the status of the HTTP response is 
 *         greater than or equal to 300 and <code>c</code> is not the type
 *         {@link ClientResponse}.
 * @throws ClientHandlerException if the client handler fails to process
 *         the request or response.
 */
<T> T post(Class<T> c, Object requestEntity) 
        throws UniformInterfaceException, ClientHandlerException;

The method takes two parameters. First parameter is the expected response type, and second one is the entity which is going to be put in the request body.

What happens here, when performing the request Jersey would serialize the object passed as a request entity into the JSON string (hence you've set the header - accept(MediaType.APPLICATION_JSON)). When the response from the server arrives, Jersey will deserialize it (the inverted process as in case of requestEntity) and return you the object.

And what if my method receives more than 1 parameter? Because the post method only acepts 1

Well you cannot do it with JAX-RS, and it makes little sense actually. You can pass multiple parameters to the method as @PathParam or a @MatrixParam, but there can be only one associated with the body (well you have only one body in our request, right?). Checkout answer to this question and checkout how to use @PathParam or @MatrixParam

Let's suppose instead of returning a "Unidade" class, my method returns a String. So, it will receive a "Unidade" as parameter and return a "String". How can i retrieve it in this case, passing the "Unidade" instance as before?

I believe you could achieve that with post(String.class, unidadeInstance). The first parameter doesn't have to be the same as the second. It's valid to accept one parameter and return another. It is even valid to take a parameter and return nothing in the body (like you have done it in the code attached to your question). You could accept the body and send back response containing status 201 Created and Location header entry pointing to the URL of the newly created resource.

Community
  • 1
  • 1
lpiepiora
  • 13,659
  • 1
  • 35
  • 47
1

Not sure what's your purpose for GenericType. Anyway, try the code below.

ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
Unidade u = new Unidade();
u.setUnidSigla("KG");
WebResource webResource = client.resource("http://localhost:8080/RestauranteWeb/rest/unidades/7");
Unidade response = webResource.accept(MediaType.APPLICATION_JSON)
                          .type(MediaType.APPLICATION_JSON)
                           .post(Unidade.class, u);
ramirezag
  • 554
  • 5
  • 9
  • Well, it works! But i don't understand exactly where you define the request and where you define the response(the method's parameter and the method's return). Let's suppose instead of returning a "Unidade" class, my method returns a String. So, it will receive a "Unidade" as parameter and return a "String". How can i retrieve it in this case, passing the "Unidade" instance as before? – Mateus Viccari Jul 24 '13 at 16:11
  • And what if my method receives more than 1 parameter? Because the post method only acepts 1. – Mateus Viccari Jul 24 '13 at 16:20
0

I'm not sure if it helps but i had a similar problem. My scenario was i need a webservice which had to receiver a bunch of values which are organized as a kind of profile. But this service has to handle that there are comming more profiles where still old clients using the service. The interface had to be as static as possible.

Our solution is very simple. We only post a single text field as content of the post. But this includes the serialized state of an profile object in JSON. Pseudo code:

public class Profile1 {
  ...

  public String asJSON() {
    JSONObject obj = new JSONObject();
    obj.put("profileAtr1", profileAtr1);
    ...
    return obj.toString()
  }
}

formParams.put("profile", profile.asJSON());
client.post(formParams);

This way it's not automaticly deserialized but it's easy to do it by hand. We do this with a generic Profile object which can be created out of JSON String in the constructor. Pseudo code:

public GenericProfile {
  public GenericProfile(String json) {
    JSONObject obj = new JSONObject(json);
    String profileName = obj.getString("profileName");

    if (profileName.equals("Profile1") {
      this = new Profile1(obj);   // I know this is not working ;) My impl. is a litle bit more complecated as that. I think i use a static method in the generic profile to create an instance i need.
    } ...
  }
}

And then in your webservice only have this one form param to handle and to deserialize ;) Pseudo code:

public ResponseEnvelope coolServiceFunction(@FormParam("profile") String profileData) {
  GenericProfile profile = new GenericProfile(profileData);

  if (profile instanceof Profile1) {
    do what you want
  }
}

Sorry for the pseudo code, but i had alleady shutdown my dev vm and have no access to any repository any more :( I think the biggest benefits from this solution is: 1. It can transport anything you can pack in JSON. I transfer BASE64 encoded binary blocks and heavyly encrypted textdata this way. 2. The easiest tutorial example of your REST Framework of the POST Service will provide all you need to do this. 3. You can be sure that your interface will stay for a long period of time.

Hope that helps

Rene M.
  • 2,660
  • 15
  • 24