user3769040
user3769040

Reputation: 225

RESTEasy: what causes code to execute?

I'm trying to solidify my understanding of Rest.

1) How does this function get called when there's no @Path, specifically, what triggers getCustomers to get called? "public StreamingOutput getCustomers(final @QueryParam("start") int start, final @QueryParam("size") @DefaultValue("2") int size)"

Source:

package com.restfully.shop.services;

import com.restfully.shop.domain.Customer;

import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.StreamingOutput;
import javax.ws.rs.core.UriInfo;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

@Path("/customers")
public class CustomerResource
{
   private Map<Integer, Customer> customerDB = Collections.synchronizedMap(new LinkedHashMap<Integer, Customer>());

   public CustomerResource()
   {
      Customer customer;
      int id = 1;

      customer = new Customer();
      customer.setId(id);
      customer.setFirstName("Bill");
      customer.setLastName("Burke");
      customerDB.put(id++, customer);

      customer = new Customer();
      customer.setId(id);
      customer.setFirstName("Joe");
      customer.setLastName("Burke");
      customerDB.put(id++, customer);
   }

   @GET
   @Produces("application/xml")
   public StreamingOutput getCustomers(final @QueryParam("start") int start,
                                       final @QueryParam("size") @DefaultValue("2") int size)
   {
      return new StreamingOutput()
      {
         public void write(OutputStream outputStream) throws IOException, WebApplicationException
         {
            PrintStream writer = new PrintStream(outputStream);
            writer.println("<customers>");
            synchronized (customerDB)
            {
               int i = 0;
               for (Customer customer : customerDB.values())
               {
                  if (i >= start && i < start + size) outputCustomer("   ", writer, customer);
                  i++;
               }
            }
            writer.println("</customers>");
         }
      };
   }

   @GET
   @Produces("application/xml")
   @Path("uriinfo")
   public StreamingOutput getCustomers(@Context UriInfo info)
   {
      int start = 0;
      int size = 2;
      if (info.getQueryParameters().containsKey("start"))
      {
         start = Integer.valueOf(info.getQueryParameters().getFirst("start"));
      }
      if (info.getQueryParameters().containsKey("size"))
      {
         size = Integer.valueOf(info.getQueryParameters().getFirst("size"));
      }
      return getCustomers(start, size);
   }

   protected void outputCustomer(String indent, PrintStream writer, Customer cust) throws IOException
   {
      writer.println(indent + "<customer id=\"" + cust.getId() + "\">");
      writer.println(indent + "   <first-name>" + cust.getFirstName() + "</first-name>");
      writer.println(indent + "   <last-name>" + cust.getLastName() + "</last-name>");
      writer.println(indent + "</customer>");
   }
}

2) As for the second getCustomers function, Am I correct that it is the the existence of the path* @Path("uriinfo") that matches the URL that triggers the call? Note #1 has no @path at all. I know there's the precedence rules, but what happens if I had an almost identical method that has the same path, then will BOTH methods get called?

Let's say I also have this- note the 2 in getCustomers2:

   @GET
   @Produces("application/xml")
   @Path("uriinfo")
   public StreamingOutput getCustomers2(@Context UriInfo info)
   {
      int start = 0;
      int size = 2;
      if (info.getQueryParameters().containsKey("start"))
      {
         start = Integer.valueOf(info.getQueryParameters().getFirst("start"));
      }
      if (info.getQueryParameters().containsKey("size"))
      {
         size = Integer.valueOf(info.getQueryParameters().getFirst("size"));
      }
      return getCustomers(start, size);
   }

I got a compilation error.

3) is it true that a) the @Path must be unique b) one unique path per method c) if @Path for the method is not specified and there's only one method, then it's referencing the "class" @Path and expects to have no more than one method.

Sorry, I made an error previously, what if I had these two methods in the class:

@GET
@Produces("application/xml")
public StreamingOutput getCustomers3(final @QueryParam("start") int start,
                                   final @QueryParam("size") @DefaultValue("2") int   size)
{
    return new StreamingOutput()
    {
     public void write(OutputStream outputStream) throws IOException, WebApplicationException
     {
         PrintStream writer = new PrintStream(outputStream);
         writer.println("<customers>");
         synchronized (customerDB)
         {
            int i = 0;
            for (Customer customer : customerDB.values())
            {
               if (i >= start && i < start + size) outputCustomer("   ", writer, customer); 
               i++;
            }
         }
         writer.println("</customers>");
      }
    };
}


   @GET
   @Produces("application/xml")
   public StreamingOutput getCustomers4(final @QueryParam("start") int start,
                                   final @QueryParam("size") @DefaultValue("2") int   size)
   {
      return new StreamingOutput()
      {
        public void write(OutputStream outputStream) throws IOException,  WebApplicationException
      {
         PrintStream writer = new PrintStream(outputStream);
         writer.println("<customers>");
         synchronized (customerDB)
         {
            int i = 0;
            for (Customer customer : customerDB.values())
            {
               if (i >= start && i < start + size) outputCustomer("   ", writer, customer) ;
               i++;
            }
         }
         writer.println("</customers>");
      }
   };
} 

Upvotes: 1

Views: 320

Answers (1)

gregwhitaker
gregwhitaker

Reputation: 13410

Question 1

The getCustomers method will be called when an HTTP GET request is sent for /customers and the client is requesting application/xml as the desired content type of the request.

If a JAX-RS method is not annotated with an @Path annotation it inherits the path specified by the class level annotation.

Question 2

The second getCustomers method will be called when an HTTP GET request is sent for /customers/uriinfo, as the paths are additive, and the client is requesting application/xml as the desired content type of the request.

Question 3

No, it is not true that the @Path value must be unique. What must be unique is the combination of HTTP method (@GET, @POST, @DELETE, etc), @Path value, and the content type defined by @Produces and @Consumes for a method.

Upvotes: 1

Related Questions