Search code examples
javarestjersey-2.0jaxb2

REST Client InboundJaxrsResponse Status 500 , when attempting to POST


Issue 1. I'm getting a Http Status 500, when I'm setting the Todo object with the Todo constructor. It works fine for an existing value set in the TodoDao. What is that I'm missing here ?( please find the code and stack trace below ) :

Issue 2. I'm attempting to set and the form param as follows, but i'm unable to resolve the following compilation error :

> The method post(Entity<?>, Class<T>) in the type SyncInvoker is not
> applicable for the arguments (Class<Form>, Form)

Code snippet setting the form :

Form form = new Form();
                    form.param("id","45");
                    form.param("summary","Summary for id 45");
                    response =         target.path("rest").path("todos").path(todo.getId()).request()
                  .accept(MediaType.APPLICATION_FORM_URLENCODED).post(Form.class,form);

Stacktrace : `

Response Code is : 500
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><todoes><todo><description>Rest todo Description 2 </description><id>2</id><summary>Summary 2 - REST</summary></todo><todo><description>Rest todo Description 1</description><id>1</id><summary>Summary 1 - REST</summary></todo><todo><id>45</id><summary>Summary for id 45</summary></todo></todoes>

Post response200

`

TodosResourceClient.java

package com.dcr.jersey.client;



import java.net.URI;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.Form;

import org.glassfish.jersey.client.ClientConfig;


import com.dcr.jersey.jaxb.model.Todo; 

public class TodosResourceClient {


    public static void main(String[] args) {
        ClientConfig config = new ClientConfig();
        Client client = ClientBuilder.newClient(config);
        WebTarget target = client.target(getBaseURI());

        Todo todo = new Todo("38","38 - Summary ReEntred");

        target.path("rest").path("todos").request().post(Entity.json(todo));

        Response response = target.path("rest").path("todos").path(todo.getId()).request()
                .accept(MediaType.APPLICATION_XML).get(Response.class);

        System.out.println("\n POST Response Code is : "+ response.getStatus());



       System.out.println(target.path("rest").path("todos").path(todo.getId()).request()
                        .accept(MediaType.APPLICATION_JSON).get(Response.class)
                        .toString()+"\n");

    System.out.println(target.path("rest").path("todos").request()
                        .accept(MediaType.APPLICATION_JSON).get(String.class)+"\n");

    System.out.println(target.path("rest").path("todos").request()
                        .accept(MediaType.APPLICATION_XML).get(String.class)+"\n");

    System.out.println(target.path("rest").path("todos/34").request()
                        .accept(MediaType.APPLICATION_JSON).get(String.class)+"\n");


                //target.path("rest").path("todos/38").request().delete();

                System.out.println(target.path("rest").path("todos").request()
                        .accept(MediaType.APPLICATION_XML).get(String.class)+"\n");

                Form form = new Form();
                form.param("id","45");
                form.param("summary","Summary for id 45");
                response = target.path("rest").path("todos").request().post(Entity.form(form));

                System.out.println("\nPost by FORM response code is "+ response.getStatus()+"\n");

                response = target.path("rest").path("todos/45").request().delete();// deletes a request

                System.out.println("\nDelete by FORM response code is "+ response.getStatus()+"\n");


    }
    private static URI getBaseURI() {

        return UriBuilder.fromUri("http://localhost:8080/com.dcr.jersey.first").build();

      }

}

Todo.java

package com.dcr.jersey.jaxb.model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement

public class Todo {

    private String id;
    private String summary;
    private String description;
    public Todo(){}
    public Todo(String id,String summary){
        this.id=id;
        this.summary=summary;

    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }

    public String getSummary() {
        return summary;
    }
    public void setSummary(String summary) {
        this.summary = summary;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }


}

create_todo.htm: ( this is saved under Deployed Resources>webapp folder )

 <!DOCTYPE html>
<html>
 <head>
  <title>Form to create a new resource</title>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> 

  <style>
    tab { padding-left: 4em; }
    </style>
 </head>
<body>

<form id= "myForm" action="../com.dcr.jersey.first/rest/todos" >

  <label for="id">ID</label>
  <input name="id" />
  <br/>
  <label for="summary">Summary</label>
  <input name="summary" />
  <br/>
  Description:
  <TEXTAREA NAME="description" COLS=40 ROWS=6></TEXTAREA>
  <br/> 
  <button type="button" value="Submit">Submit</button>  <tab> <button type="button" value="Delete">Delete</button>
  <script type="text/javascript">
        $("button.Submit").click(function(){
            $("#myForm").attr("method", "POST");
            $("#myForm").attr("action", "../com.dcr.jersey.first/rest/todos");
        });

        $("button.Delete").click(function(){
            $("#myForm").attr("method", "DELETE");
        });
  </script>

</form>

</body>
</html> 

TodosResource.java

package com.dcr.jersey.jaxb.resources;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.UriInfo;

import com.dcr.jersey.jaxb.dao.TodoDao;
import com.dcr.jersey.jaxb.model.Todo;
//Will map the resource to the URL todos
@Path("/todos")
public class TodosResource {

    // Allows to insert contextual objects into the class,
      // e.g. ServletContext, Request, Response, UriInfo
      @Context
      UriInfo uriInfo;
      @Context
      Request request;
      @Context
      Todo todo;
    // Return the list of todos to the user in the browser
      @GET
      @Produces(MediaType.TEXT_XML)
      public List<Todo> getTodosBrowser() {
        List<Todo> todos = new ArrayList<Todo>();
        todos.addAll(TodoDao.instance.getModel().values());
        return todos;
      }
    // Return the list of todos for applications
      @GET
      @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
      public List<Todo> getTodos() {
        List<Todo> todos = new ArrayList<Todo>();
        todos.addAll(TodoDao.instance.getModel().values());
        return todos;
      }
    // retuns the number of todos
      // Use http://localhost:8080/de.vogella.jersey.todo/rest/todos/count
      // to get the total number of records
      @GET
      @Path("count")
      @Produces(MediaType.TEXT_PLAIN)
      public String getCount() {
        int count = TodoDao.instance.getModel().size();
        return String.valueOf(count);
      }

      @POST
      @Produces(MediaType.TEXT_HTML)
      @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
      public void newTodo(@FormParam("id") String id,
          @FormParam("summary") String summary,
          @FormParam("description") String description,
          @Context HttpServletResponse servletResponse) throws IOException {
        Todo todo = new Todo(id, summary);
        if (description != null) {
          todo.setDescription(description);
        }
        TodoDao.instance.getModel().put(id, todo);
        servletResponse.sendRedirect("../Created_PopUp.html");
      }  

      @POST
      @Produces(MediaType.TEXT_HTML)
      @Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})

      public void newTodoXMLJSON(Todo todo) throws IOException {
        this.todo=todo;
        TodoDao.instance.getModel().put(todo.getId(), todo);
      }  

      @DELETE
      @Produces(MediaType.TEXT_HTML)
      @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
      public void delTodo(@FormParam("id") String id,
          @Context HttpServletResponse servletResponse) throws IOException {
          Todo c = TodoDao.instance.getModel().remove(id);
            if(c==null)
              throw new RuntimeException("Delete: Todo with " + id +  " not found");
            else servletResponse.sendRedirect("../create_todo.html");
      }  

      @Path("{todo}")
      public TodoResource getTodo(@PathParam("todo") String id) {
            return new TodoResource(uriInfo, request, id);
      }
}

TodoDao.java

package com.dcr.jersey.jaxb.dao;

import java.util.HashMap;
import java.util.Map;

import com.dcr.jersey.jaxb.model.Todo;


public enum TodoDao {
    instance;
    private Map<String,Todo> contentProvider = new HashMap<String, Todo>();
    private TodoDao(){
        Todo todo = new Todo("1","Summary 1 - REST");
        todo.setDescription("Rest todo Description 1");
        contentProvider.put("1",todo);
        todo = new Todo("2","Summary 2 - REST");
        todo.setDescription("Rest todo Description 2 ");
        contentProvider.put("2", todo);
    }
    public Map<String,Todo> getModel(){
        return contentProvider;
    }
}

TodoResource.java

package com.dcr.jersey.jaxb.resources;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
//import javax.ws.rs.POST;
import javax.ws.rs.DELETE;
//import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.Consumes;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import javax.xml.bind.JAXBElement;

import com.dcr.jersey.jaxb.model.Todo;
import com.dcr.jersey.jaxb.dao.TodoDao;



public class TodoResource {
    @Context
    UriInfo uriInfo;
    @Context
    Request request;
    String id;

    public TodoResource(UriInfo uriInfo, Request request, String id) {
        this.uriInfo = uriInfo;
        this.request = request;
        this.id = id;
      }

    //Application Integration     
      @GET
      @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
      public Todo getTodo() {
        Todo todo = TodoDao.instance.getModel().get(id);
        if(todo==null)
          throw new RuntimeException("Get: Todo with " + id +  " not found");
        return todo;
      }

    // for the browser
      @GET
      @Produces(MediaType.TEXT_XML)
      public Todo getTodoHTML() {
        Todo todo = TodoDao.instance.getModel().get(id);
        if(todo==null)
          throw new RuntimeException("Get: Todo with " + id +  " not found");
        return todo;
      }
      @PUT
      @Consumes(MediaType.APPLICATION_XML)
      public Response putTodo(JAXBElement<Todo> todo) {
        Todo c = todo.getValue();
        return putAndGetResponse(c);
      }

      @DELETE
      public void deleteTodo() {
        Todo c = TodoDao.instance.getModel().remove(id);
        if(c==null)
          throw new RuntimeException("Delete: Todo with " + id +  " not found");
      }

      private Response putAndGetResponse(Todo todo) {
            Response res;
            if(TodoDao.instance.getModel().containsKey(todo.getId())) {
              res = Response.noContent().build();
            } else {
              res = Response.created(uriInfo.getAbsolutePath()).build();
            }
            TodoDao.instance.getModel().put(todo.getId(), todo);
            return res;
          }

}

Solution

  • Issue 1:

    You're getting Server errors, because you are throwing a RuntimException, when the looked up Todo is null. It will always be null, because you are looking it up with the id 34, which doesn't exist. You can see that all the request where you use the id in the URL are the ones failing.

    You might want to throw something more appropriate, that will get mapped to a response, like NotFoundException, which will get mapped to a 404 response

    Issue 2:

    Response response = target.path("rest").path("todos").path(todo.getId())
                              .request()
                              .accept(MediaType.APPLICATION_FORM_URLENCODED)
                              .post(Form.class,form)
    

    Let's break down what's wrong.

    1. .path(todo.getId()). By the looks of it, you are trying to post to newTodo. That method doesn't have a template for and id. Get rid of that completely.
    2. .accept(MediaType.APPLICATION_FORM_URLENCODED). The request will get redirected to an HTML page, so the response will not be application/x-www-form-urlencoded. So you can completely get rid of that. You don't need to explicitly set the header in this case.
    3. .post(Form.class,form). Take a look at the different post methods

      • Response post(Entity<?> entity)
      • <T> T post(Entity<?> entity, Class<T> responseType)
      • <T> T post(Entity<?> entity, GenericType<T> responseType)

      You want to receive back a Response, so you will use the first one. It requires only an Entity. If you look at some of the API methods, you will see a static form(Form) method.

      Create an "application/x-www-form-urlencoded" form entity.

      This is what you want to use Entity.form(form)

    So your complete request can look like

    Form form = new Form();
    form.param("id", "45");
    form.param("summary", "Summary for id 45");
    Response response = client.target(url).request().post(Entity.form(form));
    String html = response.readEntity(String.class);
    System.out.println(html);